/*
* FindBugs - Find Bugs in Java programs
* Copyright (C) 2006, University of Maryland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.umd.cs.findbugs.ba;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.JavaClass;
import edu.umd.cs.findbugs.AnalysisCacheToRepositoryAdapter;
import edu.umd.cs.findbugs.ba.ch.Subtypes2;
import edu.umd.cs.findbugs.ba.jsr305.DirectlyRelevantTypeQualifiersDatabase;
import edu.umd.cs.findbugs.ba.npe.IsNullValueAnalysisFeatures;
import edu.umd.cs.findbugs.ba.npe.ParameterNullnessPropertyDatabase;
import edu.umd.cs.findbugs.ba.npe.ReturnValueNullnessPropertyDatabase;
import edu.umd.cs.findbugs.ba.npe.TypeQualifierNullnessAnnotationDatabase;
import edu.umd.cs.findbugs.ba.type.FieldStoreTypeDatabase;
import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
import edu.umd.cs.findbugs.classfile.ClassDescriptor;
import edu.umd.cs.findbugs.classfile.DescriptorFactory;
import edu.umd.cs.findbugs.classfile.Global;
import edu.umd.cs.findbugs.classfile.MethodDescriptor;
import edu.umd.cs.findbugs.classfile.analysis.ClassInfo;
import edu.umd.cs.findbugs.classfile.analysis.MethodInfo;
import edu.umd.cs.findbugs.internalAnnotations.DottedClassName;
import edu.umd.cs.findbugs.util.ClassName;
/**
* An AnalysisContext implementation that uses the IAnalysisCache. This class
* must only be used by FindBugs2, not the original FindBugs driver.
*
* @author David Hovemeyer
*/
public class AnalysisCacheToAnalysisContextAdapter extends AnalysisContext {
static class DelegatingRepositoryLookupFailureCallback implements RepositoryLookupFailureCallback {
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.classfile.IErrorLogger#logError(java.lang.String)
*/
public void logError(String message) {
Global.getAnalysisCache().getErrorLogger().logError(message);
}
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.classfile.IErrorLogger#logError(java.lang.String,
* java.lang.Throwable)
*/
public void logError(String message, Throwable e) {
Global.getAnalysisCache().getErrorLogger().logError(message, e);
}
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.classfile.IErrorLogger#reportMissingClass(java
* .lang.ClassNotFoundException)
*/
public void reportMissingClass(ClassNotFoundException ex) {
Global.getAnalysisCache().getErrorLogger().reportMissingClass(ex);
}
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.classfile.IErrorLogger#reportMissingClass(edu
* .umd.cs.findbugs.classfile.ClassDescriptor)
*/
public void reportMissingClass(ClassDescriptor classDescriptor) {
Global.getAnalysisCache().getErrorLogger().reportMissingClass(classDescriptor);
}
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.classfile.IErrorLogger#reportSkippedAnalysis(
* edu.umd.cs.findbugs.classfile.MethodDescriptor)
*/
public void reportSkippedAnalysis(MethodDescriptor method) {
Global.getAnalysisCache().getErrorLogger().reportSkippedAnalysis(method);
}
}
private RepositoryLookupFailureCallback lookupFailureCallback;
/**
* Constructor.
*/
public AnalysisCacheToAnalysisContextAdapter() {
this.lookupFailureCallback = new DelegatingRepositoryLookupFailureCallback();
}
// /* (non-Javadoc)
// * @see
// edu.umd.cs.findbugs.ba.AnalysisContext#addApplicationClassToRepository(org.apache.bcel.classfile.JavaClass)
// */
// @Override
// public void addApplicationClassToRepository(JavaClass appClass) {
// throw new UnsupportedOperationException();
// }
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.ba.AnalysisContext#addClasspathEntry(java.lang.String
* )
*/
@Override
public void addClasspathEntry(String url) throws IOException {
throw new UnsupportedOperationException();
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#clearClassContextCache()
*/
@Override
public void clearClassContextCache() {
throw new UnsupportedOperationException();
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#clearRepository()
*/
@Override
public void clearRepository() {
// Set the backing store for the BCEL Repository to
// be the AnalysisCache.
Repository.setRepository(new AnalysisCacheToRepositoryAdapter());
}
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.ba.AnalysisContext#getAnnotationRetentionDatabase()
*/
@Override
public AnnotationRetentionDatabase getAnnotationRetentionDatabase() {
return getDatabase(AnnotationRetentionDatabase.class);
}
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.ba.AnalysisContext#getCheckReturnAnnotationDatabase()
*/
@Override
public CheckReturnAnnotationDatabase getCheckReturnAnnotationDatabase() {
return getDatabase(CheckReturnAnnotationDatabase.class);
}
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.ba.AnalysisContext#getClassContext(org.apache.bcel
* .classfile.JavaClass)
*/
@Override
public ClassContext getClassContext(JavaClass javaClass) {
// This is a bit silly since we're doing an unnecessary
// ClassDescriptor->JavaClass lookup.
// However, we can be assured that it will succeed.
ClassDescriptor classDescriptor = DescriptorFactory.instance().getClassDescriptor(
ClassName.toSlashedClassName(javaClass.getClassName()));
try {
return Global.getAnalysisCache().getClassAnalysis(ClassContext.class, classDescriptor);
} catch (CheckedAnalysisException e) {
IllegalStateException ise = new IllegalStateException("Could not get ClassContext for JavaClass");
ise.initCause(e);
throw ise;
}
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#getClassContextStats()
*/
@Override
public String getClassContextStats() {
return "<unknown ClassContext stats>";
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#getFieldStoreTypeDatabase()
*/
@Override
public FieldStoreTypeDatabase getFieldStoreTypeDatabase() {
return getDatabase(FieldStoreTypeDatabase.class);
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#getJCIPAnnotationDatabase()
*/
@Override
public JCIPAnnotationDatabase getJCIPAnnotationDatabase() {
return getDatabase(JCIPAnnotationDatabase.class);
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#getLookupFailureCallback()
*/
@Override
public RepositoryLookupFailureCallback getLookupFailureCallback() {
return lookupFailureCallback;
}
private TypeQualifierNullnessAnnotationDatabase tqNullnessDatabase;
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.ba.AnalysisContext#getNullnessAnnotationDatabase()
*/
@Override
public INullnessAnnotationDatabase getNullnessAnnotationDatabase() {
if (IsNullValueAnalysisFeatures.USE_TYPE_QUALIFIERS) {
if (tqNullnessDatabase == null) {
tqNullnessDatabase = new TypeQualifierNullnessAnnotationDatabase();
}
return tqNullnessDatabase;
} else {
return getDatabase(NullnessAnnotationDatabase.class);
}
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#getSourceFinder()
*/
@Override
public SourceFinder getSourceFinder() {
return project.getSourceFinder();
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#getSourceInfoMap()
*/
@Override
public SourceInfoMap getSourceInfoMap() {
return getDatabase(SourceInfoMap.class);
}
// /* (non-Javadoc)
// * @see edu.umd.cs.findbugs.ba.AnalysisContext#getSubtypes()
// */
// @Override
// public Subtypes getSubtypes() {
// if (Subtypes.DO_NOT_USE) {
// throw new IllegalArgumentException();
// }
// return getDatabase(Subtypes.class);
// }
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.ba.AnalysisContext#getUnconditionalDerefParamDatabase
* ()
*/
@Override
public ParameterNullnessPropertyDatabase getUnconditionalDerefParamDatabase() {
return getDatabase(ParameterNullnessPropertyDatabase.class);
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#initDatabases()
*/
@Override
public void initDatabases() {
// Databases are created on-demand - don't need to explicitly create
// them
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#lookupClass(java.lang.String)
*/
@Override
public JavaClass lookupClass(@DottedClassName String className) throws ClassNotFoundException {
try {
if (className.length() == 0)
throw new IllegalArgumentException("Class name is empty");
if (!ClassName.isValidClassName(className)) {
throw new ClassNotFoundException("Invalid class name: " + className);
}
return Global.getAnalysisCache().getClassAnalysis(JavaClass.class,
DescriptorFactory.instance().getClassDescriptor(ClassName.toSlashedClassName(className)));
} catch (CheckedAnalysisException e) {
throw new ClassNotFoundException("Class not found: " + className, e);
}
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#getInnerClassAccessMap()
*/
@Override
public InnerClassAccessMap getInnerClassAccessMap() {
return getDatabase(InnerClassAccessMap.class);
}
/**
* Helper method to get a database without having to worry about a
* CheckedAnalysisException.
*
* @param cls
* Class of the database to get
* @return the database
*/
private <E> E getDatabase(Class<E> cls) {
return Global.getAnalysisCache().getDatabase(cls);
}
/**
* Set the collection of class descriptors identifying all application
* classes.
*
* @param appClassCollection
* List of ClassDescriptors identifying application classes
*/
public void setAppClassList(List<ClassDescriptor> appClassCollection) throws CheckedAnalysisException {
// FIXME: we really should drive the progress callback here
HashSet<ClassDescriptor> appSet = new HashSet<ClassDescriptor>(appClassCollection);
Collection<ClassDescriptor> allClassDescriptors = new ArrayList<ClassDescriptor>(DescriptorFactory.instance()
.getAllClassDescriptors());
for (ClassDescriptor appClass : allClassDescriptors)
try {
XClass xclass = currentXFactory().getXClass(appClass);
if (xclass == null)
continue;
// Add the application class to the database
if (appSet.contains(appClass))
getSubtypes2().addApplicationClass(xclass);
else if (xclass instanceof ClassInfo)
getSubtypes2().addClass(xclass);
} catch (Exception e) {
AnalysisContext.logError("Unable to get XClass for " + appClass, e);
}
if (Subtypes2.ENABLE_SUBTYPES2 && Subtypes2.DEBUG) {
System.out.println(getSubtypes2().getGraph().getNumVertices() + " vertices in inheritance graph");
}
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#updateDatabases(int)
*/
@Override
public void updateDatabases(int pass) {
if (pass == 0) {
getCheckReturnAnnotationDatabase().loadAuxiliaryAnnotations();
getNullnessAnnotationDatabase().loadAuxiliaryAnnotations();
}
}
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.ba.AnalysisContext#getReturnValueNullnessPropertyDatabase
* ()
*/
@Override
public ReturnValueNullnessPropertyDatabase getReturnValueNullnessPropertyDatabase() {
return getDatabase(ReturnValueNullnessPropertyDatabase.class);
}
// private Subtypes2 subtypes2;
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#getSubtypes2()
*/
@Override
public Subtypes2 getSubtypes2() {
return Global.getAnalysisCache().getDatabase(Subtypes2.class);
}
/*
* (non-Javadoc)
*
* @see edu.umd.cs.findbugs.ba.AnalysisContext#
* getDirectlyRelevantTypeQualifiersDatabase()
*/
@Override
public DirectlyRelevantTypeQualifiersDatabase getDirectlyRelevantTypeQualifiersDatabase() {
return Global.getAnalysisCache().getDatabase(DirectlyRelevantTypeQualifiersDatabase.class);
}
@Override
public @CheckForNull
XMethod getBridgeTo(MethodInfo m) {
return bridgeTo.get(m);
}
@Override
public @CheckForNull
XMethod getBridgeFrom(MethodInfo m) {
return bridgeFrom.get(m);
}
@Override
public void setBridgeMethod(MethodInfo from, MethodInfo to) {
bridgeTo.put(from, to);
bridgeFrom.put(to, from);
}
final Map<MethodInfo, MethodInfo> bridgeTo = new IdentityHashMap<MethodInfo, MethodInfo>();
final Map<MethodInfo, MethodInfo> bridgeFrom = new IdentityHashMap<MethodInfo, MethodInfo>();
}