001: /*
002: * Bytecode Analysis Framework
003: * Copyright (C) 2003-2005 University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.ba.ch;
021:
022: import java.util.Collection;
023: import java.util.Collections;
024: import java.util.HashSet;
025: import java.util.Set;
026:
027: import org.apache.bcel.classfile.Field;
028: import org.apache.bcel.classfile.JavaClass;
029: import org.apache.bcel.classfile.Method;
030:
031: import edu.umd.cs.findbugs.SystemProperties;
032: import edu.umd.cs.findbugs.ba.AnalysisContext;
033: import edu.umd.cs.findbugs.ba.XClass;
034: import edu.umd.cs.findbugs.ba.XFactory;
035: import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
036: import edu.umd.cs.findbugs.classfile.ClassDescriptor;
037: import edu.umd.cs.findbugs.classfile.DescriptorFactory;
038: import edu.umd.cs.findbugs.classfile.Global;
039:
040: /**
041: * Support for class hierarchy queries.
042: *
043: * @author Bill Pugh
044: * @author David Hovemeyer
045: */
046: @Deprecated
047: // use Subtypes2 instead
048: public class Subtypes {
049: private static final boolean DEBUG_HIERARCHY = false || SystemProperties
050: .getBoolean("findbugs.debug.hierarchy");
051:
052: public Subtypes() {
053: }
054:
055: /**
056: * Get immediate subtypes of given class or interface.
057: *
058: * @param c a class or interface
059: * @return set of immediate subtypes
060: */
061:
062: public Set<JavaClass> getImmediateSubtypes(JavaClass c) {
063: ClassDescriptor classDescriptor = DescriptorFactory
064: .createClassDescriptor(c);
065: try {
066: return getJavaClasses(subtypes2().getSubtypes(
067: classDescriptor));
068: } catch (ClassNotFoundException e) {
069: AnalysisContext.reportMissingClass(e);
070: return Collections.emptySet();
071: } catch (CheckedAnalysisException e) {
072: AnalysisContext.logError("Error checking subtypes of "
073: + c.getClassName(), e);
074: return Collections.emptySet();
075: }
076: }
077:
078: private JavaClass getJavaClass(ClassDescriptor descriptor)
079: throws CheckedAnalysisException {
080: return Global.getAnalysisCache().getClassAnalysis(
081: JavaClass.class, descriptor);
082: }
083:
084: private JavaClass getJavaClass(XClass xClass)
085: throws CheckedAnalysisException {
086: return Global.getAnalysisCache().getClassAnalysis(
087: JavaClass.class, xClass.getClassDescriptor());
088: }
089:
090: private Set<JavaClass> getJavaClasses(
091: Collection<ClassDescriptor> descriptors)
092: throws CheckedAnalysisException {
093: HashSet<JavaClass> result = new HashSet<JavaClass>();
094: for (ClassDescriptor c : descriptors)
095: result.add(getJavaClass(c));
096: return result;
097: }
098:
099: private Set<JavaClass> getJavaClassesFromXClasses(
100: Collection<XClass> xclasses)
101: throws CheckedAnalysisException {
102: HashSet<JavaClass> result = new HashSet<JavaClass>();
103: for (XClass c : xclasses)
104: result.add(getJavaClass(c));
105: return result;
106: }
107:
108: private static Subtypes2 subtypes2() {
109: AnalysisContext analysisContext = AnalysisContext
110: .currentAnalysisContext();
111: return analysisContext.getSubtypes2();
112: }
113:
114: /**
115: * Determine if a class or interface has subtypes
116: *
117: * @param c a class or interface
118: * @return true if c has any subtypes/interfaces
119: */
120: public boolean hasSubtypes(JavaClass c) {
121: ClassDescriptor classDescriptor = DescriptorFactory
122: .createClassDescriptor(c);
123: try {
124: return !subtypes2().getDirectSubtypes(classDescriptor)
125: .isEmpty();
126: } catch (ClassNotFoundException e) {
127: AnalysisContext.reportMissingClass(e);
128: return false;
129: }
130: }
131:
132: /**
133: * Get set of all known classes and interfaces.
134: *
135: * @return set of all known classes and interfaces
136: */
137: @Deprecated
138: public Set<JavaClass> getAllClasses() {
139: assert false;
140: try {
141: return getJavaClassesFromXClasses(subtypes2()
142: .getXClassCollection());
143: } catch (CheckedAnalysisException e) {
144: throw new AssertionError("We're screwed");
145: }
146: }
147:
148: /**
149: * Get set of all transitive subtypes of given class or interface,
150: * <em>not including the class or interface itself</em>.
151: *
152: * @param c a class or interface
153: * @return set of all transitive subtypes
154: */
155: public Set<JavaClass> getTransitiveSubtypes(JavaClass c) {
156: assert !c.getClassName().equals("java.lang.Object");
157: ClassDescriptor classDescriptor = DescriptorFactory
158: .createClassDescriptor(c);
159: try {
160: return getJavaClasses(subtypes2().getSubtypes(
161: classDescriptor));
162: } catch (ClassNotFoundException e) {
163: AnalysisContext.reportMissingClass(e);
164: return Collections.emptySet();
165: } catch (CheckedAnalysisException e) {
166: AnalysisContext.logError("Error checking subtypes of "
167: + c.getClassName(), e);
168: return Collections.emptySet();
169: }
170: }
171:
172: /**
173: * Get set of all known transitive classes and interfaces which are subtypes of
174: * both of the given classes and/or interfaces. Note that in this method,
175: * we consider a class to be a subtype of itself. Therefore, this method
176: * can be used to determine, e.g., if there are any classes implementing
177: * both of two given interfaces.
178: *
179: * @param a a class or interface
180: * @param b another class or interface
181: * @return set of all common subtypes of <i>a</i> and <i>b</i>
182: */
183: public Set<JavaClass> getTransitiveCommonSubtypes(JavaClass a,
184: JavaClass b) {
185: ClassDescriptor aD = DescriptorFactory.createClassDescriptor(a);
186: ClassDescriptor bD = DescriptorFactory.createClassDescriptor(b);
187: try {
188: return getJavaClasses(subtypes2()
189: .getTransitiveCommonSubtypes(aD, bD));
190: } catch (ClassNotFoundException e) {
191: AnalysisContext.reportMissingClass(e);
192: return Collections.emptySet();
193: } catch (CheckedAnalysisException e) {
194: AnalysisContext.logError(
195: "Error checking common subtypes of "
196: + a.getClassName() + " and "
197: + b.getClassName(), e);
198: return Collections.emptySet();
199: }
200:
201: }
202:
203: public static void learnFieldsAndMethods(JavaClass c) {
204: for (Field f : c.getFields())
205: XFactory.createXField(c, f);
206: for (Method m : c.getMethods())
207: XFactory.createXMethod(c, m);
208: }
209:
210: @Deprecated
211: public void addNamedClass(String name) {
212:
213: }
214:
215: @Deprecated
216: public void addApplicationClass(JavaClass c) {
217:
218: }
219:
220: @Deprecated
221: public void addClass(JavaClass c) {
222:
223: }
224:
225: public static String extractClassName(String originalName) {
226: String name = originalName;
227: if (name.charAt(0) != '['
228: && name.charAt(name.length() - 1) != ';')
229: return name;
230: while (name.charAt(0) == '[')
231: name = name.substring(1);
232: if (name.charAt(0) == 'L'
233: && name.charAt(name.length() - 1) == ';')
234: name = name.substring(1, name.length() - 1);
235: if (name.charAt(0) == '[')
236: throw new IllegalArgumentException("Bad class name: "
237: + originalName);
238: return name;
239: }
240:
241: /**
242: * Determine whether or not the given class is an application class.
243: *
244: * @param javaClass a class
245: * @return true if it's an application class, false if not
246: */
247: public boolean isApplicationClass(JavaClass javaClass) {
248: return subtypes2().isApplicationClass(
249: DescriptorFactory.createClassDescriptor(javaClass));
250: }
251: }
|