001: /*
002: * FindBugs - Find Bugs in Java programs
003: * Copyright (C) 2003-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.ba;
021:
022: import java.io.IOException;
023:
024: import org.apache.bcel.Repository;
025: import org.apache.bcel.classfile.JavaClass;
026:
027: import edu.umd.cs.findbugs.annotations.NonNull;
028: import edu.umd.cs.findbugs.ba.ch.Subtypes;
029: import edu.umd.cs.findbugs.ba.ch.Subtypes2;
030: import edu.umd.cs.findbugs.ba.npe.ParameterNullnessPropertyDatabase;
031: import edu.umd.cs.findbugs.ba.npe.ReturnValueNullnessPropertyDatabase;
032: import edu.umd.cs.findbugs.ba.type.FieldStoreTypeDatabase;
033: import edu.umd.cs.findbugs.util.MapCache;
034:
035: /**
036: * Original implementation of AnalysisContext.
037: * (Eventual goal is a new implementation that uses
038: * the IAnalysisCache.)
039: *
040: * @author David Hovemeyer
041: */
042: @Deprecated
043: public class LegacyAnalysisContext extends AnalysisContext {
044:
045: private RepositoryLookupFailureCallback lookupFailureCallback;
046: private SourceFinder sourceFinder;
047: private MapCache<JavaClass, ClassContext> classContextCache;
048: private Subtypes subtypes;
049: private final SourceInfoMap sourceInfoMap;
050: private InnerClassAccessMap innerClassAccessMap;
051:
052: // Interprocedural fact databases
053: // private MayReturnNullPropertyDatabase mayReturnNullDatabase;
054: private FieldStoreTypeDatabase fieldStoreTypeDatabase;
055: private ParameterNullnessPropertyDatabase unconditionalDerefParamDatabase;
056: private ReturnValueNullnessPropertyDatabase returnValueNullnessDatabase;
057:
058: private NullnessAnnotationDatabase nullnessAnnotationDatabase; //= new NullnessAnnotationDatabase();
059:
060: @Override
061: public INullnessAnnotationDatabase getNullnessAnnotationDatabase() {
062: return nullnessAnnotationDatabase;
063: }
064:
065: private CheckReturnAnnotationDatabase checkReturnAnnotationDatabase;
066:
067: @Override
068: public CheckReturnAnnotationDatabase getCheckReturnAnnotationDatabase() {
069: return checkReturnAnnotationDatabase;
070: }
071:
072: private AnnotationRetentionDatabase annotationRetentionDatabase;
073:
074: @Override
075: public AnnotationRetentionDatabase getAnnotationRetentionDatabase() {
076: return annotationRetentionDatabase;
077: }
078:
079: private JCIPAnnotationDatabase jcipAnnotationDatabase;
080:
081: @Override
082: public JCIPAnnotationDatabase getJCIPAnnotationDatabase() {
083: return jcipAnnotationDatabase;
084: }
085:
086: /** save the original SyntheticRepository so we may
087: * obtain JavaClass objects which we can reuse.
088: * (A URLClassPathRepository gets closed after analysis.) */
089: private static final org.apache.bcel.util.Repository originalRepository = Repository
090: .getRepository(); // BCEL SyntheticRepository
091:
092: /**
093: * Default maximum number of ClassContext objects to cache.
094: * FIXME: need to evaluate this parameter. Need to keep stats about accesses.
095: */
096: private static final int DEFAULT_CACHE_SIZE = 6;
097:
098: /**
099: * Constructor.
100: *
101: * @param lookupFailureCallback the RepositoryLookupFailureCallback to use when
102: * reporting errors and class lookup failures
103: */
104: LegacyAnalysisContext(
105: RepositoryLookupFailureCallback lookupFailureCallback) {
106: this .lookupFailureCallback = lookupFailureCallback;
107: this .sourceFinder = new SourceFinder();
108: this .subtypes = new Subtypes();
109: this .sourceInfoMap = new SourceInfoMap();
110:
111: if (originalRepository instanceof URLClassPathRepository) {
112: getLookupFailureCallback()
113: .logError(
114: "originalRepository is a URLClassPathRepository, which may cause problems");
115: }
116:
117: //CheckReturnAnnotationDatabase may reportMissingClass, so do it after the currentAnalysisContext is set.
118: //Otherwise null ptr exceptions will happen.
119:
120: /*
121: checkReturnAnnotationDatabase = new CheckReturnAnnotationDatabase();
122:
123: To take the above comment one step further, there is a circular dependency here.
124: CheckReturnAnnotationDatabase calls Repository.lookupClass() when it is initializing,
125: so we don't want to instantiate it until after we have set up the repository.
126: Unfortunately, we can't set up the repository properly without an AnalysisContext,
127: and therefore not until after this AnalysisContext constructor returns.
128:
129: To handle this, we no longer instantiate the CheckReturnAnnotationDatabase here in
130: the constructor, but instead require that initDatabases() be called later on, after
131: the repository has been set up.
132: Yes this is ugly, but it will do for now. It's not worth the effort to redisign out
133: the circular dependency properly if we plan to move from BCEL to ASM soon anyway.
134: */
135: }
136:
137: @Override
138: public void initDatabases() {
139: checkReturnAnnotationDatabase = new CheckReturnAnnotationDatabase();
140: annotationRetentionDatabase = new AnnotationRetentionDatabase();
141: jcipAnnotationDatabase = new JCIPAnnotationDatabase();
142: nullnessAnnotationDatabase = new NullnessAnnotationDatabase();
143: }
144:
145: @Override
146: public void updateDatabases(int pass) {
147: if (pass == 0) {
148: checkReturnAnnotationDatabase.loadAuxiliaryAnnotations();
149: nullnessAnnotationDatabase.loadAuxiliaryAnnotations();
150: }
151: }
152:
153: @Override
154: public RepositoryLookupFailureCallback getLookupFailureCallback() {
155: return lookupFailureCallback;
156: }
157:
158: @Override
159: public SourceFinder getSourceFinder() {
160: return sourceFinder;
161: }
162:
163: @Override
164: public Subtypes getSubtypes() {
165: return subtypes;
166: }
167:
168: @Override
169: public void clearRepository() {
170: // If the old repository backing store is a URLClassPathRepository
171: // (which it certainly should be), destroy it.
172: // This will close all underlying resources (archive files, etc.)
173: org.apache.bcel.util.Repository repos = Repository
174: .getRepository();
175: if (repos instanceof URLClassPathRepository) {
176: ((URLClassPathRepository) repos).destroy();
177: }
178:
179: // Purge repository of previous contents
180: Repository.clearCache();
181:
182: // Clear any ClassContexts
183: clearClassContextCache();
184:
185: // Clear InnerClassAccessMap cache.
186: getInnerClassAccessMap().clearCache();
187:
188: // Create a URLClassPathRepository and make it current.
189: URLClassPathRepository repository = new URLClassPathRepository();
190: Repository.setRepository(repository);
191: }
192:
193: @Override
194: public void clearClassContextCache() {
195: if (classContextCache != null)
196: classContextCache.clear();
197: }
198:
199: @Override
200: public void addClasspathEntry(String url) throws IOException {
201: URLClassPathRepository repos = (URLClassPathRepository) Repository
202: .getRepository();
203: repos.addURL(url);
204: }
205:
206: @Override
207: public void addApplicationClassToRepository(JavaClass appClass) {
208: Repository.addClass(appClass);
209: subtypes.addApplicationClass(appClass);
210: }
211:
212: @Override
213: public JavaClass lookupClass(@NonNull
214: String className) throws ClassNotFoundException {
215: // TODO: eventually we should move to our own thread-safe repository implementation
216: if (className == null)
217: throw new IllegalArgumentException("className is null");
218: return Repository.lookupClass(className);
219: // note: previous line does not throw ClassNotFoundException, instead returns null
220: }
221:
222: /**
223: * Get the ClassContext for a class.
224: *
225: * @param javaClass the class
226: * @return the ClassContext for that class
227: */
228: int hits = 0;
229: int misses = 0;
230:
231: @Override
232: public ClassContext getClassContext(JavaClass javaClass) {
233: if (classContextCache == null) {
234: int cacheSize = getBoolProperty(AnalysisFeatures.CONSERVE_SPACE) ? 3
235: : DEFAULT_CACHE_SIZE;
236: classContextCache = new MapCache<JavaClass, ClassContext>(
237: cacheSize);
238: }
239: ClassContext classContext = classContextCache.get(javaClass);
240: if (classContext == null) {
241: classContext = new ClassContext(javaClass, this );
242: classContextCache.put(javaClass, classContext);
243: misses++;
244: } else
245: hits++;
246: return classContext;
247: }
248:
249: @Override
250: public SourceInfoMap getSourceInfoMap() {
251: return sourceInfoMap;
252: }
253:
254: @Override
255: public FieldStoreTypeDatabase getFieldStoreTypeDatabase() {
256: if (fieldStoreTypeDatabase == null) {
257: fieldStoreTypeDatabase = new FieldStoreTypeDatabase();
258: }
259: return fieldStoreTypeDatabase;
260: }
261:
262: @Override
263: public ParameterNullnessPropertyDatabase getUnconditionalDerefParamDatabase() {
264: if (unconditionalDerefParamDatabase == null) {
265: unconditionalDerefParamDatabase = new ParameterNullnessPropertyDatabase();
266: }
267: return unconditionalDerefParamDatabase;
268: }
269:
270: /* (non-Javadoc)
271: * @see edu.umd.cs.findbugs.ba.AnalysisContext#getInnerClassAccessMap()
272: */
273: @Override
274: public InnerClassAccessMap getInnerClassAccessMap() {
275: if (innerClassAccessMap == null) {
276: innerClassAccessMap = InnerClassAccessMap.create();
277: }
278: return innerClassAccessMap;
279: }
280:
281: /* (non-Javadoc)
282: * @see edu.umd.cs.findbugs.ba.AnalysisContext#getReturnValueNullnessPropertyDatabase()
283: */
284: @Override
285: public ReturnValueNullnessPropertyDatabase getReturnValueNullnessPropertyDatabase() {
286: if (returnValueNullnessDatabase == null) {
287: returnValueNullnessDatabase = new ReturnValueNullnessPropertyDatabase();
288: }
289: return returnValueNullnessDatabase;
290: }
291:
292: /* (non-Javadoc)
293: * @see edu.umd.cs.findbugs.ba.AnalysisContext#getSubtypes2()
294: */
295: @Override
296: public Subtypes2 getSubtypes2() {
297: throw new UnsupportedOperationException();
298: }
299:
300: /* (non-Javadoc)
301: * @see edu.umd.cs.findbugs.ba.AnalysisContext#getClassContextStats()
302: */
303: @Override
304: public String getClassContextStats() {
305: return "";
306: }
307:
308: }
|