All Downloads are FREE. Search and download functionalities are using the official Maven repository.

edu.umd.cs.findbugs.ba.AnalysisContext Maven / Gradle / Ivy

The newest version!
/*
 * Bytecode Analysis Framework
 * Copyright (C) 2003-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 static java.util.Objects.requireNonNull;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.BitSet;
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 javax.annotation.Nonnull;

import org.apache.bcel.Repository;
import org.apache.bcel.classfile.JavaClass;

import edu.umd.cs.findbugs.AbstractBugReporter;
import edu.umd.cs.findbugs.AnalysisCacheToRepositoryAdapter;
import edu.umd.cs.findbugs.AnalysisLocal;
import edu.umd.cs.findbugs.BugInstance.NoSuchBugPattern;
import edu.umd.cs.findbugs.Project;
import edu.umd.cs.findbugs.SourceLineAnnotation;
import edu.umd.cs.findbugs.SuppressionMatcher;
import edu.umd.cs.findbugs.SystemProperties;
import edu.umd.cs.findbugs.ba.AnalysisFeatures.AnalysisFeature;
import edu.umd.cs.findbugs.ba.ch.Subtypes2;
import edu.umd.cs.findbugs.ba.interproc.PropertyDatabase;
import edu.umd.cs.findbugs.ba.interproc.PropertyDatabaseFormatException;
import edu.umd.cs.findbugs.ba.jsr305.DirectlyRelevantTypeQualifiersDatabase;
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.FieldOrMethodDescriptor;
import edu.umd.cs.findbugs.classfile.Global;
import edu.umd.cs.findbugs.classfile.IAnalysisCache;
import edu.umd.cs.findbugs.classfile.MethodDescriptor;
import edu.umd.cs.findbugs.classfile.analysis.ClassData;
import edu.umd.cs.findbugs.classfile.analysis.ClassInfo;
import edu.umd.cs.findbugs.classfile.analysis.MethodInfo;
import edu.umd.cs.findbugs.detect.UnreadFields;
import edu.umd.cs.findbugs.detect.UnreadFieldsData;
import edu.umd.cs.findbugs.internalAnnotations.DottedClassName;
import edu.umd.cs.findbugs.io.IO;
import edu.umd.cs.findbugs.util.ClassName;
import net.jcip.annotations.NotThreadSafe;

/**
 * A context for analysis of a complete project. This serves as the repository
 * for whole-program information and data structures.
 *
 * 

* NOTE: this class is slated to become obsolete. New code should use the * IAnalysisCache object returned by Global.getAnalysisCache() to access all * analysis information (global databases, class and method analyses, etc.) *

* * @author David Hovemeyer * @see edu.umd.cs.findbugs.classfile.IAnalysisCache * @see edu.umd.cs.findbugs.classfile.Global */ @NotThreadSafe public class AnalysisContext implements AutoCloseable { public static final boolean DEBUG = SystemProperties.getBoolean("findbugs.analysiscontext.debug"); public static final boolean IGNORE_BUILTIN_MODELS = SystemProperties.getBoolean("findbugs.ignoreBuiltinModels"); public static final String DEFAULT_NONNULL_PARAM_DATABASE_FILENAME = "nonnullParam.db"; public static final String DEFAULT_CHECK_FOR_NULL_PARAM_DATABASE_FILENAME = "checkForNullParam.db"; public static final String DEFAULT_NULL_RETURN_VALUE_ANNOTATION_DATABASE = "nullReturn.db"; public static final String UNCONDITIONAL_DEREF_DB_FILENAME = "unconditionalDeref.db"; public static final String NONNULL_RETURN_DB_FILENAME = "nonnullReturn.db"; public static final String UNCONDITIONAL_DEREF_DB_RESOURCE = "jdkBaseUnconditionalDeref.db"; public static final String NONNULL_RETURN_DB_RESOURCE = "jdkBaseNonnullReturn.db"; public static final String DEFAULT_NULL_RETURN_VALUE_DB_FILENAME = "mayReturnNull.db"; private static InheritableThreadLocal currentAnalysisContext = new InheritableThreadLocal() { @Override public AnalysisContext initialValue() { // throw new // IllegalStateException("currentAnalysisContext should be set by AnalysisContext.setCurrentAnalysisContext"); return null; } }; private static AnalysisLocal currentXFactory = new AnalysisLocal() { @Override public XFactory initialValue() { throw new IllegalStateException("currentXFactory should be set by AnalysisContext.setCurrentAnalysisContext"); } }; /** * save the original SyntheticRepository so we may obtain JavaClass objects * which we can reuse. (A URLClassPathRepository gets closed after * analysis.) */ private static final org.apache.bcel.util.Repository originalRepository = Repository.getRepository(); // BCEL // SyntheticRepository /** * Default maximum number of ClassContext objects to cache. FIXME: need to * evaluate this parameter. Need to keep stats about accesses. */ // private static final int DEFAULT_CACHE_SIZE = 3; // Instance fields private BitSet boolPropertySet; private String databaseInputDir; private String databaseOutputDir; boolean missingClassWarningsSuppressed; private ClassSummary classSummary; private ClassDescriptor classBeingAnalyzed; private FieldSummary fieldSummary; private UnreadFields unreadFields; private TypeQualifierNullnessAnnotationDatabase tqNullnessDatabase; private final HashSet skippedDueToInvokeDynamic; private final Project project; private final EqualsKindSummary equalsKindSummary; private final UnreadFieldsData unreadFieldsData; private final SuppressionMatcher suppressionMatcher; protected final RepositoryLookupFailureCallback lookupFailureCallback; private final Map bridgeTo; private final Map bridgeFrom; public AnalysisContext(@Nonnull Project project) { requireNonNull(project); this.project = project; this.boolPropertySet = new BitSet(); this.lookupFailureCallback = new DelegatingRepositoryLookupFailureCallback(); skippedDueToInvokeDynamic = new HashSet<>(); equalsKindSummary = new EqualsKindSummary(); unreadFieldsData = new UnreadFieldsData(); suppressionMatcher = new SuppressionMatcher(); bridgeTo = new IdentityHashMap<>(); bridgeFrom = new IdentityHashMap<>(); } /** * Clear cache and reference in this instances. Cleared {@link AnalysisContext} instance should not be reused. */ private void clear() { boolPropertySet = null; databaseInputDir = null; databaseOutputDir = null; IO.close(project); } /** * Get the AnalysisContext associated with this thread */ static public AnalysisContext currentAnalysisContext() { return currentAnalysisContext.get(); } static public XFactory currentXFactory() { return currentXFactory.get(); } public ClassDescriptor getClassBeingAnalyzed() { return classBeingAnalyzed; } public void setClassBeingAnalyzed(@Nonnull ClassDescriptor classBeingAnalyzed) { this.classBeingAnalyzed = classBeingAnalyzed; } public void clearClassBeingAnalyzed() { this.classBeingAnalyzed = null; } public ClassSummary getClassSummary() { if (classSummary == null) { throw new IllegalStateException("ClassSummary not set"); } return classSummary; } public void setClassSummary(@Nonnull ClassSummary classSummary) { if (this.classSummary != null) { throw new IllegalStateException("ClassSummary already set"); } this.classSummary = classSummary; } public EqualsKindSummary getEqualsKindSummary() { return equalsKindSummary; } public FieldSummary getFieldSummary() { if (fieldSummary == null) { AnalysisContext.logError("Field Summary not set", new IllegalStateException()); fieldSummary = new FieldSummary(); } return fieldSummary; } public void setFieldSummary(@Nonnull FieldSummary fieldSummary) { if (this.fieldSummary != null) { AnalysisContext.logError("Field Summary already set", new IllegalStateException()); } this.fieldSummary = fieldSummary; } public @Nonnull UnreadFieldsData getUnreadFieldsData() { return unreadFieldsData; } public @Nonnull UnreadFields getUnreadFields() { if (!unreadFieldsAvailable()) { throw new IllegalStateException(); } return unreadFields; } public boolean unreadFieldsAvailable() { return unreadFields != null; } public void setUnreadFields(@Nonnull UnreadFields unreadFields) { if (this.unreadFields != null) { throw new IllegalStateException("UnreadFields detector already set"); } this.unreadFields = unreadFields; } private static boolean skipReportingMissingClass(@CheckForNull @DottedClassName String missing) { return missing == null || missing.length() == 0 || missing.charAt(0) == '[' || missing.endsWith("package-info"); } private static @CheckForNull RepositoryLookupFailureCallback getCurrentLookupFailureCallback() { AnalysisContext currentAnalysisContext2 = currentAnalysisContext(); if (currentAnalysisContext2 == null) { return null; } if (currentAnalysisContext2.missingClassWarningsSuppressed) { return null; } return currentAnalysisContext2.getLookupFailureCallback(); } /** * file a ClassNotFoundException with the lookupFailureCallback * * @see #getLookupFailureCallback() */ static public void reportMissingClass(ClassNotFoundException e) { requireNonNull(e, "argument is null"); String missing = AbstractBugReporter.getMissingClassName(e); if (skipReportingMissingClass(missing)) { return; } if (!analyzingApplicationClass()) { return; } RepositoryLookupFailureCallback lookupFailureCallback = getCurrentLookupFailureCallback(); if (lookupFailureCallback != null) { lookupFailureCallback.reportMissingClass(e); } } static public void reportMissingClass(edu.umd.cs.findbugs.ba.MissingClassException e) { requireNonNull(e, "argument is null"); reportMissingClass(e.getClassDescriptor()); } static public boolean analyzingApplicationClass() { AnalysisContext context = AnalysisContext.currentAnalysisContext(); if (context == null) { return false; } ClassDescriptor clazz = context.getClassBeingAnalyzed(); if (clazz == null) { return false; } return context.isApplicationClass(clazz); } static public void reportMissingClass(edu.umd.cs.findbugs.classfile.MissingClassException e) { requireNonNull(e, "argument is null"); reportMissingClass(e.getClassDescriptor()); } static public void reportMissingClass(ClassDescriptor c) { requireNonNull(c, "argument is null"); if (!analyzingApplicationClass()) { return; } String missing = c.getDottedClassName(); if (missing.length() == 1) { System.out.println(c); } if (skipReportingMissingClass(missing)) { return; } RepositoryLookupFailureCallback lookupFailureCallback = getCurrentLookupFailureCallback(); if (lookupFailureCallback != null) { lookupFailureCallback.reportMissingClass(c); } } /** * Report an error */ static public void logError(String msg, Exception e) { AnalysisContext currentAnalysisContext2 = currentAnalysisContext(); if (currentAnalysisContext2 == null) { if (e instanceof NoSuchBugPattern) { return; } /* if (false && SystemProperties.ASSERTIONS_ENABLED) { AssertionError e2 = new AssertionError("Exception logged with no analysis context"); e2.initCause(e); throw e2; } */ e.printStackTrace(System.err); return; } if (e instanceof MissingClassException) { reportMissingClass(((MissingClassException) e).getClassNotFoundException()); return; } if (e instanceof edu.umd.cs.findbugs.classfile.MissingClassException) { reportMissingClass(((edu.umd.cs.findbugs.classfile.MissingClassException) e).toClassNotFoundException()); return; } RepositoryLookupFailureCallback lookupFailureCallback = currentAnalysisContext2.getLookupFailureCallback(); if (lookupFailureCallback != null) { lookupFailureCallback.logError(msg, e); } } /** * Report an error */ static public void logError(String msg) { AnalysisContext currentAnalysisContext2 = currentAnalysisContext(); if (currentAnalysisContext2 == null) { return; } currentAnalysisContext2.logAnError(msg); } public void logAnError(String msg) { RepositoryLookupFailureCallback lookupFailureCallback = getLookupFailureCallback(); if (lookupFailureCallback != null) { lookupFailureCallback.logError(msg); } } public void analysisSkippedDueToInvokeDynamic(XMethod m) { if (!m.usesInvokeDynamic()) { throw new IllegalArgumentException(); } if (skippedDueToInvokeDynamic.add(m.getMethodDescriptor())) { logAnError(m + " skipped due to invoke_dynamic"); } } public boolean setMissingClassWarningsSuppressed(boolean value) { boolean oldValue = missingClassWarningsSuppressed; missingClassWarningsSuppressed = value; return oldValue; } // /** // * Add an application class to the repository. // * // * @param appClass the application class // */ // public abstract void addApplicationClassToRepository(JavaClass appClass); /** * Return whether or not the given class is an application class. * * @param cls * the class to lookup * @return true if the class is an application class, false if not an * application class or if the class cannot be located */ public boolean isApplicationClass(JavaClass cls) { // return getSubtypes().isApplicationClass(cls); return getSubtypes2().isApplicationClass(DescriptorFactory.createClassDescriptor(cls)); } /** * Return whether or not the given class is an application class. * * @param className * name of a class * @return true if the class is an application class, false if not an * application class or if the class cannot be located */ public boolean isApplicationClass(@DottedClassName String className) { // try { // JavaClass javaClass = lookupClass(className); // return isApplicationClass(javaClass); // } catch (ClassNotFoundException e) { // AnalysisContext.reportMissingClass(e); // return false; // } ClassDescriptor classDesc = DescriptorFactory.createClassDescriptorFromDottedClassName(className); return getSubtypes2().isApplicationClass(classDesc); } public boolean isApplicationClass(ClassDescriptor desc) { return getSubtypes2().isApplicationClass(desc); } public int getClassSize(ClassDescriptor desc) { IAnalysisCache analysisCache = Global.getAnalysisCache(); try { /* ClassContext classContext =*/ analysisCache.getClassAnalysis(ClassContext.class, desc); ClassData classData = analysisCache.getClassAnalysis(ClassData.class, desc); return classData.getData().length; } catch (RuntimeException e) { AnalysisContext.logError("Error getting class data for " + desc, e); return 10000; } catch (CheckedAnalysisException e) { AnalysisContext.logError("Could not get class context for " + desc, e); return 10000; } } public boolean isTooBig(ClassDescriptor desc) { IAnalysisCache analysisCache = Global.getAnalysisCache(); try { ClassContext classContext = analysisCache.getClassAnalysis(ClassContext.class, desc); ClassData classData = analysisCache.getClassAnalysis(ClassData.class, desc); if (classData.getData().length > 1000000) { return true; } try { JavaClass javaClass = classContext.getJavaClass(); if (javaClass.getMethods().length > 1000) { return true; } } catch (RuntimeException e) { AnalysisContext.logError("Error parsing class " + desc + " from " + classData.getCodeBaseEntry().getCodeBase(), e); return true; } } catch (RuntimeException e) { AnalysisContext.logError("Error getting class data for " + desc, e); return true; } catch (CheckedAnalysisException e) { AnalysisContext.logError("Could not get class context for " + desc, e); return true; } return false; } /** * Lookup a class. * Use this method instead of Repository.lookupClass(). * * @param classDescriptor * descriptor specifying the class to look up * @return the class * @throws ClassNotFoundException * if the class can't be found */ public JavaClass lookupClass(@Nonnull ClassDescriptor classDescriptor) throws ClassNotFoundException { return lookupClass(classDescriptor.toDottedClassName()); } /** * This is equivalent to Repository.lookupClass() or this.lookupClass(), * except it uses the original Repository instead of the current one. * * This can be important because URLClassPathRepository objects are closed * after an analysis, so JavaClass objects obtained from them are no good on * subsequent runs. * * @param className * the name of the class * @return the JavaClass representing the class * @throws ClassNotFoundException */ public static JavaClass lookupSystemClass(@Nonnull String className) throws ClassNotFoundException { // TODO: eventually we should move to our own thread-safe repository // implementation requireNonNull(className, "className is null"); if (originalRepository == null) { throw new IllegalStateException("originalRepository is null"); } JavaClass clazz = originalRepository.findClass(className); if (clazz != null) { return clazz; } // XXX workaround for system classes missing on Java 9 // Not sure if we BCEL update, but this seem to work in simple cases return AnalysisContext.currentAnalysisContext().lookupClass(className); } /** * Lookup a class's source file * * @param dottedClassName * the name of the class * @return the source file for the class, or * {@link SourceLineAnnotation#UNKNOWN_SOURCE_FILE} if unable to * determine */ public final String lookupSourceFile(@Nonnull @DottedClassName String dottedClassName) { requireNonNull(dottedClassName, "className is null"); try { XClass xClass = Global.getAnalysisCache().getClassAnalysis(XClass.class, DescriptorFactory.createClassDescriptorFromDottedClassName(dottedClassName)); String name = xClass.getSource(); if (name == null) { return SourceLineAnnotation.UNKNOWN_SOURCE_FILE; } return name; } catch (CheckedAnalysisException e) { return SourceLineAnnotation.UNKNOWN_SOURCE_FILE; } } /** * If possible, load interprocedural property databases. */ public final void loadInterproceduralDatabases() { loadPropertyDatabase(getFieldStoreTypeDatabase(), FieldStoreTypeDatabase.DEFAULT_FILENAME, "field store type database"); loadPropertyDatabase(getUnconditionalDerefParamDatabase(), UNCONDITIONAL_DEREF_DB_FILENAME, "unconditional param deref database"); loadPropertyDatabase(getReturnValueNullnessPropertyDatabase(), NONNULL_RETURN_DB_FILENAME, "nonnull return db database"); } /** * If possible, load default (built-in) interprocedural property databases. * These are the databases for things like Java core APIs that unconditional * dereference parameters. */ public final void loadDefaultInterproceduralDatabases() { if (IGNORE_BUILTIN_MODELS) { return; } loadPropertyDatabaseFromResource(getUnconditionalDerefParamDatabase(), UNCONDITIONAL_DEREF_DB_RESOURCE, "unconditional param deref database"); loadPropertyDatabaseFromResource(getReturnValueNullnessPropertyDatabase(), NONNULL_RETURN_DB_RESOURCE, "nonnull return db database"); } /** * Set a boolean property. * * @param prop * the property to set * @param value * the value of the property */ public final void setBoolProperty(@AnalysisFeature int prop, boolean value) { boolPropertySet.set(prop, value); } /** * Get a boolean property. * * @param prop * the property * @return value of the property; defaults to false if the property has not * had a value assigned explicitly */ public final boolean getBoolProperty(@AnalysisFeature int prop) { return boolPropertySet.get(prop); } /** * Set the interprocedural database input directory. * * @param databaseInputDir * the interprocedural database input directory */ public final void setDatabaseInputDir(String databaseInputDir) { if (DEBUG) { System.out.println("Setting database input directory: " + databaseInputDir); } this.databaseInputDir = databaseInputDir; } /** * Get the interprocedural database input directory. * * @return the interprocedural database input directory */ public final String getDatabaseInputDir() { return databaseInputDir; } /** * Set the interprocedural database output directory. * * @param databaseOutputDir * the interprocedural database output directory */ public final void setDatabaseOutputDir(String databaseOutputDir) { if (DEBUG) { System.out.println("Setting database output directory: " + databaseOutputDir); } this.databaseOutputDir = databaseOutputDir; } /** * Get the interprocedural database output directory. * * @return the interprocedural database output directory */ public final String getDatabaseOutputDir() { return databaseOutputDir; } /** * Load an interprocedural property database. * * @param * actual type of the database * @param * type of key (e.g., method or field) * @param * type of properties stored in the database * @param database * the empty database object * @param fileName * file to load database from * @param description * description of the database (for diagnostics) * @return the database object, or null if the database couldn't be loaded */ public , KeyType extends FieldOrMethodDescriptor, Property> DatabaseType loadPropertyDatabase( DatabaseType database, String fileName, String description) { try { File dbFile = new File(getDatabaseInputDir(), fileName); if (DEBUG) { System.out.println("Loading " + description + " from " + dbFile.getPath() + "..."); } database.readFromFile(dbFile.getPath()); return database; } catch (IOException e) { getLookupFailureCallback().logError("Error loading " + description, e); } catch (PropertyDatabaseFormatException e) { getLookupFailureCallback().logError("Invalid " + description, e); } return null; } /** * Load an interprocedural property database. * * @param * actual type of the database * @param * type of key (e.g., method or field) * @param * type of properties stored in the database * @param database * the empty database object * @param resourceName * name of resource to load the database from * @param description * description of the database (for diagnostics) * @return the database object, or null if the database couldn't be loaded */ public , KeyType extends FieldOrMethodDescriptor, Property> DatabaseType loadPropertyDatabaseFromResource( DatabaseType database, String resourceName, String description) { try { if (DEBUG) { System.out.println("Loading default " + description + " from " + resourceName + " @ " + database.getClass().getResource(resourceName) + " ... "); } try (InputStream in = database.getClass().getResourceAsStream(resourceName)) { if (in == null) { AnalysisContext.logError("Unable to load " + description + " from resource " + resourceName); } else { database.read(in); } } return database; } catch (IOException e) { getLookupFailureCallback().logError("Error loading " + description, e); } catch (PropertyDatabaseFormatException e) { getLookupFailureCallback().logError("Invalid " + description, e); } return null; } /** * Write an interprocedural property database. * * @param * actual type of the database * @param * type of key (e.g., method or field) * @param * type of properties stored in the database * @param database * the database * @param fileName * name of database file * @param description * description of the database */ public , KeyType extends FieldOrMethodDescriptor, Property> void storePropertyDatabase( DatabaseType database, String fileName, String description) { try { File dbFile = new File(getDatabaseOutputDir(), fileName); if (DEBUG) { System.out.println("Writing " + description + " to " + dbFile.getPath() + "..."); } database.writeToFile(dbFile.getPath()); } catch (IOException e) { getLookupFailureCallback().logError("Error writing " + description, e); } } /** * Set the current analysis context for this thread. * * @param analysisContext * the current analysis context for this thread */ public static void setCurrentAnalysisContext(AnalysisContext analysisContext) { currentAnalysisContext.set(analysisContext); if (Global.getAnalysisCache() != null) { currentXFactory.set(new XFactory()); } } public static void removeCurrentAnalysisContext() { AnalysisContext context = currentAnalysisContext(); if (context != null) { context.clear(); } currentAnalysisContext.remove(); } /** * Get Collection of all XClass objects seen so far. * * @return Collection of all XClass objects seen so far */ public Collection getXClassCollection() { return getSubtypes2().getXClassCollection(); } public SuppressionMatcher getSuppressionMatcher() { return suppressionMatcher; } /** * Add an entry to the Repository's classpath. * * @param url * the classpath entry URL * @throws IOException */ public void addClasspathEntry(String url) throws IOException { throw new UnsupportedOperationException(); } /** * Clear the ClassContext cache. This should be done between analysis * passes. */ public void clearClassContextCache() { throw new UnsupportedOperationException(); } /** * Clear the BCEL Repository in preparation for analysis. */ public void clearRepository() { // Set the backing store for the BCEL Repository to // be the AnalysisCache. Repository.setRepository(new AnalysisCacheToRepositoryAdapter()); } public AnnotationRetentionDatabase getAnnotationRetentionDatabase() { return getDatabase(AnnotationRetentionDatabase.class); } public CheckReturnAnnotationDatabase getCheckReturnAnnotationDatabase() { return getDatabase(CheckReturnAnnotationDatabase.class); } /** * Get the ClassContext for a class. * * @param javaClass * the class * @return the ClassContext for that class */ 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; } } /** * Get stats about hit rate for ClassContext cache. * * @return stats about hit rate for ClassContext cache */ public String getClassContextStats() { return ""; } /** * Get the property database recording the types of values stored into * fields. * * @return the database, or null if there is no database available */ public FieldStoreTypeDatabase getFieldStoreTypeDatabase() { return getDatabase(FieldStoreTypeDatabase.class); } public JCIPAnnotationDatabase getJCIPAnnotationDatabase() { return getDatabase(JCIPAnnotationDatabase.class); } /** * Get the lookup failure callback. */ public RepositoryLookupFailureCallback getLookupFailureCallback() { return lookupFailureCallback; } /** * Get the SourceFinder, for finding source files. */ public SourceFinder getSourceFinder() { return project.getSourceFinder(); } /** * Get the SourceInfoMap. */ public SourceInfoMap getSourceInfoMap() { return getDatabase(SourceInfoMap.class); } /** * Get the property database recording which methods unconditionally * dereference parameters. * * @return the database, or null if there is no database available */ public ParameterNullnessPropertyDatabase getUnconditionalDerefParamDatabase() { return getDatabase(ParameterNullnessPropertyDatabase.class); } /** * Instantiate the CheckReturnAnnotationDatabase. Do this after the * repository has been set up. */ public void initDatabases() { // Databases are created on-demand - don't need to explicitly create // them } /** * Lookup a class. * Use this method instead of Repository.lookupClass(). * * @param className * the name of the class * @return the JavaClass representing the class * @throws ClassNotFoundException * (but not really) */ public JavaClass lookupClass(@Nonnull @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); } } public InnerClassAccessMap getInnerClassAccessMap() { return getDatabase(InnerClassAccessMap.class); } public void setAppClassList(List appClassCollection) { // FIXME: we really should drive the progress callback here HashSet appSet = new HashSet<>(appClassCollection); Collection allClassDescriptors = new ArrayList<>(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 (true && Subtypes2.DEBUG) { System.out.println(getSubtypes2().getGraph().getNumVertices() + " vertices in inheritance graph"); } } /** * After a pass has been completed, allow the analysis context to update * information. * * @param pass * -- the first pass is pass 0 */ public void updateDatabases(int pass) { if (pass == 0) { getCheckReturnAnnotationDatabase().loadAuxiliaryAnnotations(); getNullnessAnnotationDatabase().loadAuxiliaryAnnotations(); } } /** * Get the property database recording which methods always return nonnull * values * * @return the database, or null if there is no database available */ public ReturnValueNullnessPropertyDatabase getReturnValueNullnessPropertyDatabase() { return getDatabase(ReturnValueNullnessPropertyDatabase.class); } /** * Get the Subtypes2 inheritance hierarchy database. */ public Subtypes2 getSubtypes2() { return Global.getAnalysisCache().getDatabase(Subtypes2.class); } public DirectlyRelevantTypeQualifiersDatabase getDirectlyRelevantTypeQualifiersDatabase() { return Global.getAnalysisCache().getDatabase(DirectlyRelevantTypeQualifiersDatabase.class); } @CheckForNull public XMethod getBridgeTo(MethodInfo m) { return bridgeTo.get(m); } @CheckForNull public XMethod getBridgeFrom(MethodInfo m) { return bridgeFrom.get(m); } public void setBridgeMethod(MethodInfo from, MethodInfo to) { bridgeTo.put(from, to); bridgeFrom.put(to, from); } public TypeQualifierNullnessAnnotationDatabase getNullnessAnnotationDatabase() { if (tqNullnessDatabase == null) { tqNullnessDatabase = new TypeQualifierNullnessAnnotationDatabase(); } return tqNullnessDatabase; } protected E getDatabase(Class cls) { return Global.getAnalysisCache().getDatabase(cls); } static class DelegatingRepositoryLookupFailureCallback implements RepositoryLookupFailureCallback { @Override public void logError(String message) { Global.getAnalysisCache().getErrorLogger().logError(message); } @Override public void logError(String message, Throwable e) { Global.getAnalysisCache().getErrorLogger().logError(message, e); } @Override public void reportMissingClass(ClassNotFoundException ex) { Global.getAnalysisCache().getErrorLogger().reportMissingClass(ex); } @Override public void reportMissingClass(ClassDescriptor classDescriptor) { Global.getAnalysisCache().getErrorLogger().reportMissingClass(classDescriptor); } @Override public void reportSkippedAnalysis(MethodDescriptor method) { Global.getAnalysisCache().getErrorLogger().reportSkippedAnalysis(method); } } @Override public void close() { clear(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy