001: /*
002: * FindBugs - Find Bugs in Java programs
003: * Copyright (C) 2006, 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.classfile.analysis;
021:
022: import java.lang.annotation.ElementType;
023: import java.util.Arrays;
024: import java.util.Collection;
025: import java.util.HashMap;
026: import java.util.LinkedList;
027: import java.util.List;
028: import java.util.Map;
029:
030: import edu.umd.cs.findbugs.annotations.CheckForNull;
031: import edu.umd.cs.findbugs.ba.XClass;
032: import edu.umd.cs.findbugs.ba.XField;
033: import edu.umd.cs.findbugs.ba.XMethod;
034: import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
035: import edu.umd.cs.findbugs.classfile.ClassDescriptor;
036: import edu.umd.cs.findbugs.classfile.DescriptorFactory;
037: import edu.umd.cs.findbugs.classfile.Global;
038: import edu.umd.cs.findbugs.classfile.ICodeBaseEntry;
039: import edu.umd.cs.findbugs.classfile.MethodDescriptor;
040: import edu.umd.cs.findbugs.util.Util;
041:
042: /**
043: * ClassInfo represents important metadata about a loaded class, such as its
044: * superclass, access flags, codebase entry, etc.
045: *
046: * @author David Hovemeyer
047: */
048: public class ClassInfo extends ClassNameAndSuperclassInfo implements
049: XClass, AnnotatedObject {
050: private final FieldInfo[] xFields;
051:
052: private final MethodInfo[] xMethods;
053:
054: private final ClassDescriptor immediateEnclosingClass;
055:
056: /*final*/Map<ClassDescriptor, AnnotationValue> classAnnotations;
057: final private String classSourceSignature;
058: final private String source;
059:
060: public static class Builder extends
061: ClassNameAndSuperclassInfo.Builder {
062: private List<FieldInfo> fieldDescriptorList = new LinkedList<FieldInfo>();
063:
064: private List<MethodInfo> methodDescriptorList = new LinkedList<MethodInfo>();
065:
066: private ClassDescriptor immediateEnclosingClass;
067: final Map<ClassDescriptor, AnnotationValue> classAnnotations = new HashMap<ClassDescriptor, AnnotationValue>();
068: private String classSourceSignature;
069: private String source;
070:
071: @Override
072: public ClassInfo build() {
073: return new ClassInfo(classDescriptor, classSourceSignature,
074: super classDescriptor, interfaceDescriptorList,
075: codeBaseEntry, accessFlags, source, majorVersion,
076: minorVersion, referencedClassDescriptorList,
077: calledClassDescriptorList, classAnnotations,
078: fieldDescriptorList.toArray(new FieldInfo[0]),
079: methodDescriptorList.toArray(new MethodInfo[0]),
080: immediateEnclosingClass);
081: }
082:
083: public void setSource(String source) {
084: this .source = source;
085: }
086:
087: /**
088: * @return Returns the classDescriptor.
089: */
090: public ClassDescriptor getClassDescriptor() {
091: return classDescriptor;
092: }
093:
094: public void setSourceSignature(String classSourceSignature) {
095: this .classSourceSignature = classSourceSignature;
096: }
097:
098: public void addAnnotation(String name, AnnotationValue value) {
099: ClassDescriptor annotationClass = DescriptorFactory
100: .createClassDescriptorFromSignature(name);
101: classAnnotations.put(annotationClass, value);
102: }
103:
104: /**
105: * @param fieldDescriptorList
106: * The fieldDescriptorList to set.
107: */
108: public void setFieldDescriptorList(
109: FieldInfo[] fieldDescriptorList) {
110: this .fieldDescriptorList = Arrays
111: .asList(fieldDescriptorList);
112: }
113:
114: public void addFieldDescriptor(FieldInfo field) {
115: fieldDescriptorList.add(field);
116: }
117:
118: /**
119: * @param methodDescriptorList
120: * The methodDescriptorList to set.
121: */
122: public void setMethodDescriptorList(
123: MethodInfo[] methodDescriptorList) {
124: this .methodDescriptorList = Arrays
125: .asList(methodDescriptorList);
126: }
127:
128: public void addMethodDescriptor(MethodInfo method) {
129: methodDescriptorList.add(method);
130: }
131:
132: /**
133: * @param immediateEnclosingClass
134: * The immediateEnclosingClass to set.
135: */
136: public void setImmediateEnclosingClass(
137: ClassDescriptor immediateEnclosingClass) {
138: this .immediateEnclosingClass = immediateEnclosingClass;
139: }
140:
141: }
142:
143: /**
144: *
145: * @param classDescriptor
146: * ClassDescriptor representing the class name
147: * @param superclassDescriptor
148: * ClassDescriptor representing the superclass name
149: * @param interfaceDescriptorList
150: * ClassDescriptors representing implemented interface names
151: * @param codeBaseEntry
152: * codebase entry class was loaded from
153: * @param accessFlags
154: * class's access flags
155: * @param referencedClassDescriptorList
156: * ClassDescriptors of all classes/interfaces referenced by the
157: * class
158: * @param calledClassDescriptors TODO
159: * @param fieldDescriptorList
160: * FieldDescriptors of fields defined in the class
161: * @param methodDescriptorList
162: * MethodDescriptors of methods defined in the class
163: */
164: private ClassInfo(ClassDescriptor classDescriptor,
165: String classSourceSignature,
166: ClassDescriptor super classDescriptor,
167: ClassDescriptor[] interfaceDescriptorList,
168: ICodeBaseEntry codeBaseEntry, int accessFlags,
169: String source, int majorVersion, int minorVersion,
170: Collection<ClassDescriptor> referencedClassDescriptorList,
171: Collection<ClassDescriptor> calledClassDescriptors,
172: Map<ClassDescriptor, AnnotationValue> classAnnotations,
173: FieldInfo[] fieldDescriptorList,
174: MethodInfo[] methodDescriptorList,
175: ClassDescriptor immediateEnclosingClass) {
176: super (classDescriptor, super classDescriptor,
177: interfaceDescriptorList, codeBaseEntry, accessFlags,
178: referencedClassDescriptorList, calledClassDescriptors,
179: majorVersion, minorVersion);
180: this .source = source;
181: this .classSourceSignature = classSourceSignature;
182: this .xFields = fieldDescriptorList;
183: this .xMethods = methodDescriptorList;
184: this .immediateEnclosingClass = immediateEnclosingClass;
185: this .classAnnotations = Util.immutableMap(classAnnotations);
186: }
187:
188: /**
189: * @return Returns the fieldDescriptorList.
190: */
191: public List<? extends XField> getXFields() {
192: return Arrays.asList(xFields);
193: }
194:
195: /**
196: * @return Returns the methodDescriptorList.
197: */
198: public List<? extends XMethod> getXMethods() {
199: return Arrays.asList(xMethods);
200: }
201:
202: /* (non-Javadoc)
203: * @see edu.umd.cs.findbugs.ba.XClass#findMethod(java.lang.String, java.lang.String, boolean)
204: */
205: public XMethod findMethod(String methodName, String methodSig,
206: boolean isStatic) {
207: for (MethodInfo mInfo : xMethods)
208: if (mInfo.getName().equals(methodName)
209: && mInfo.getSignature().equals(methodSig)
210: && mInfo.isStatic() == isStatic)
211: return mInfo;
212: if (true)
213: return null;
214: try {
215: if (getSuperclassDescriptor() == null)
216: return null;
217: XClass super Class = Global.getAnalysisCache()
218: .getClassAnalysis(XClass.class,
219: getSuperclassDescriptor());
220: return super Class.findMethod(methodName, methodSig,
221: isStatic);
222: } catch (CheckedAnalysisException e) {
223: return null;
224: }
225: }
226:
227: /* (non-Javadoc)
228: * @see edu.umd.cs.findbugs.ba.XClass#findMethod(edu.umd.cs.findbugs.classfile.MethodDescriptor)
229: */
230: public XMethod findMethod(MethodDescriptor descriptor) {
231: if (!descriptor.getClassDescriptor().equals(this )) {
232: throw new IllegalArgumentException();
233: }
234: return findMethod(descriptor.getName(), descriptor
235: .getSignature(), descriptor.isStatic());
236: }
237:
238: /* (non-Javadoc)
239: * @see edu.umd.cs.findbugs.ba.XClass#findField(java.lang.String, java.lang.String, boolean)
240: */
241: public XField findField(String name, String signature,
242: boolean isStatic) {
243: for (FieldInfo fInfo : xFields)
244: if (fInfo.getName().equals(name)
245: && fInfo.getSignature().equals(signature)
246: && fInfo.isStatic() == isStatic)
247: return fInfo;
248: try {
249: if (getSuperclassDescriptor() == null)
250: return null;
251: XClass super Class = Global.getAnalysisCache()
252: .getClassAnalysis(XClass.class,
253: getSuperclassDescriptor());
254: return super Class.findField(name, signature, isStatic);
255: } catch (CheckedAnalysisException e) {
256: return null;
257: }
258: }
259:
260: /**
261: * @return Returns the immediateEnclosingClass.
262: */
263: public ClassDescriptor getImmediateEnclosingClass() {
264: return immediateEnclosingClass;
265: }
266:
267: /*
268: * (non-Javadoc)
269: *
270: * @see edu.umd.cs.findbugs.ba.AccessibleEntity#getPackageName()
271: */
272: @Override
273: public String getPackageName() {
274: String dottedClassName = getClassDescriptor()
275: .toDottedClassName();
276: int lastDot = dottedClassName.lastIndexOf('.');
277: if (lastDot < 0) {
278: return "";
279: } else {
280: return dottedClassName.substring(0, lastDot);
281: }
282: }
283:
284: public Collection<ClassDescriptor> getAnnotationDescriptors() {
285: return classAnnotations.keySet();
286: }
287:
288: public Collection<AnnotationValue> getAnnotations() {
289: return classAnnotations.values();
290: }
291:
292: public AnnotationValue getAnnotation(ClassDescriptor desc) {
293: return classAnnotations.get(desc);
294: }
295:
296: /**
297: * Destructively add an annotation to the object.
298: * In general, this is not a great idea, since it could cause
299: * the same class to appear to have different annotations
300: * at different times. However, this method is necessary
301: * for "built-in" annotations that FindBugs adds to
302: * system classes. As long as we add such annotations early
303: * enough that nobody will notice, we should be ok.
304: *
305: * @param annotationValue an AnnotationValue to add to the class
306: */
307: public void addAnnotation(AnnotationValue annotationValue) {
308: HashMap<ClassDescriptor, AnnotationValue> updatedMap = new HashMap<ClassDescriptor, AnnotationValue>(
309: classAnnotations);
310: updatedMap.put(annotationValue.getAnnotationClass(),
311: annotationValue);
312: classAnnotations = Util.immutableMap(updatedMap);
313: }
314:
315: public ElementType getElementType() {
316: if (getClassName().endsWith("package-info"))
317: return ElementType.PACKAGE;
318: else if (isAnnotation())
319: return ElementType.ANNOTATION_TYPE;
320: return ElementType.TYPE;
321:
322: }
323:
324: public @CheckForNull
325: String getSource() {
326: return source;
327: }
328:
329: public @CheckForNull
330: AnnotatedObject getContainingScope() {
331: try {
332: if (immediateEnclosingClass != null) {
333: return (ClassInfo) Global.getAnalysisCache()
334: .getClassAnalysis(XClass.class,
335: getImmediateEnclosingClass());
336: }
337: if (getClassName().endsWith("/package-info")
338: || getClassName().equals("package-info")) {
339: return null;
340: }
341: ClassDescriptor p = DescriptorFactory
342: .createClassDescriptorFromDottedClassName(getPackageName()
343: + "." + "package-info");
344: return (ClassInfo) Global.getAnalysisCache()
345: .getClassAnalysis(XClass.class, p);
346: } catch (CheckedAnalysisException e) {
347: return null;
348: }
349: }
350:
351: }
|