ExceptionSet.java :  » Code-Analyzer » findbugs-1.3.9 » edu » umd » cs » findbugs » ba » type » Java Open Source

Java Open Source » Code Analyzer » findbugs 1.3.9 
findbugs 1.3.9 » edu » umd » cs » findbugs » ba » type » ExceptionSet.java
/*
 * Bytecode Analysis Framework
 * Copyright (C) 2004 University of Maryland
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package edu.umd.cs.findbugs.ba.type;

import java.io.Serializable;
import java.util.BitSet;
import java.util.Iterator;
import java.util.NoSuchElementException;

import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.Type;

import edu.umd.cs.findbugs.ba.AnalysisContext;
import edu.umd.cs.findbugs.ba.Hierarchy;
import edu.umd.cs.findbugs.ba.ch.Subtypes2;

/**
 * Class for keeping track of exceptions that can be
 * thrown by an instruction.  We distinguish <em>explicit</em>
 * and <em>implicit</em> exceptions.  Explicit exceptions
 * are explicitly declared, thrown, or caught.  Implicit exceptions
 * are runtime faults (NPE, array out of bounds)
 * not explicitly handled by the user code.
 *
 * @author David Hovemeyer
 * @see TypeAnalysis
 */
public class ExceptionSet implements Serializable {
    private static final long serialVersionUID = 1;

  private ExceptionSetFactory factory;
  private BitSet exceptionSet;
  private BitSet explicitSet;
  private int size;
  private boolean universalHandler;
  private Type commonSupertype;

  /**
   * Object to iterate over the exception types in the set.
   */
  public class ThrownExceptionIterator implements Iterator<ObjectType> {
    private int last = -1, next = -1;

    ThrownExceptionIterator() {
      findNext();
    }

    public boolean hasNext() {
      if (last == next)
        findNext();
      return next < factory.getNumTypes();
    }

    public ObjectType next() {
      if (!hasNext())
        throw new NoSuchElementException();
      ObjectType result = factory.getType(next);
      last = next;
      return result;
    }

    public boolean isExplicit() {
      return explicitSet.get(last);
    }

    public void remove() {
      exceptionSet.clear(last);
      explicitSet.clear(last);
      --size;
      commonSupertype = null;
    }

    private void findNext() {
      ++next;
      while (next < factory.getNumTypes()) {
        if (exceptionSet.get(next))
          break;
        ++next;
      }
    }
  }

  /**
   * Constructor.
   * Creates an empty set.
   */
  ExceptionSet(ExceptionSetFactory factory) {
    this.factory = factory;
    this.exceptionSet = new BitSet();
    this.explicitSet = new BitSet();
    this.size = 0;
    this.universalHandler = false;
  }

  /**
   * Return an exact copy of this object.
   */
  public ExceptionSet duplicate() {
    ExceptionSet dup = factory.createExceptionSet();
    dup.exceptionSet.clear();
    dup.exceptionSet.or(this.exceptionSet);
    dup.explicitSet.clear();
    dup.explicitSet.or(this.explicitSet);
    dup.size = this.size;
    dup.universalHandler = this.universalHandler;
    dup.commonSupertype = this.commonSupertype;

    return dup;
  }

  @Override
     public int hashCode() {
    return exceptionSet.hashCode() + explicitSet.hashCode();
  }

  @Override
     public boolean equals(Object o) {
    if (o == null) return false;
    if (o.getClass() != this.getClass()) return false;

    ExceptionSet other = (ExceptionSet) o;
    return exceptionSet.equals(other.exceptionSet)
        && explicitSet.equals(other.explicitSet)
        && universalHandler == other.universalHandler;
  }

  /**
   * Get the least (lowest in the lattice) common supertype
   * of the exceptions in the set.  Returns the special TOP
   * type if the set is empty.
   */
  public Type getCommonSupertype() throws ClassNotFoundException {
    if (commonSupertype != null)
      return commonSupertype;

    if (isEmpty()) {
      // This probably means that we're looking at an
      // infeasible exception path.
      return TypeFrame.getTopType();
    }

    // Compute first common superclass
    ThrownExceptionIterator i = iterator();
    ReferenceType result = i.next();
    while (i.hasNext()) {
      if (Subtypes2.ENABLE_SUBTYPES2_FOR_COMMON_SUPERCLASS_QUERIES) {
        result = AnalysisContext.currentAnalysisContext().getSubtypes2().getFirstCommonSuperclass(result, i.next());
      } else {
        result = result.getFirstCommonSuperclass(i.next());
      }
      if (result == null) {
        // This should only happen if the class hierarchy
        // is incomplete.  We'll just be conservative.
        result = Type.THROWABLE;
        break;
      }
    }

    // Cache and return the result
    commonSupertype = result;
    return result;
  }

  /**
   * Return an iterator over thrown exceptions.
   */
  public ThrownExceptionIterator iterator() {
    return new ThrownExceptionIterator();
  }

  /**
   * Return whether or not the set is empty.
   */
  public boolean isEmpty() {
    return size == 0;
  }

  /**
   * Checks to see if the exception set is a singleton set
   * containing just the named exception
   * @param exceptionName (in dotted format)
   * @return true if it is
   */
  public boolean isSingleton(String exceptionName) {
    if (size != 1) return false;
    ObjectType e = iterator().next();
    return e.toString().equals(exceptionName);

  }
  /**
   * Add an explicit exception.
   *
   * @param type type of the exception
   */
  public void addExplicit(ObjectType type) {
    add(type, true);
  }

  /**
   * Add an implicit exception.
   *
   * @param type type of the exception
   */
  public void addImplicit(ObjectType type) {
    add(type, false);
  }

  /**
   * Add an exception.
   *
   * @param type     the exception type
   * @param explicit true if the exception is explicitly declared
   *                 or thrown, false if implicit
   */
  public void add(ObjectType type, boolean explicit) {
    int index = factory.getIndexOfType(type);
    if (!exceptionSet.get(index))
      ++size;
    exceptionSet.set(index);
    if (explicit)
      explicitSet.set(index);

    commonSupertype = null;
  }

  /**
   * Add all exceptions in the given set.
   *
   * @param other the set
   */
  public void addAll(ExceptionSet other) {
    exceptionSet.or(other.exceptionSet);
    explicitSet.or(other.explicitSet);
    size = countBits(exceptionSet);

    commonSupertype = null;
  }

  private int countBits(BitSet bitSet) {
    int count = 0;
    for (int i = 0; i < factory.getNumTypes(); ++i) {
      if (bitSet.get(i))
        ++count;
    }
    return count;
  }

  /**
   * Remove all exceptions from the set.
   */
  public void clear() {
    exceptionSet.clear();
    explicitSet.clear();
    universalHandler = false;
    commonSupertype = null;
  }

  /**
   * Return whether or not a universal exception handler
   * was reached by the set.
   */
  public void sawUniversal() {
    clear();
    universalHandler = true;
  }

  /**
   * Mark the set as having reached a universal exception handler.
   */
  public boolean sawUniversalHandler() {
    return universalHandler;
  }

  /**
   * Return whether or not the set contains any checked exceptions.
   */
  public boolean containsCheckedExceptions() throws ClassNotFoundException {
    for (ThrownExceptionIterator i = iterator(); i.hasNext();) {
      ObjectType type = i.next();
      if (!Hierarchy.isUncheckedException(type))
        return true;
    }
    return false;
  }

  /**
   * Return whether or not the set contains any explicit exceptions.
   */
  public boolean containsExplicitExceptions() {
    for (ThrownExceptionIterator i = iterator(); i.hasNext();) {
      i.next();
      if (i.isExplicit())
        return true;
    }
    return false;
  }

  @Override
  public String toString() {
    StringBuilder buf = new StringBuilder();
    buf.append('{');
    boolean first = true;
    for (ThrownExceptionIterator i = iterator(); i.hasNext();) {
      ObjectType type = i.next();
      if (first)
        first = false;
      else
        buf.append(',');
      boolean implicit = !i.isExplicit();
      if (implicit) buf.append('[');
      buf.append(type.toString());
      if (implicit) buf.append(']');
    }
    buf.append('}');
    return buf.toString();
  }
  public int size() {
    return size;
  }
}

// vim:ts=4
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.