KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > soot > toolkits > exceptions > ThrowableSet


1 /* Soot - a J*va Optimization Framework
2  * Copyright (C) 2003 John Jorgensen
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */

19
20 package soot.toolkits.exceptions;
21
22 import soot.*;
23 import soot.jimple.*;
24 import soot.util.*;
25 import java.util.*;
26
27 /**
28  * <p>A class for representing the set of exceptions that an
29  * instruction may throw.</p>
30  *
31  * <p> <code>ThrowableSet</code> does not implement the
32  * {@link java.util.Set} interface, so perhaps it is misnamed.
33  * Instead, it provides only the operations that we require for
34  * determining whether a given statement might throw an exception that
35  * would be caught by a given handler.</p>
36  *
37  * <p>There is a limitation on the combinations of operations
38  * permitted on a <code>ThrowableSet</code>. The
39  * <code>ThrowableSet</code>s returned by {@link
40  * #whichCatchableAs(RefType)} cannot be involved in subsequent
41  * <code>add()</code> or <code>whichCatchableAs()</code> operations.
42  * That is, given
43  *
44  * <blockquote>
45  * <code>p = s.whichCatchableAs(r)</code>
46  * </blockquote>
47  *
48  * for any <code>ThrowableSet</code> <code>s</code> and
49  * {@link soot.RefType RefType} <code>r</code>, and
50  *
51  * <blockquote>
52  * <code>t == p.getUncaught()</code> or
53  * <code>t == p.getCaught()</code>
54  * </blockquote>
55  *
56  * then calls to
57  * <code>t.add(r)</code>, <code>t.add(a)</code>, and <code>s.add(t)</code>,
58  * will throw an {@link ThrowableSet.AlreadyHasExclusionsException}, for any
59  * <code>RefType</code> <code>r</code>, {@link AnySubType} <code>a</code>,
60  * and <code>ThrowableSet</code> <code>t</code>.</p>
61  *
62  * <p> Actually the restrictions implemented are not quite so strict
63  * (there are some combinations of <code>whichCatchableAs()</code>
64  * followed by <code>add()</code> which will not raise an exception),
65  * but a more accurate description would require reference to the
66  * internals of the current implementation. The restrictions should
67  * not be too onerous for <code>ThrowableSet</code>'s anticipated
68  * uses: we expect <code>ThrowableSet</code>s to grow by accumulating
69  * all the exception types that a given {@link Unit} may throw, then,
70  * shrink as the types caught by different exception handlers are
71  * removed to yield the sets representing exceptions which escape
72  * those handlers.</p>
73  *
74  * <p> The <code>ThrowableSet</code> class is intended to be immutable
75  * (hence the <code>final</code> modifier on its declaration). It
76  * does not take the step of guaranteeing immutability by cloning the
77  * <code>RefLikeType</code> objects it contains, though, because we trust
78  * {@link Scene} to enforce the existence of only one
79  * <code>RefLikeType</code> instance with a given name.</p>
80  */

81
82 public final class ThrowableSet {
83
84     private static final boolean INSTRUMENTING = true;
85
86     /**
87      * Singleton class for fields and initializers common to all
88      * ThrowableSet objects (i.e., these would be static fields and
89      * initializers, in the absence of soot's {@link G} and {@link
90      * Singletons} classes).
91      */

92     public static class Manager {
93
94     /**
95      * Map from {@link Integer}s representing set size to all
96      * <code>ThrowableSet</code>s of that size.
97      */

98     private final Map sizeToSets = new HashMap();
99
100     /**
101      * <code>ThrowableSet</code> containing no exception classes.
102      */

103     public final ThrowableSet EMPTY;
104
105     /**
106      * <code>ThrowableSet</code> representing all possible
107      * Throwables.
108      */

109     final ThrowableSet ALL_THROWABLES;
110
111     /**
112      * <code>ThrowableSet</code> containing all the asynchronous
113      * and virtual machine errors, which may be thrown by any
114      * bytecode instruction at any point in the computation.
115      */

116     final ThrowableSet VM_ERRORS;
117
118     /**
119      * <code>ThrowableSet</code> containing all the exceptions
120      * that may be thrown in the course of resolving a reference
121      * to another class, including the process of loading, preparing,
122      * and verifying the referenced class.
123      */

124     final ThrowableSet RESOLVE_CLASS_ERRORS;
125
126     /**
127      * <code>ThrowableSet</code> containing all the exceptions
128      * that may be thrown in the course of resolving a reference
129      * to a field.
130      */

131     final ThrowableSet RESOLVE_FIELD_ERRORS;
132
133     /**
134      * <code>ThrowableSet</code> containing all the exceptions
135      * that may be thrown in the course of resolving a reference
136      * to a non-static method.
137      */

138     final ThrowableSet RESOLVE_METHOD_ERRORS;
139
140     /**
141      * <code>ThrowableSet</code> containing all the exceptions
142      * which may be thrown by instructions that have the potential
143      * to cause a new class to be loaded and initialized (including
144      * UnsatisfiedLinkError, which is raised at runtime rather than
145      * linking type).
146      */

147     final ThrowableSet INITIALIZATION_ERRORS;
148
149     final RefType RUNTIME_EXCEPTION;
150     final RefType ARITHMETIC_EXCEPTION;
151     final RefType ARRAY_STORE_EXCEPTION;
152     final RefType CLASS_CAST_EXCEPTION;
153     final RefType ILLEGAL_MONITOR_STATE_EXCEPTION;
154     final RefType INDEX_OUT_OF_BOUNDS_EXCEPTION;
155     final RefType ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION;
156     final RefType NEGATIVE_ARRAY_SIZE_EXCEPTION;
157     final RefType NULL_POINTER_EXCEPTION;
158     final RefType INSTANTIATION_ERROR;
159
160     // counts for instrumenting:
161
private int registeredSets = 0;
162     private int addsOfRefType = 0;
163     private int addsOfAnySubType = 0;
164     private int addsOfSet = 0;
165     private int addsInclusionFromMap = 0;
166     private int addsInclusionFromMemo = 0;
167     private int addsInclusionFromSearch = 0;
168     private int addsInclusionInterrupted = 0;
169     private int addsExclusionWithSearch = 0;
170     private int addsExclusionWithoutSearch = 0;
171     private int removesOfAnySubType = 0;
172     private int removesFromMap = 0;
173     private int removesFromMemo = 0;
174     private int removesFromSearch = 0;
175     private int registrationCalls = 0;
176     private int catchableAsQueries = 0;
177     private int catchableAsFromMap = 0;
178     private int catchableAsFromSearch = 0;
179     
180     /**
181      * Constructs a <code>ThrowableSet.Manager</code> for inclusion in
182      * Soot's global variable manager, {@link G}.
183      *
184      * @param g guarantees that the constructor may only be called
185      * from {@link Singletons}.
186      */

187     public Manager( Singletons.Global g ) {
188         // First ensure the Exception classes are represented in Soot.
189

190         // Runtime errors:
191
RUNTIME_EXCEPTION =
192         Scene.v().getRefType("java.lang.RuntimeException");
193         ARITHMETIC_EXCEPTION =
194         Scene.v().getRefType("java.lang.ArithmeticException");
195         ARRAY_STORE_EXCEPTION =
196         Scene.v().getRefType("java.lang.ArrayStoreException");
197         CLASS_CAST_EXCEPTION =
198         Scene.v().getRefType("java.lang.ClassCastException");
199             ILLEGAL_MONITOR_STATE_EXCEPTION =
200                 Scene.v().getRefType("java.lang.IllegalMonitorStateException");
201         INDEX_OUT_OF_BOUNDS_EXCEPTION =
202         Scene.v().getRefType("java.lang.IndexOutOfBoundsException");
203         ARRAY_INDEX_OUT_OF_BOUNDS_EXCEPTION =
204         Scene.v().getRefType("java.lang.ArrayIndexOutOfBoundsException");
205         NEGATIVE_ARRAY_SIZE_EXCEPTION =
206         Scene.v().getRefType("java.lang.NegativeArraySizeException");
207         NULL_POINTER_EXCEPTION =
208         Scene.v().getRefType("java.lang.NullPointerException");
209
210         INSTANTIATION_ERROR =
211         Scene.v().getRefType("java.lang.InstantiationError");
212
213         EMPTY = registerSetIfNew(null, null);
214
215         Set allThrowablesSet = new HashSet();
216         allThrowablesSet.add(AnySubType.v(Scene.v().getRefType("java.lang.Throwable")));
217         ALL_THROWABLES = registerSetIfNew(allThrowablesSet, null);
218
219         Set vmErrorSet = new HashSet();
220         vmErrorSet.add(Scene.v().getRefType("java.lang.InternalError"));
221         vmErrorSet.add(Scene.v().getRefType("java.lang.OutOfMemoryError"));
222         vmErrorSet.add(Scene.v().getRefType("java.lang.StackOverflowError"));
223         vmErrorSet.add(Scene.v().getRefType("java.lang.UnknownError"));
224
225         // The Java library's deprecated Thread.stop(Throwable) method
226
// would actually allow _any_ Throwable to be delivered
227
// asynchronously, not just java.lang.ThreadDeath.
228
vmErrorSet.add(Scene.v().getRefType("java.lang.ThreadDeath"));
229
230         VM_ERRORS = registerSetIfNew(vmErrorSet, null);
231
232         Set resolveClassErrorSet = new HashSet();
233         resolveClassErrorSet.add(Scene.v().getRefType("java.lang.ClassCircularityError"));
234         // We add AnySubType(ClassFormatError) so that we can
235
// avoid adding its subclass,
236
// UnsupportedClassVersionError, explicitly. This is a
237
// hack to allow Soot to analyze older class libraries
238
// (UnsupportedClassVersionError was added in JDK 1.2).
239
resolveClassErrorSet.add(AnySubType.v(Scene.v().getRefType("java.lang.ClassFormatError")));
240         resolveClassErrorSet.add(Scene.v().getRefType("java.lang.IllegalAccessError"));
241         resolveClassErrorSet.add(Scene.v().getRefType("java.lang.IncompatibleClassChangeError"));
242         resolveClassErrorSet.add(Scene.v().getRefType("java.lang.LinkageError"));
243         resolveClassErrorSet.add(Scene.v().getRefType("java.lang.NoClassDefFoundError"));
244         resolveClassErrorSet.add(Scene.v().getRefType("java.lang.VerifyError"));
245         RESOLVE_CLASS_ERRORS = registerSetIfNew(resolveClassErrorSet, null);
246
247         Set resolveFieldErrorSet = new HashSet(resolveClassErrorSet);
248         resolveFieldErrorSet.add(Scene.v().getRefType("java.lang.NoSuchFieldError"));
249         RESOLVE_FIELD_ERRORS = registerSetIfNew(resolveFieldErrorSet, null);
250
251         Set resolveMethodErrorSet = new HashSet(resolveClassErrorSet);
252         resolveMethodErrorSet.add(Scene.v().getRefType("java.lang.AbstractMethodError"));
253         resolveMethodErrorSet.add(Scene.v().getRefType("java.lang.NoSuchMethodError"));
254         resolveMethodErrorSet.add(Scene.v().getRefType("java.lang.UnsatisfiedLinkError"));
255         RESOLVE_METHOD_ERRORS = registerSetIfNew(resolveMethodErrorSet, null);
256
257         // The static initializers of a newly loaded class might
258
// throw any Error (if they threw an Exception---even a
259
// RuntimeException---it would be replaced by an
260
// ExceptionInInitializerError):
261
//
262
Set initializationErrorSet = new HashSet();
263         initializationErrorSet.add(AnySubType.v(Scene.v().getRefType("java.lang.Error")));
264         INITIALIZATION_ERRORS = registerSetIfNew(initializationErrorSet, null);
265     }
266
267
268     /**
269      * Returns the single instance of <code>ThrowableSet.Manager</code>.
270      *
271      * @return Soot's <code>ThrowableSet.Manager</code>.
272      */

273     public static Manager v() {
274         return G.v().soot_toolkits_exceptions_ThrowableSet_Manager();
275     }
276
277
278     /**
279      * <p>Returns a <code>ThrowableSet</code> representing the set of
280      * exceptions included in <code>include</code> minus the set
281      * of exceptions included in <code>exclude</code>. Creates a
282      * new <code>ThrowableSet</code> only if there was not already
283      * one whose contents correspond to <code>include</code> -
284      * <code>exclude</code>.</p>
285      *
286      * @param include A set of {@link RefLikeType}
287      * objects representing exception types included in the result; may
288      * be <code>null</code> if there are no included types.
289      *
290      * @param exclude A set of {@link AnySubType}
291      * objects representing exception types excluded from the result; may
292      * be <code>null</code> if there are no excluded types.
293      *
294      * @return a <code>ThrowableSet</code> representing the set of
295      * exceptions corresponding to <code>include</code> -
296      * <code>exclude</code>.
297      */

298     private ThrowableSet registerSetIfNew(Set include, Set exclude) {
299         if (INSTRUMENTING) {
300         registrationCalls++;
301         }
302         if (include == null) {
303         include = Collections.EMPTY_SET;
304         }
305         if (exclude == null) {
306         exclude = Collections.EMPTY_SET;
307         }
308         int size = include.size() + exclude.size();
309         Integer JavaDoc sizeKey = new Integer JavaDoc(size);
310
311         List sizeList = (List) sizeToSets.get(sizeKey);
312         if (sizeList == null) {
313         sizeList = new LinkedList();
314         sizeToSets.put(sizeKey, sizeList);
315         }
316         for (Iterator i = sizeList.iterator(); i.hasNext() ;) {
317         ThrowableSet set = (ThrowableSet) i.next();
318         if (set.exceptionsIncluded.equals(include)
319             && set.exceptionsExcluded.equals(exclude)) {
320             return set;
321         }
322         }
323         if (INSTRUMENTING) {
324         registeredSets++;
325         }
326         ThrowableSet result = new ThrowableSet(include, exclude);
327         sizeList.add(result);
328         return result;
329     }
330
331
332     /**
333      * Report the counts collected by instrumentation (for now, at
334      * least, there is no need to provide access to the individual
335      * values as numbers).
336      *
337      * @return a string listing the counts.
338      */

339     public String JavaDoc reportInstrumentation() {
340         int setCount = 0;
341         for (Iterator it = sizeToSets.values().iterator(); it.hasNext(); ) {
342         List sizeList = (List) it.next();
343         setCount += sizeList.size();
344         }
345         if (setCount != registeredSets) {
346         throw new IllegalStateException JavaDoc("ThrowableSet.reportInstrumentation() assertion failure: registeredSets != list count");
347         }
348         StringBuffer JavaDoc buf = new StringBuffer JavaDoc("registeredSets: ")
349         .append(setCount)
350         .append("\naddsOfRefType: ")
351         .append(addsOfRefType)
352         .append("\naddsOfAnySubType: ")
353         .append(addsOfAnySubType)
354         .append("\naddsOfSet: ")
355         .append(addsOfSet)
356         .append("\naddsInclusionFromMap: ")
357         .append(addsInclusionFromMap)
358         .append("\naddsInclusionFromMemo: ")
359         .append(addsInclusionFromMemo)
360         .append("\naddsInclusionFromSearch: ")
361         .append(addsInclusionFromSearch)
362         .append("\naddsInclusionInterrupted: ")
363         .append(addsInclusionInterrupted)
364         .append("\naddsExclusionWithoutSearch: ")
365         .append(addsExclusionWithoutSearch)
366         .append("\naddsExclusionWithSearch: ")
367         .append(addsExclusionWithSearch)
368         .append("\nremovesOfAnySubType: ")
369         .append(removesOfAnySubType)
370         .append("\nremovesFromMap: ")
371         .append(removesFromMap)
372         .append("\nremovesFromMemo: ")
373         .append(removesFromMemo)
374         .append("\nremovesFromSearch: ")
375         .append(removesFromSearch)
376         .append("\nregistrationCalls: ")
377         .append(registrationCalls)
378         .append("\ncatchableAsQueries: ")
379         .append(catchableAsQueries)
380         .append("\ncatchableAsFromMap: ")
381         .append(catchableAsFromMap)
382         .append("\ncatchableAsFromSearch: ")
383         .append(catchableAsFromSearch)
384         .append('\n');
385         return buf.toString();
386     }
387
388     /**
389      * A package-private method to provide unit tests with access
390      * to the collection of ThrowableSets.
391      */

392     Map getSizeToSets() {
393         return Manager.v().sizeToSets;
394     }
395     }
396
397
398     public static class AlreadyHasExclusionsException extends IllegalStateException JavaDoc {
399     public AlreadyHasExclusionsException(String JavaDoc s) {
400         super(s);
401     }
402     }
403
404
405     /**
406      * Set of exception types included within the set.
407      */

408     private final Set exceptionsIncluded;
409
410     /**
411      * Set of exception types which, though members of
412      * exceptionsIncluded, are to be excluded from the types
413      * represented by this <code>ThrowableSet</code>. To simplify
414      * the implementation, once a <code>ThrowableSet</code> has
415      * any excluded types, the various <code>add()</code> methods of
416      * this class must bar additions of subtypes of those
417      * excluded types.
418      */

419     private final Set exceptionsExcluded;
420
421     /**
422      * A map from
423      * ({@link RefLikeType} \\union <code>ThrowableSet</code>)
424      * to <code>ThrowableSet</code>. If the mapping (k,v) is in
425      * <code>memoizedAdds</code> and k is a
426      * <code>ThrowableSet</code>, then v is the set that
427      * results from adding all elements in k to <code>this</code>. If
428      * (k,v) is in <code>memoizedAdds</code> and k is a
429      * {@link RefLikeType}, then v is the set that results from adding
430      * k to <code>this</code>.
431      */

432     private Map memoizedAdds;
433
434     private ThrowableSet getMemoizedAdds(Object JavaDoc key) {
435     if (memoizedAdds == null) {
436         memoizedAdds = new HashMap();
437     }
438     return (ThrowableSet) memoizedAdds.get(key);
439     }
440
441
442     /**
443      * Constructs a <code>ThrowableSet</code> which contains the
444      * exception types represented in <code>include</code>, except for
445      * those which are also in <code>exclude</code>. The constructor
446      * is private to ensure that the only way to get a new
447      * <code>ThrowableSet</code> is by adding elements to or removing
448      * them from an existing set.
449      *
450      * @param include The set of {@link RefType} and {@link AnySubType}
451      * objects representing the types to be included in the set.
452      * @param exclude The set of {@link AnySubType}
453      * objects representing the types to be excluded
454      * from the set.
455      */

456     private ThrowableSet(Set include, Set exclude) {
457     exceptionsIncluded = Collections.unmodifiableSet(include);
458     exceptionsExcluded = Collections.unmodifiableSet(exclude);
459     // We don't need to clone include and exclude to guarantee
460
// immutability since ThrowableSet(Set,Set) is private to this
461
// class, where it is only called (via
462
// Manager.v().registerSetIfNew()) with arguments which the
463
// callers do not subsequently modify.
464
}
465
466
467     /**
468      * Returns a <code>ThrowableSet</code> which contains
469      * <code>e</code> in addition to the exceptions in
470      * this <code>ThrowableSet</code>.
471      *
472      * <p>Add <code>e</code> as a {@link RefType} when
473      * you know that the run-time class of the exception you are representing is
474      * necessarily <code>e</code> and cannot be a subclass of
475      * <code>e</code>.
476      *
477      * <p>For example, if you were
478      * recording the type of the exception thrown by
479      *
480      * <pre>
481      * throw new IOException("Permission denied");
482      * </pre>
483      *
484      * you would call
485      *
486      * <pre>
487      * <code>add(Scene.v().getRefType("java.lang.Exception.IOException"))</code>
488      * </pre>
489      *
490      * since the class of the exception is necessarily
491      * <code>IOException</code>.
492      *
493      * @param e the exception class
494      *
495      * @return a set containing <code>e</code> as well as the
496      * exceptions in this set.
497      *
498      * @throws {@link ThrowableSet.IllegalStateException} if this
499      * <code>ThrowableSet</code> is the result of a {@link
500      * #whichCatchableAs(RefType)} operation and, thus, unable to
501      * represent the addition of <code>e</code>.
502      */

503     public ThrowableSet add(RefType e)
504       throws ThrowableSet.AlreadyHasExclusionsException {
505     if (INSTRUMENTING) {
506         Manager.v().addsOfRefType++;
507     }
508     if (this.exceptionsIncluded.contains(e)) {
509         if (INSTRUMENTING) {
510         Manager.v().addsInclusionFromMap++;
511         Manager.v().addsExclusionWithoutSearch++;
512         }
513         return this;
514     } else {
515         ThrowableSet result = getMemoizedAdds(e);
516         if (result != null) {
517         if (INSTRUMENTING) {
518             Manager.v().addsInclusionFromMemo++;
519             Manager.v().addsExclusionWithoutSearch++;
520         }
521         return result;
522         } else {
523         if (INSTRUMENTING) {
524             Manager.v().addsInclusionFromSearch++;
525             if (exceptionsExcluded.size() != 0) {
526             Manager.v().addsExclusionWithSearch++;
527             } else {
528             Manager.v().addsExclusionWithoutSearch++;
529             }
530         }
531         FastHierarchy hierarchy = Scene.v().getOrMakeFastHierarchy();
532
533         for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) {
534             RefType exclusionBase = ((AnySubType) i.next()).getBase();
535             if (hierarchy.canStoreType(e, exclusionBase)) {
536             throw new AlreadyHasExclusionsException(
537                 "ThrowableSet.add(RefType): adding" + e.toString()
538                 + " to the set [ " + this.toString()
539                 + "] where " + exclusionBase.toString()
540                 + " is excluded.");
541             }
542         }
543
544         for (Iterator i = exceptionsIncluded.iterator(); i.hasNext() ; ) {
545             RefLikeType incumbent = (RefLikeType) i.next();
546             if (incumbent instanceof AnySubType) {
547             // Need to use incumbent.getBase() because
548
// hierarchy.canStoreType() assumes that parent
549
// is not an AnySubType.
550
RefType incumbentBase = ((AnySubType) incumbent).getBase();
551             if (hierarchy.canStoreType(e, incumbentBase)) {
552                 memoizedAdds.put(e, this);
553                 return this;
554             }
555             } else if (! (incumbent instanceof RefType)) {
556             // assertion failure.
557
throw new IllegalStateException JavaDoc("ThrowableSet.add(RefType): Set element " +
558                             incumbent.toString() +
559                             " is neither a RefType nor an AnySubType.");
560             }
561         }
562         Set resultSet = new HashSet(this.exceptionsIncluded);
563         resultSet.add(e);
564         result = Manager.v().registerSetIfNew(resultSet,
565                               this.exceptionsExcluded);
566         memoizedAdds.put(e, result);
567         return result;
568         }
569     }
570     }
571
572
573     /**
574      * Returns a <code>ThrowableSet</code> which contains
575      * <code>e</code> and all of its subclasses as well as the
576      * exceptions in this set.
577      *
578      * <p><code>e</code> should be an instance of {@link AnySubType}
579      * if you know that the
580      * compile-time type of the exception you are representing is
581      * <code>e</code>, but the exception may be instantiated at run-time
582      * by a subclass of
583      * <code>e</code>.
584      *
585      * <p>For example, if you were recording the type of
586      * the exception thrown by
587      *
588      * <pre>
589      * catch (IOException e) {
590      * throw e;
591      * }
592      * </pre>
593      *
594      * you would call
595      *
596      * <pre>
597      * <code>add(AnySubtype.v(Scene.v().getRefType("java.lang.Exception.IOException")))</code>
598      * </pre>
599      *
600      * since the handler might rethrow any subclass of
601      * <code>IOException</code>.
602      *
603      * @param e represents a subtree of the exception class hierarchy
604      * to add to this set.
605      *
606      * @return a set containing <code>e</code> and all its subclasses,
607      * as well as the exceptions represented by this set.
608      *
609      * @throws ThrowableSet.AlreadyHasExclusionsException if this
610      * <code>ThrowableSet</code> is the result of a {@link
611      * #whichCatchableAs(RefType)} operation and, thus, unable to
612      * represent the addition of <code>e</code>.
613      */

614     public ThrowableSet add(AnySubType e)
615       throws ThrowableSet.AlreadyHasExclusionsException {
616     if (INSTRUMENTING) {
617         Manager.v().addsOfAnySubType++;
618     }
619
620     ThrowableSet result = getMemoizedAdds(e);
621     if (result != null) {
622         if (INSTRUMENTING) {
623         Manager.v().addsInclusionFromMemo++;
624         Manager.v().addsExclusionWithoutSearch++;
625         }
626         return result;
627     } else {
628         FastHierarchy hierarchy = Scene.v().getOrMakeFastHierarchy();
629         RefType newBase = e.getBase();
630
631         if (INSTRUMENTING) {
632         if (exceptionsExcluded.size() != 0) {
633             Manager.v().addsExclusionWithSearch++;
634         } else {
635             Manager.v().addsExclusionWithoutSearch++;
636         }
637         }
638         for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) {
639         RefType exclusionBase = ((AnySubType) i.next()).getBase();
640         if (hierarchy.canStoreType(newBase, exclusionBase)
641             || hierarchy.canStoreType(exclusionBase, newBase)) {
642             if (INSTRUMENTING) {
643             // To ensure that the subcategories total properly:
644
Manager.v().addsInclusionInterrupted++;
645             }
646             throw new AlreadyHasExclusionsException(
647             "ThrowableSet.add(" + e.toString()
648             + ") to the set [ " + this.toString()
649             + "] where " + exclusionBase.toString()
650             + " is excluded.");
651         }
652         }
653
654         if (this.exceptionsIncluded.contains(e)) {
655         if (INSTRUMENTING) {
656             Manager.v().addsInclusionFromMap++;
657         }
658         return this;
659
660         } else {
661         if (INSTRUMENTING) {
662             Manager.v().addsInclusionFromSearch++;
663         }
664
665         int changes = 0;
666         boolean addNewException = true;
667         Set resultSet = new HashSet();
668
669         for (Iterator i = this.exceptionsIncluded.iterator(); i.hasNext() ; ) {
670             RefLikeType incumbent = (RefLikeType) i.next();
671             if (incumbent instanceof RefType) {
672             if (hierarchy.canStoreType(incumbent, newBase)) {
673                 // Omit incumbent from result.
674
changes++;
675             } else {
676                 resultSet.add(incumbent);
677             }
678             } else if (incumbent instanceof AnySubType) {
679             RefType incumbentBase = ((AnySubType) incumbent).getBase();
680             // We have to use the base types in these hierarchy calls
681
// because we want to know if _all_ possible
682
// types represented by e can be represented by
683
// the incumbent, or vice versa.
684
if (hierarchy.canStoreType(newBase, incumbentBase)) {
685                 addNewException = false;
686                 resultSet.add(incumbent);
687             } else if (hierarchy.canStoreType(incumbentBase, newBase)) {
688                 // Omit incumbent from result;
689
changes++;
690             } else {
691                 resultSet.add(incumbent);
692             }
693             } else { // assertion failure.
694
throw new IllegalStateException JavaDoc("ThrowableSet.add(AnySubType): Set element " +
695                             incumbent.toString() +
696                             " is neither a RefType nor an AnySubType.");
697             }
698         }
699         if (addNewException) {
700             resultSet.add(e);
701             changes++;
702         }
703         if (changes > 0) {
704             result = Manager.v().registerSetIfNew(resultSet,
705                               this.exceptionsExcluded);
706         } else {
707             result = this;
708         }
709         memoizedAdds.put(e, result);
710         return result;
711         }
712     }
713     }
714
715
716     /**
717      * Returns a <code>ThrowableSet</code> which contains
718      * all the exceptions in <code>s</code> in addition to those in
719      * this <code>ThrowableSet</code>.
720      *
721      * @param s set of exceptions to add to this set.
722      *
723      * @return the union of this set with <code>s</code>
724      *
725      * @throws ThrowableSet.AlreadyHasExclusionsException if this
726      * <code>ThrowableSet</code> or <code>s</code> is the
727      * result of a {@link #whichCatchableAs(RefType)} operation, so that
728      * it is not possible to represent the addition of <code>s</code> to
729      * this <code>ThrowableSet</code>.
730      */

731     public ThrowableSet add(ThrowableSet s)
732       throws ThrowableSet.AlreadyHasExclusionsException {
733     if (INSTRUMENTING) {
734         Manager.v().addsOfSet++;
735     }
736     if (exceptionsExcluded.size() > 0 || s.exceptionsExcluded.size() > 0) {
737         throw new AlreadyHasExclusionsException("ThrowableSet.Add(ThrowableSet): attempt to add to [" + this.toString() + "] after removals recorded.");
738     }
739     ThrowableSet result = getMemoizedAdds(s);
740     if (result == null) {
741         if (INSTRUMENTING) {
742         Manager.v().addsInclusionFromSearch++;
743         Manager.v().addsExclusionWithoutSearch++;
744         }
745         result = this.add(s.exceptionsIncluded);
746         memoizedAdds.put(s, result);
747     } else if (INSTRUMENTING) {
748         Manager.v().addsInclusionFromMemo++;
749         Manager.v().addsExclusionWithoutSearch++;
750     }
751     return result;
752     }
753
754
755     /**
756      * Returns a <code>ThrowableSet</code> which contains all
757      * the exceptions in <code>addedExceptions</code> in addition to those
758      * in this <code>ThrowableSet</code>.
759      *
760      * @param addedExceptions a set of {@link RefLikeType} and
761      * {@link AnySubType} objects to be added to the types included in this
762      * <code>ThrowableSet</code>.
763      *
764      * @return a set containing all the <code>addedExceptions</code> as well
765      * as the exceptions in this set.
766      */

767     private ThrowableSet add(Set addedExceptions) {
768     Set resultSet = new HashSet(this.exceptionsIncluded);
769     int changes = 0;
770     FastHierarchy hierarchy = Scene.v().getOrMakeFastHierarchy();
771
772     // This algorithm is O(n m), where n and m are the sizes of the
773
// two sets, so hope that the sets are small.
774

775     for (Iterator i = addedExceptions.iterator(); i.hasNext(); ) {
776         RefLikeType newType = (RefLikeType) i.next();
777         if (! resultSet.contains(newType)) {
778         boolean addNewType = true;
779         if (newType instanceof RefType) {
780             for (Iterator j = resultSet.iterator(); j.hasNext(); ) {
781             RefLikeType incumbentType = (RefLikeType) j.next();
782             if (incumbentType instanceof RefType) {
783                 if (newType == incumbentType) {
784                 // assertion failure.
785
throw new IllegalStateException JavaDoc("ThrowableSet.add(Set): resultSet.contains() failed to screen duplicate RefType "
786                                 + newType);
787                 }
788             } else if (incumbentType instanceof AnySubType) {
789                 RefType incumbentBase = ((AnySubType) incumbentType).getBase();
790                 if (hierarchy.canStoreType(newType, incumbentBase)) {
791                 // No need to add this class.
792
addNewType = false;
793                 }
794             } else { // assertion failure.
795
throw new IllegalStateException JavaDoc("ThrowableSet.add(Set): incumbent Set element "
796                                 + incumbentType
797                                 + " is neither a RefType nor an AnySubType.");
798             }
799             }
800         } else if (newType instanceof AnySubType) {
801             RefType newBase = ((AnySubType) newType).getBase();
802             for (Iterator j = resultSet.iterator(); j.hasNext(); ) {
803             RefLikeType incumbentType = (RefLikeType) j.next();
804             if (incumbentType instanceof RefType) {
805                 RefType incumbentBase = (RefType) incumbentType;
806                 if (hierarchy.canStoreType(incumbentBase, newBase)) {
807                 j.remove();
808                 changes++;
809                 }
810             } else if (incumbentType instanceof AnySubType) {
811                 RefType incumbentBase = ((AnySubType) incumbentType).getBase();
812                 if (newBase == incumbentBase) {
813                 // assertion failure.
814
throw new IllegalStateException JavaDoc("ThrowableSet.add(Set): resultSet.contains() failed to screen duplicate AnySubType "
815                                + newBase);
816                 } else if (hierarchy.canStoreType(incumbentBase, newBase)) {
817                 j.remove();
818                 changes++;
819                 } else if (hierarchy.canStoreType(newBase, incumbentBase)) {
820                 // No need to add this class.
821
addNewType = false;
822                 }
823             } else { // assertion failure.
824
throw new IllegalStateException JavaDoc("ThrowableSet.add(Set): old Set element "
825                                + incumbentType
826                                + " is neither a RefType nor an AnySubType.");
827             }
828             }
829         } else { // assertion failure.
830
throw new IllegalArgumentException JavaDoc("ThrowableSet.add(Set): new Set element "
831                                + newType
832                                + " is neither a RefType nor an AnySubType.");
833         }
834         if (addNewType) {
835             changes++;
836             resultSet.add(newType);
837         }
838         }
839     }
840                 
841     ThrowableSet result = null;
842     if (changes > 0) {
843         result = Manager.v().registerSetIfNew(resultSet,
844                           this.exceptionsExcluded);
845     } else {
846         result = this;
847     }
848     return result;
849     }
850
851
852     /**
853      * Indicates whether this ThrowableSet includes some
854      * exception that might be caught by a handler argument of the
855      * type <code>catcher</code>.
856      *
857      * @param catcher type of the handler parameter to be tested.
858      *
859      * @return <code>true</code> if this set contains an exception type
860      * that might be caught by <code>catcher</code>,
861      * false if it does not.
862      */

863     public boolean catchableAs(RefType catcher) {
864     if (INSTRUMENTING) {
865         Manager.v().catchableAsQueries++;
866     }
867
868     FastHierarchy h = Scene.v().getOrMakeFastHierarchy();
869
870     if (exceptionsExcluded.size() > 0) {
871         if (INSTRUMENTING) {
872         Manager.v().catchableAsFromSearch++;
873         }
874         for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) {
875         AnySubType exclusion = (AnySubType) i.next();
876         if (h.canStoreType(catcher, exclusion.getBase())) {
877             return false;
878         }
879         }
880     }
881
882     if (exceptionsIncluded.contains(catcher)) {
883         if (INSTRUMENTING) {
884         if (exceptionsExcluded.size() == 0) {
885             Manager.v().catchableAsFromMap++;
886         } else {
887             Manager.v().catchableAsFromSearch++;
888         }
889         }
890         return true;
891     } else {
892         if (INSTRUMENTING) {
893         if (exceptionsExcluded.size() == 0) {
894             Manager.v().catchableAsFromSearch++;
895         }
896         }
897         for (Iterator i = exceptionsIncluded.iterator(); i.hasNext(); ) {
898         RefLikeType thrownType = (RefLikeType) i.next();
899         if (thrownType instanceof RefType) {
900             if (thrownType == catcher) {
901             // assertion failure.
902
throw new IllegalStateException JavaDoc("ThrowableSet.catchableAs(RefType): exceptions.contains() failed to match contained RefType "
903                                + catcher);
904             } else if (h.canStoreType(thrownType, catcher)) {
905             return true;
906             }
907         } else {
908             RefType thrownBase = ((AnySubType) thrownType).getBase();
909             // At runtime, thrownType might be instantiated by any
910
// of thrownBase's subtypes, so:
911
if (h.canStoreType(thrownBase, catcher)
912             || h.canStoreType(catcher, thrownBase)) {
913             return true;
914             }
915         }
916         }
917         return false;
918     }
919     }
920
921
922     /**
923      * Partitions the exceptions in this <code>ThrowableSet</code>
924      * into those which would be caught by a handler with the passed
925      * <code>catch</code> parameter type and those which would not.
926      *
927      * @param catcher type of the handler parameter to be tested.
928      *
929      * @return a pair of <code>ThrowableSet</code>s, one containing the
930      * types in this <code>ThrowableSet</code> which would be
931      * be caught as <code>catcher</code> and the other containing
932      * the types in this <code>ThrowableSet</code> which would
933      * not be caught as <code>catcher</code>.
934      */

935     public Pair whichCatchableAs(RefType catcher) {
936     if (INSTRUMENTING) {
937         Manager.v().removesOfAnySubType++;
938     }
939
940     FastHierarchy h = Scene.v().getOrMakeFastHierarchy();
941     Set caughtIncluded = null;
942     Set caughtExcluded = null;
943     Set uncaughtIncluded = null;
944     Set uncaughtExcluded = null;
945
946     if (INSTRUMENTING) {
947         Manager.v().removesFromSearch++;
948     }
949
950     for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) {
951         AnySubType exclusion = (AnySubType) i.next();
952         RefType exclusionBase = exclusion.getBase();
953         if (h.canStoreType(catcher, exclusionBase)) {
954         // Because the add() operations ban additions to sets
955
// with exclusions, we can be sure no types in this are
956
// caught by catcher.
957
return new Pair(ThrowableSet.Manager.v().EMPTY, this);
958         } else if (h.canStoreType(exclusionBase, catcher)) {
959         // exclusion wouldn't be in exceptionsExcluded if one
960
// of its supertypes were not in exceptionsIncluded,
961
// so we know the next loop will add either that supertype
962
// or catcher to caughtIncluded. Thus:
963
caughtExcluded = addExceptionToSet(exclusion, caughtExcluded);
964         } else {
965         uncaughtExcluded = addExceptionToSet(exclusion, uncaughtExcluded);
966         }
967     }
968
969     for (Iterator i = exceptionsIncluded.iterator(); i.hasNext(); ) {
970         RefLikeType inclusion = (RefLikeType) i.next();
971         if (inclusion instanceof RefType) {
972         if (h.canStoreType(inclusion, catcher)) {
973             caughtIncluded = addExceptionToSet(inclusion, caughtIncluded);
974         } else {
975             uncaughtIncluded = addExceptionToSet(inclusion, uncaughtIncluded);
976         }
977         } else {
978         RefType base = ((AnySubType) inclusion).getBase();
979         if (h.canStoreType(base, catcher)) {
980             // All subtypes of base will be caught. Any exclusions
981
// will already have been copied to caughtExcluded by
982
// the preceding loop.
983
caughtIncluded =
984             addExceptionToSet(inclusion, caughtIncluded);
985         } else if (h.canStoreType(catcher, base)) {
986             // Some subtypes of base will be caught, and
987
// we know that not all of those catchable subtypes
988
// are among exceptionsExcluded, since in that case we
989
// would already have returned from within the
990
// preceding loop. So, remove AnySubType(catcher)
991
// from the uncaught types.
992
uncaughtIncluded
993             = addExceptionToSet(inclusion, uncaughtIncluded);
994             uncaughtExcluded
995             = addExceptionToSet(AnySubType.v(catcher), uncaughtExcluded);
996             caughtIncluded
997             = addExceptionToSet(AnySubType.v(catcher), caughtIncluded);
998             // Any already excluded subtypes of inclusion
999
// which are subtypes of catcher will have been
1000
// added to caughtExcluded by the previous loop.
1001
} else {
1002            uncaughtIncluded
1003            = addExceptionToSet(inclusion, uncaughtIncluded);
1004        }
1005        }
1006    }
1007    ThrowableSet caughtSet
1008        = Manager.v().registerSetIfNew(caughtIncluded, caughtExcluded);
1009    ThrowableSet uncaughtSet
1010        = Manager.v().registerSetIfNew(uncaughtIncluded, uncaughtExcluded);
1011    return new Pair(caughtSet, uncaughtSet);
1012    }
1013
1014
1015    /**
1016     * The return type for {@link ThrowableSet#whichCatchableAs(RefType)},
1017     * consisting of a pair of ThrowableSets.
1018     */

1019    public static class Pair {
1020    private ThrowableSet caught;
1021    private ThrowableSet uncaught;
1022    /**
1023     * Constructs a <code>ThrowableSet.Pair</code>.
1024     *
1025     * @param caught The set of exceptions to be returned when
1026     * {@link #getCaught()} is called on the constructed
1027     * <code>ThrowableSet.Pair</code>.
1028     *
1029     * @param uncaught The set of exceptions to be returned when
1030     * {@link #getUncaught()} is called on the
1031     * constructed <code>ThrowableSet.Pair</code>.
1032     */

1033    protected Pair(ThrowableSet caught, ThrowableSet uncaught) {
1034        this.caught = caught;
1035        this.uncaught = uncaught;
1036    }
1037
1038    /**
1039     * @return the set of caught exceptions.
1040     */

1041    public ThrowableSet getCaught() {
1042        return caught;
1043    }
1044
1045    /**
1046     * @return the set of uncaught exceptions.
1047     */

1048    public ThrowableSet getUncaught() {
1049        return uncaught;
1050    }
1051
1052    /**
1053     * Indicates whether two {@link Object}s are
1054     * <code>ThrowableSet.Pair</code>s representing the same set of
1055     * caught and uncaught exception types.
1056     *
1057     * @param o the <code>Object</code> to compare to this
1058     * <code>ThrowableSet.Pair</code>.
1059     *
1060     * @return <code>true</code> if <code>o</code> is a
1061     * <code>ThrowableSet.Pair</code> representing the same set of
1062     * caught and uncaught types as this
1063     * <code>ThrowableSet.Pair</code>.
1064     */

1065    public boolean equals(Object JavaDoc o) {
1066        if (o == this) {
1067        return true;
1068        }
1069        if (! (o instanceof Pair)) {
1070        return false;
1071        }
1072        Pair tsp = (Pair) o;
1073        if ( this.caught.equals(tsp.caught)
1074        && this.uncaught.equals(tsp.uncaught)) {
1075        return true;
1076        }
1077        return false;
1078    }
1079
1080
1081    public int hashCode() {
1082        int result = 31;
1083        result = 37 * result + caught.hashCode();
1084        result = 37 * result + uncaught.hashCode();
1085        return result;
1086    }
1087    }
1088
1089
1090    /**
1091     * Utility method for building sets of exceptional types for a
1092     * {@link Pair}.
1093     *
1094     * @param e The exceptional type to add to the set.
1095     *
1096     * @param set The <code>Set</code> to which to add the types, or
1097     * <code>null</code> if no <code>Set</code> has yet been
1098     * allocated.
1099     *
1100     * @return A <code>Set</code> containing the elements in <code>set</code>
1101     * plus <code>e</code>.
1102     */

1103    private Set addExceptionToSet(RefLikeType e, Set set) {
1104    if (set == null) {
1105        set = new HashSet();
1106    }
1107    set.add(e);
1108    return set;
1109    }
1110
1111
1112    /**
1113     * Returns a string representation of this <code>ThrowableSet</code>.
1114     */

1115    public String JavaDoc toString() {
1116    StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(this.toBriefString());
1117    buffer.append(":\n ");
1118    for (Iterator i = exceptionsIncluded.iterator(); i.hasNext(); ) {
1119        buffer.append('+');
1120        Object JavaDoc o = i.next();
1121        buffer.append(o == null ? "null" : o.toString());
1122        // buffer.append(i.next().toString());
1123
}
1124    for (Iterator i = exceptionsExcluded.iterator(); i.hasNext(); ) {
1125        buffer.append('-');
1126        buffer.append(i.next().toString());
1127    }
1128    return buffer.toString();
1129    }
1130
1131
1132    /**
1133     * Returns a cryptic identifier for this <code>ThrowableSet</code>,
1134     * used to identify a set when it appears in a collection.
1135     */

1136    public String JavaDoc toBriefString() {
1137    return super.toString();
1138    }
1139
1140
1141    /**
1142     * Returns an {@link Iterator} over a {@link Collection} of
1143     * Throwable types which iterates over its elements in a
1144     * consistent order (maintaining an ordering that is consistent
1145     * across different runs makes it easier to compare sets generated
1146     * by different implementations of the CFG classes).
1147     *
1148     * @param coll The collection to iterate over.
1149     *
1150     * @return An iterator which presents the elements of <code>coll</code>
1151     * in order.
1152     */

1153    private static Iterator sortedThrowableIterator(Collection coll) {
1154    if (coll.size() <= 1) {
1155        return coll.iterator();
1156    } else {
1157        Object JavaDoc array[] = coll.toArray();
1158        Arrays.sort(array, new ThrowableComparator());
1159        return Arrays.asList(array).iterator();
1160    }
1161    }
1162
1163
1164    /**
1165     * Comparator used to implement sortedThrowableIterator().
1166     *
1167     */

1168    private static class ThrowableComparator implements java.util.Comparator JavaDoc {
1169
1170    private static RefType baseType(Object JavaDoc o) {
1171        if (o instanceof AnySubType) {
1172        return ((AnySubType) o).getBase();
1173        } else {
1174        return (RefType) o; // ClassCastException if o is not a RefType.
1175
}
1176    }
1177
1178    public int compare(Object JavaDoc o1, Object JavaDoc o2) {
1179        RefType t1 = baseType(o1);
1180        RefType t2 = baseType(o2);
1181        if (t1.equals(t2)) {
1182        // There should never be both AnySubType(t) and
1183
// t in a ThrowableSet, but if it happens, put
1184
// AnySubType(t) first:
1185
if (o1 instanceof AnySubType) {
1186            if (o2 instanceof AnySubType) {
1187            return 0;
1188            } else {
1189            return -1;
1190            }
1191        } else if (o2 instanceof AnySubType) {
1192            return 1;
1193        } else {
1194            return 0;
1195        }
1196        } else {
1197        return t1.toString().compareTo(t2.toString());
1198        }
1199    }
1200
1201    public boolean equal(Object JavaDoc o1, Object JavaDoc o2) {
1202        return (o1.equals(o2));
1203    }
1204    }
1205
1206
1207    /**
1208     * <p>Produce an abbreviated representation of this
1209     * <code>ThrowableSet</code>, suitable for human consumption. The
1210     * abbreviations include:</p>
1211     *
1212     * <ul>
1213     *
1214     * <li>The strings &ldquo;<code>java.lang.</code>&rdquo; is
1215     * stripped from the beginning of exception names.</li>
1216     *
1217     * <li>The string &ldquo;<code>Exception</code>&rdquo; is stripped from
1218     * the ends of exception names.</li>
1219     *
1220     * <li>Instances of <code>AnySubType</code> are indicated by surrounding
1221     * the base type name with parentheses, rather than with the string
1222     * &ldquo;<code>Any_subtype_of_</code>&rdquo;</li>
1223     *
1224     * <li>If this <code>ThrowableSet</code> includes all the elements
1225     * of {@link ThrowableSet.Manager#VM_ERRORS VM_ERRORS}, they are
1226     * abbreviated as &ldquo;<code>vmErrors</code>&rdquo; rather than
1227     * listed individually.</li>
1228     *
1229     * @return An abbreviated representation of the contents of this set.
1230     */

1231    public String JavaDoc toAbbreviatedString() {
1232    return toAbbreviatedString(exceptionsIncluded, '+')
1233        + toAbbreviatedString(exceptionsExcluded, '-');
1234    }
1235
1236
1237    /**
1238     * <p>Utility method which prints the abbreviations of the
1239     * elements in a passed {@link Set} of exception types.</p>
1240     *
1241     * @param s The exceptions to print.
1242     *
1243     * @param connector The character to insert between exceptions.
1244     *
1245     * @return An abbreviated representation of the exceptions.
1246     */

1247    private String JavaDoc toAbbreviatedString(Set s, char connector) {
1248    final String JavaDoc JAVA_LANG = "java.lang.";
1249    final int JAVA_LANG_LENGTH = JAVA_LANG.length();
1250    final String JavaDoc EXCEPTION = "Exception";
1251    final int EXCEPTION_LENGTH = EXCEPTION.length();
1252
1253    Collection vmErrorThrowables = ThrowableSet.Manager.v().VM_ERRORS.exceptionsIncluded;
1254    boolean containsAllVmErrors = s.containsAll(vmErrorThrowables);
1255    StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
1256
1257    if (containsAllVmErrors) {
1258        buf.append(connector);
1259        buf.append("vmErrors");
1260    }
1261
1262    for (Iterator it = sortedThrowableIterator(s); it.hasNext(); ) {
1263        RefLikeType reflikeType = (RefLikeType) it.next();
1264        RefType baseType = null;
1265        if (reflikeType instanceof RefType) {
1266        baseType = (RefType)reflikeType;
1267        if (vmErrorThrowables.contains(baseType) && containsAllVmErrors) {
1268            continue; // Already accounted for vmErrors.
1269
} else {
1270            buf.append(connector);
1271        }
1272        } else if (reflikeType instanceof AnySubType) {
1273        buf.append(connector);
1274        buf.append('(');
1275        baseType = ((AnySubType)reflikeType).getBase();
1276        }
1277        String JavaDoc typeName = baseType.toString();
1278        if (typeName.startsWith(JAVA_LANG)) {
1279        typeName = typeName.substring(JAVA_LANG_LENGTH);
1280        }
1281        if (typeName.length() > EXCEPTION_LENGTH &&
1282        typeName.endsWith(EXCEPTION)) {
1283        typeName = typeName.substring(0, typeName.length()-EXCEPTION_LENGTH);
1284        }
1285        buf.append(typeName);
1286        if (reflikeType instanceof AnySubType) {
1287        buf.append(')');
1288        }
1289    }
1290    return buf.toString();
1291    }
1292
1293
1294    /**
1295     * A package-private method to provide unit tests with access to
1296     * the {@link RefLikeType} objects which represent the
1297     * <code>Throwable</code> types included in this set.
1298     *
1299     * @return an unmodifiable collection view of the
1300     * <code>Throwable</code> types in this set.
1301     */

1302    Collection typesIncluded() {
1303        return new AbstractCollection() {
1304
1305        public Iterator iterator() {
1306        return new Iterator() {
1307            private Iterator i = exceptionsIncluded.iterator();
1308
1309            public boolean hasNext() {
1310            return i.hasNext();
1311            }
1312
1313            public Object JavaDoc next() {
1314            return i.next();
1315            }
1316
1317            public void remove() {
1318            throw new UnsupportedOperationException JavaDoc();
1319            }
1320        };
1321        }
1322
1323        public int size() {
1324        return exceptionsIncluded.size();
1325        }
1326    };
1327    }
1328
1329
1330    /**
1331     * A package-private method to provide unit tests with access to
1332     * the {@link RefLikeType} objects which represent the
1333     * <code>Throwable</code> types excluded from this set.
1334     *
1335     * @return an unmodifiable collection view of the
1336     * <code>Throwable</code> types excluded from this set.
1337     */

1338    Collection typesExcluded() {
1339        return new AbstractCollection() {
1340
1341        public Iterator iterator() {
1342        return new Iterator() {
1343            private Iterator i = exceptionsExcluded.iterator();
1344
1345            public boolean hasNext() {
1346            return i.hasNext();
1347            }
1348
1349            public Object JavaDoc next() {
1350            return i.next();
1351            }
1352
1353            public void remove() {
1354            throw new UnsupportedOperationException JavaDoc();
1355            }
1356        };
1357        }
1358
1359        public int size() {
1360        return exceptionsExcluded.size();
1361        }
1362    };
1363    }
1364
1365
1366    /**
1367     * A package-private method to provide unit tests with access to
1368     * ThrowableSet's internals.
1369     */

1370    Map getMemoizedAdds() {
1371    if (memoizedAdds == null) {
1372        return Collections.EMPTY_MAP;
1373    } else {
1374        return Collections.unmodifiableMap(memoizedAdds);
1375    }
1376    }
1377}
1378
Popular Tags