/** * Indicates whether this ThrowableSet includes some exception that might be caught by a handler * argument of the type <code>catcher</code>. * * @param catcher type of the handler parameter to be tested. * @return <code>true</code> if this set contains an exception type that might be caught by <code> * catcher</code>, false if it does not. */ public boolean catchableAs(RefType catcher) { if (INSTRUMENTING) { Manager.v().catchableAsQueries++; } FastHierarchy h = Scene.v().getOrMakeFastHierarchy(); if (exceptionsExcluded.size() > 0) { if (INSTRUMENTING) { Manager.v().catchableAsFromSearch++; } for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) { AnySubType exclusion = (AnySubType) i.next(); if (h.canStoreType(catcher, exclusion.getBase())) { return false; } } } if (exceptionsIncluded.contains(catcher)) { if (INSTRUMENTING) { if (exceptionsExcluded.size() == 0) { Manager.v().catchableAsFromMap++; } else { Manager.v().catchableAsFromSearch++; } } return true; } else { if (INSTRUMENTING) { if (exceptionsExcluded.size() == 0) { Manager.v().catchableAsFromSearch++; } } for (Iterator i = exceptionsIncluded.iterator(); i.hasNext(); ) { RefLikeType thrownType = (RefLikeType) i.next(); if (thrownType instanceof RefType) { if (thrownType == catcher) { // assertion failure. throw new IllegalStateException( "ThrowableSet.catchableAs(RefType): exceptions.contains() failed to match contained RefType " + catcher); } else if (h.canStoreType(thrownType, catcher)) { return true; } } else { RefType thrownBase = ((AnySubType) thrownType).getBase(); // At runtime, thrownType might be instantiated by any // of thrownBase's subtypes, so: if (h.canStoreType(thrownBase, catcher) || h.canStoreType(catcher, thrownBase)) { return true; } } } return false; } }
/** * Returns a <code>ThrowableSet</code> which contains all the exceptions in <code>s</code> in * addition to those in this <code>ThrowableSet</code>. * * @param s set of exceptions to add to this set. * @return the union of this set with <code>s</code> * @throws ThrowableSet.AlreadyHasExclusionsException if this <code>ThrowableSet</code> or <code>s * </code> is the result of a {@link #whichCatchableAs(RefType)} operation, so that it is not * possible to represent the addition of <code>s</code> to this <code>ThrowableSet</code>. */ public ThrowableSet add(ThrowableSet s) throws ThrowableSet.AlreadyHasExclusionsException { if (INSTRUMENTING) { Manager.v().addsOfSet++; } if (exceptionsExcluded.size() > 0 || s.exceptionsExcluded.size() > 0) { throw new AlreadyHasExclusionsException( "ThrowableSet.Add(ThrowableSet): attempt to add to [" + this.toString() + "] after removals recorded."); } ThrowableSet result = getMemoizedAdds(s); if (result == null) { if (INSTRUMENTING) { Manager.v().addsInclusionFromSearch++; Manager.v().addsExclusionWithoutSearch++; } result = this.add(s.exceptionsIncluded); memoizedAdds.put(s, result); } else if (INSTRUMENTING) { Manager.v().addsInclusionFromMemo++; Manager.v().addsExclusionWithoutSearch++; } return result; }
/** * Partitions the exceptions in this <code>ThrowableSet</code> into those which would be caught by * a handler with the passed <code>catch</code> parameter type and those which would not. * * @param catcher type of the handler parameter to be tested. * @return a pair of <code>ThrowableSet</code>s, one containing the types in this <code> * ThrowableSet</code> which would be be caught as <code>catcher</code> and the other * containing the types in this <code>ThrowableSet</code> which would not be caught as <code> * catcher</code>. */ public Pair whichCatchableAs(RefType catcher) { if (INSTRUMENTING) { Manager.v().removesOfAnySubType++; } FastHierarchy h = Scene.v().getOrMakeFastHierarchy(); Set caughtIncluded = null; Set caughtExcluded = null; Set uncaughtIncluded = null; Set uncaughtExcluded = null; if (INSTRUMENTING) { Manager.v().removesFromSearch++; } for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) { AnySubType exclusion = (AnySubType) i.next(); RefType exclusionBase = exclusion.getBase(); if (h.canStoreType(catcher, exclusionBase)) { // Because the add() operations ban additions to sets // with exclusions, we can be sure no types in this are // caught by catcher. return new Pair(ThrowableSet.Manager.v().EMPTY, this); } else if (h.canStoreType(exclusionBase, catcher)) { // exclusion wouldn't be in exceptionsExcluded if one // of its supertypes were not in exceptionsIncluded, // so we know the next loop will add either that supertype // or catcher to caughtIncluded. Thus: caughtExcluded = addExceptionToSet(exclusion, caughtExcluded); } else { uncaughtExcluded = addExceptionToSet(exclusion, uncaughtExcluded); } } for (Iterator i = exceptionsIncluded.iterator(); i.hasNext(); ) { RefLikeType inclusion = (RefLikeType) i.next(); if (inclusion instanceof RefType) { if (h.canStoreType(inclusion, catcher)) { caughtIncluded = addExceptionToSet(inclusion, caughtIncluded); } else { uncaughtIncluded = addExceptionToSet(inclusion, uncaughtIncluded); } } else { RefType base = ((AnySubType) inclusion).getBase(); if (h.canStoreType(base, catcher)) { // All subtypes of base will be caught. Any exclusions // will already have been copied to caughtExcluded by // the preceding loop. caughtIncluded = addExceptionToSet(inclusion, caughtIncluded); } else if (h.canStoreType(catcher, base)) { // Some subtypes of base will be caught, and // we know that not all of those catchable subtypes // are among exceptionsExcluded, since in that case we // would already have returned from within the // preceding loop. So, remove AnySubType(catcher) // from the uncaught types. uncaughtIncluded = addExceptionToSet(inclusion, uncaughtIncluded); uncaughtExcluded = addExceptionToSet(AnySubType.v(catcher), uncaughtExcluded); caughtIncluded = addExceptionToSet(AnySubType.v(catcher), caughtIncluded); // Any already excluded subtypes of inclusion // which are subtypes of catcher will have been // added to caughtExcluded by the previous loop. } else { uncaughtIncluded = addExceptionToSet(inclusion, uncaughtIncluded); } } } ThrowableSet caughtSet = Manager.v().registerSetIfNew(caughtIncluded, caughtExcluded); ThrowableSet uncaughtSet = Manager.v().registerSetIfNew(uncaughtIncluded, uncaughtExcluded); return new Pair(caughtSet, uncaughtSet); }
/** * Returns a <code>ThrowableSet</code> which contains all the exceptions in <code>addedExceptions * </code> in addition to those in this <code>ThrowableSet</code>. * * @param addedExceptions a set of {@link RefLikeType} and {@link AnySubType} objects to be added * to the types included in this <code>ThrowableSet</code>. * @return a set containing all the <code>addedExceptions</code> as well as the exceptions in this * set. */ private ThrowableSet add(Set addedExceptions) { Set resultSet = new HashSet(this.exceptionsIncluded); int changes = 0; FastHierarchy hierarchy = Scene.v().getOrMakeFastHierarchy(); // This algorithm is O(n m), where n and m are the sizes of the // two sets, so hope that the sets are small. for (Iterator i = addedExceptions.iterator(); i.hasNext(); ) { RefLikeType newType = (RefLikeType) i.next(); if (!resultSet.contains(newType)) { boolean addNewType = true; if (newType instanceof RefType) { for (Iterator j = resultSet.iterator(); j.hasNext(); ) { RefLikeType incumbentType = (RefLikeType) j.next(); if (incumbentType instanceof RefType) { if (newType == incumbentType) { // assertion failure. throw new IllegalStateException( "ThrowableSet.add(Set): resultSet.contains() failed to screen duplicate RefType " + newType); } } else if (incumbentType instanceof AnySubType) { RefType incumbentBase = ((AnySubType) incumbentType).getBase(); if (hierarchy.canStoreType(newType, incumbentBase)) { // No need to add this class. addNewType = false; } } else { // assertion failure. throw new IllegalStateException( "ThrowableSet.add(Set): incumbent Set element " + incumbentType + " is neither a RefType nor an AnySubType."); } } } else if (newType instanceof AnySubType) { RefType newBase = ((AnySubType) newType).getBase(); for (Iterator j = resultSet.iterator(); j.hasNext(); ) { RefLikeType incumbentType = (RefLikeType) j.next(); if (incumbentType instanceof RefType) { RefType incumbentBase = (RefType) incumbentType; if (hierarchy.canStoreType(incumbentBase, newBase)) { j.remove(); changes++; } } else if (incumbentType instanceof AnySubType) { RefType incumbentBase = ((AnySubType) incumbentType).getBase(); if (newBase == incumbentBase) { // assertion failure. throw new IllegalStateException( "ThrowableSet.add(Set): resultSet.contains() failed to screen duplicate AnySubType " + newBase); } else if (hierarchy.canStoreType(incumbentBase, newBase)) { j.remove(); changes++; } else if (hierarchy.canStoreType(newBase, incumbentBase)) { // No need to add this class. addNewType = false; } } else { // assertion failure. throw new IllegalStateException( "ThrowableSet.add(Set): old Set element " + incumbentType + " is neither a RefType nor an AnySubType."); } } } else { // assertion failure. throw new IllegalArgumentException( "ThrowableSet.add(Set): new Set element " + newType + " is neither a RefType nor an AnySubType."); } if (addNewType) { changes++; resultSet.add(newType); } } } ThrowableSet result = null; if (changes > 0) { result = Manager.v().registerSetIfNew(resultSet, this.exceptionsExcluded); } else { result = this; } return result; }
/** * Returns a <code>ThrowableSet</code> which contains <code>e</code> and all of its subclasses as * well as the exceptions in this set. * * <p><code>e</code> should be an instance of {@link AnySubType} if you know that the compile-time * type of the exception you are representing is <code>e</code>, but the exception may be * instantiated at run-time by a subclass of <code>e</code>. * * <p>For example, if you were recording the type of the exception thrown by * * <pre> * catch (IOException e) { * throw e; * } * </pre> * * you would call * * <pre> * <code>add(AnySubtype.v(Scene.v().getRefType("java.lang.Exception.IOException")))</code> * </pre> * * since the handler might rethrow any subclass of <code>IOException</code>. * * @param e represents a subtree of the exception class hierarchy to add to this set. * @return a set containing <code>e</code> and all its subclasses, as well as the exceptions * represented by this set. * @throws ThrowableSet.AlreadyHasExclusionsException if this <code>ThrowableSet</code> is the * result of a {@link #whichCatchableAs(RefType)} operation and, thus, unable to represent the * addition of <code>e</code>. */ public ThrowableSet add(AnySubType e) throws ThrowableSet.AlreadyHasExclusionsException { if (INSTRUMENTING) { Manager.v().addsOfAnySubType++; } ThrowableSet result = getMemoizedAdds(e); if (result != null) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMemo++; Manager.v().addsExclusionWithoutSearch++; } return result; } else { FastHierarchy hierarchy = Scene.v().getOrMakeFastHierarchy(); RefType newBase = e.getBase(); if (INSTRUMENTING) { if (exceptionsExcluded.size() != 0) { Manager.v().addsExclusionWithSearch++; } else { Manager.v().addsExclusionWithoutSearch++; } } for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) { RefType exclusionBase = ((AnySubType) i.next()).getBase(); if (hierarchy.canStoreType(newBase, exclusionBase) || hierarchy.canStoreType(exclusionBase, newBase)) { if (INSTRUMENTING) { // To ensure that the subcategories total properly: Manager.v().addsInclusionInterrupted++; } throw new AlreadyHasExclusionsException( "ThrowableSet.add(" + e.toString() + ") to the set [ " + this.toString() + "] where " + exclusionBase.toString() + " is excluded."); } } if (this.exceptionsIncluded.contains(e)) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMap++; } return this; } else { if (INSTRUMENTING) { Manager.v().addsInclusionFromSearch++; } int changes = 0; boolean addNewException = true; Set resultSet = new HashSet(); for (Iterator i = this.exceptionsIncluded.iterator(); i.hasNext(); ) { RefLikeType incumbent = (RefLikeType) i.next(); if (incumbent instanceof RefType) { if (hierarchy.canStoreType(incumbent, newBase)) { // Omit incumbent from result. changes++; } else { resultSet.add(incumbent); } } else if (incumbent instanceof AnySubType) { RefType incumbentBase = ((AnySubType) incumbent).getBase(); // We have to use the base types in these hierarchy calls // because we want to know if _all_ possible // types represented by e can be represented by // the incumbent, or vice versa. if (hierarchy.canStoreType(newBase, incumbentBase)) { addNewException = false; resultSet.add(incumbent); } else if (hierarchy.canStoreType(incumbentBase, newBase)) { // Omit incumbent from result; changes++; } else { resultSet.add(incumbent); } } else { // assertion failure. throw new IllegalStateException( "ThrowableSet.add(AnySubType): Set element " + incumbent.toString() + " is neither a RefType nor an AnySubType."); } } if (addNewException) { resultSet.add(e); changes++; } if (changes > 0) { result = Manager.v().registerSetIfNew(resultSet, this.exceptionsExcluded); } else { result = this; } memoizedAdds.put(e, result); return result; } } }
/** * Returns a <code>ThrowableSet</code> which contains <code>e</code> in addition to the exceptions * in this <code>ThrowableSet</code>. * * <p>Add <code>e</code> as a {@link RefType} when you know that the run-time class of the * exception you are representing is necessarily <code>e</code> and cannot be a subclass of <code> * e</code>. * * <p>For example, if you were recording the type of the exception thrown by * * <pre> * throw new IOException("Permission denied"); * </pre> * * you would call * * <pre> * <code>add(Scene.v().getRefType("java.lang.Exception.IOException"))</code> * </pre> * * since the class of the exception is necessarily <code>IOException</code>. * * @param e the exception class * @return a set containing <code>e</code> as well as the exceptions in this set. * @throws {@link ThrowableSet.IllegalStateException} if this <code>ThrowableSet</code> is the * result of a {@link #whichCatchableAs(RefType)} operation and, thus, unable to represent the * addition of <code>e</code>. */ public ThrowableSet add(RefType e) throws ThrowableSet.AlreadyHasExclusionsException { if (INSTRUMENTING) { Manager.v().addsOfRefType++; } if (this.exceptionsIncluded.contains(e)) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMap++; Manager.v().addsExclusionWithoutSearch++; } return this; } else { ThrowableSet result = getMemoizedAdds(e); if (result != null) { if (INSTRUMENTING) { Manager.v().addsInclusionFromMemo++; Manager.v().addsExclusionWithoutSearch++; } return result; } else { if (INSTRUMENTING) { Manager.v().addsInclusionFromSearch++; if (exceptionsExcluded.size() != 0) { Manager.v().addsExclusionWithSearch++; } else { Manager.v().addsExclusionWithoutSearch++; } } FastHierarchy hierarchy = Scene.v().getOrMakeFastHierarchy(); for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) { RefType exclusionBase = ((AnySubType) i.next()).getBase(); if (hierarchy.canStoreType(e, exclusionBase)) { throw new AlreadyHasExclusionsException( "ThrowableSet.add(RefType): adding" + e.toString() + " to the set [ " + this.toString() + "] where " + exclusionBase.toString() + " is excluded."); } } for (Iterator i = exceptionsIncluded.iterator(); i.hasNext(); ) { RefLikeType incumbent = (RefLikeType) i.next(); if (incumbent instanceof AnySubType) { // Need to use incumbent.getBase() because // hierarchy.canStoreType() assumes that parent // is not an AnySubType. RefType incumbentBase = ((AnySubType) incumbent).getBase(); if (hierarchy.canStoreType(e, incumbentBase)) { memoizedAdds.put(e, this); return this; } } else if (!(incumbent instanceof RefType)) { // assertion failure. throw new IllegalStateException( "ThrowableSet.add(RefType): Set element " + incumbent.toString() + " is neither a RefType nor an AnySubType."); } } Set resultSet = new HashSet(this.exceptionsIncluded); resultSet.add(e); result = Manager.v().registerSetIfNew(resultSet, this.exceptionsExcluded); memoizedAdds.put(e, result); return result; } } }
/** * A package-private method to provide unit tests with access to the collection of * ThrowableSets. */ Map getSizeToSets() { return Manager.v().sizeToSets; }