1 19 20 package edu.umd.cs.findbugs.ba; 21 22 import java.io.File ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.util.BitSet ; 26 import java.util.Collections ; 27 import java.util.HashMap ; 28 import java.util.List ; 29 import java.util.Map ; 30 31 import net.jcip.annotations.NotThreadSafe; 32 33 import org.apache.bcel.Repository; 34 import org.apache.bcel.classfile.JavaClass; 35 36 import edu.umd.cs.findbugs.SourceLineAnnotation; 37 import edu.umd.cs.findbugs.SystemProperties; 38 import edu.umd.cs.findbugs.annotations.NonNull; 39 import edu.umd.cs.findbugs.ba.ch.Subtypes; 40 import edu.umd.cs.findbugs.ba.interproc.PropertyDatabase; 41 import edu.umd.cs.findbugs.ba.interproc.PropertyDatabaseFormatException; 42 import edu.umd.cs.findbugs.ba.npe.ParameterNullnessPropertyDatabase; 43 import edu.umd.cs.findbugs.ba.type.FieldStoreTypeDatabase; 44 import edu.umd.cs.findbugs.classfile.ClassDescriptor; 45 import edu.umd.cs.findbugs.classfile.IAnalysisCache; 46 import edu.umd.cs.findbugs.detect.NoteAnnotationRetention; 47 import edu.umd.cs.findbugs.detect.UnreadFields; 48 import edu.umd.cs.findbugs.util.ClassName; 49 import edu.umd.cs.findbugs.util.MapCache; 50 51 52 68 @NotThreadSafe 69 public abstract class AnalysisContext { 70 public static final boolean DEBUG = SystemProperties.getBoolean("findbugs.analysiscontext.debug"); 71 72 public static final String DEFAULT_NONNULL_PARAM_DATABASE_FILENAME = "nonnullParam.db"; 73 public static final String DEFAULT_CHECK_FOR_NULL_PARAM_DATABASE_FILENAME = "checkForNullParam.db"; 74 public static final String DEFAULT_NULL_RETURN_VALUE_ANNOTATION_DATABASE = "nonnullReturn.db"; 75 public static final String UNCONDITIONAL_DEREF_DB_FILENAME = "unconditionalDeref.db"; 76 public static final String UNCONDITIONAL_DEREF_DB_RESOURCE = "jdkBaseUnconditionalDeref.db"; 77 public static final String DEFAULT_NULL_RETURN_VALUE_DB_FILENAME = "mayReturnNull.db"; 78 79 private static InheritableThreadLocal <AnalysisContext> currentAnalysisContext 80 = new InheritableThreadLocal <AnalysisContext>(); 81 82 private static InheritableThreadLocal <XFactory> currentXFactory 83 = new InheritableThreadLocal <XFactory>() { 84 @Override 85 public XFactory initialValue() { 86 return new XFactory(); 87 } 88 }; 89 90 public abstract NullnessAnnotationDatabase getNullnessAnnotationDatabase(); 91 public abstract CheckReturnAnnotationDatabase getCheckReturnAnnotationDatabase(); 92 public abstract AnnotationRetentionDatabase getAnnotationRetentionDatabase(); 93 public abstract JCIPAnnotationDatabase getJCIPAnnotationDatabase(); 94 95 98 private static final org.apache.bcel.util.Repository originalRepository = 99 Repository.getRepository(); 101 105 private static final int DEFAULT_CACHE_SIZE = 3; 106 107 108 private BitSet boolPropertySet; 110 private Map <Object ,Object > analysisLocals; 111 private String databaseInputDir; 112 private String databaseOutputDir; 113 114 protected AnalysisContext() { 115 this.boolPropertySet = new BitSet (); 116 this.analysisLocals = Collections.synchronizedMap(new HashMap <Object ,Object >()); 117 } 118 119 126 public static AnalysisContext create(RepositoryLookupFailureCallback lookupFailureCallback) { 127 AnalysisContext analysisContext = new LegacyAnalysisContext(lookupFailureCallback); 128 setCurrentAnalysisContext(analysisContext); 129 return analysisContext; 130 } 131 132 135 public abstract void initDatabases(); 136 137 138 142 public abstract void updateDatabases(int pass); 143 146 static public AnalysisContext currentAnalysisContext() { 147 return currentAnalysisContext.get(); 148 } 149 150 static public XFactory currentXFactory() { 151 return currentXFactory.get(); 152 } 153 154 UnreadFields unreadFields; 155 public UnreadFields getUnreadFields() { 156 if (unreadFields == null) throw new IllegalStateException ("UnreadFields detector not set"); 157 return unreadFields; 158 } 159 public void setUnreadFields(@NonNull UnreadFields unreadFields) { 160 if (this.unreadFields != null) throw new IllegalStateException ("UnreadFields detector already set"); 161 this.unreadFields = unreadFields; 162 } 163 167 static public void reportMissingClass(ClassNotFoundException e) { 168 AnalysisContext currentAnalysisContext2 = currentAnalysisContext(); 169 if (currentAnalysisContext2 == null) return; 170 if (currentAnalysisContext2.missingClassWarningsSuppressed) return; 171 RepositoryLookupFailureCallback lookupFailureCallback = currentAnalysisContext2.getLookupFailureCallback(); 172 if (lookupFailureCallback != null) lookupFailureCallback.reportMissingClass(e); 173 } 174 175 178 static public void logError(String msg, Exception e) { 179 AnalysisContext currentAnalysisContext2 = currentAnalysisContext(); 180 if (currentAnalysisContext2 == null) return; 181 RepositoryLookupFailureCallback lookupFailureCallback = currentAnalysisContext2.getLookupFailureCallback(); 182 if (lookupFailureCallback != null) lookupFailureCallback.logError(msg, e); 183 } 184 187 static public void logError(String msg) { 188 AnalysisContext currentAnalysisContext2 = currentAnalysisContext(); 189 if (currentAnalysisContext2 == null) return; 190 RepositoryLookupFailureCallback lookupFailureCallback = currentAnalysisContext2.getLookupFailureCallback(); 191 if (lookupFailureCallback != null) lookupFailureCallback.logError(msg); 192 } 193 194 boolean missingClassWarningsSuppressed = false; 195 196 public boolean setMissingClassWarningsSuppressed(boolean value) { 197 boolean oldValue = missingClassWarningsSuppressed; 198 missingClassWarningsSuppressed = value; 199 return oldValue; 200 } 201 204 public abstract RepositoryLookupFailureCallback getLookupFailureCallback(); 205 206 209 public final void setSourcePath(List <String > sourcePath) { 210 getSourceFinder().setSourceBaseList(sourcePath); 211 } 212 213 216 public abstract SourceFinder getSourceFinder(); 217 218 223 public abstract Subtypes getSubtypes(); 224 225 228 public abstract void clearRepository(); 229 230 234 public abstract void clearClassContextCache(); 235 236 242 public abstract void addClasspathEntry(String url) throws IOException ; 243 244 249 public abstract void addApplicationClassToRepository(JavaClass appClass); 250 251 258 public boolean isApplicationClass(JavaClass cls) { 259 return getSubtypes().isApplicationClass(cls); 260 } 261 262 269 public boolean isApplicationClass(String className) { 270 try { 271 JavaClass javaClass = lookupClass(className); 272 return isApplicationClass(javaClass); 273 } catch (ClassNotFoundException e) { 274 AnalysisContext.reportMissingClass(e); 275 return false; 276 } 277 } 278 279 287 public abstract JavaClass lookupClass(@NonNull String className) throws ClassNotFoundException ; 288 289 297 public JavaClass lookupClass(@NonNull ClassDescriptor classDescriptor) throws ClassNotFoundException { 298 return lookupClass(classDescriptor.toDottedClassName()); 299 } 300 301 313 public static JavaClass lookupSystemClass(@NonNull String className) throws ClassNotFoundException { 314 if (className == null) throw new IllegalArgumentException ("className is null"); 316 if (originalRepository == null) throw new IllegalStateException ("originalRepository is null"); 317 318 JavaClass clazz = originalRepository.findClass(className); 319 return (clazz==null ? originalRepository.loadClass(className) : clazz); 320 } 321 322 328 public final String lookupSourceFile(@NonNull String className) { 329 if (className == null) 330 throw new IllegalArgumentException ("className is null"); 331 try { 332 JavaClass jc = this.lookupClass(className); 333 String name = jc.getSourceFileName(); 334 if (name == null) { 335 System.out.println("No sourcefile for " + className); 336 return SourceLineAnnotation.UNKNOWN_SOURCE_FILE; 337 } 338 return name; 339 } catch (ClassNotFoundException cnfe) { 340 return SourceLineAnnotation.UNKNOWN_SOURCE_FILE; 341 } 342 } 343 344 350 public abstract ClassContext getClassContext(JavaClass javaClass); 351 352 357 public abstract String getClassContextStats(); 358 359 362 public final void loadInterproceduralDatabases() { 363 loadPropertyDatabase( 364 getFieldStoreTypeDatabase(), 365 FieldStoreTypeDatabase.DEFAULT_FILENAME, 366 "field store type database"); 367 loadPropertyDatabase( 368 getUnconditionalDerefParamDatabase(), 369 UNCONDITIONAL_DEREF_DB_FILENAME, 370 "unconditional param deref database"); 371 } 372 373 378 public final void loadDefaultInterproceduralDatabases() { 379 loadPropertyDatabaseFromResource( 380 getUnconditionalDerefParamDatabase(), 381 UNCONDITIONAL_DEREF_DB_RESOURCE, 382 "unconditional param deref database"); 383 } 384 385 391 public final void setBoolProperty(int prop, boolean value) { 392 boolPropertySet.set(prop, value); 393 } 394 395 402 public final boolean getBoolProperty(int prop) { 403 return boolPropertySet.get(prop); 404 } 405 406 409 public abstract SourceInfoMap getSourceInfoMap(); 410 411 416 public final void setDatabaseInputDir(String databaseInputDir) { 417 if (DEBUG) System.out.println("Setting database input directory: " + databaseInputDir); 418 this.databaseInputDir = databaseInputDir; 419 } 420 421 426 public final String getDatabaseInputDir() { 427 return databaseInputDir; 428 } 429 430 435 public final void setDatabaseOutputDir(String databaseOutputDir) { 436 if (DEBUG) System.out.println("Setting database output directory: " + databaseOutputDir); 437 this.databaseOutputDir = databaseOutputDir; 438 } 439 440 445 public final String getDatabaseOutputDir() { 446 return databaseOutputDir; 447 } 448 449 455 public abstract FieldStoreTypeDatabase getFieldStoreTypeDatabase(); 456 457 463 public abstract ParameterNullnessPropertyDatabase getUnconditionalDerefParamDatabase(); 464 465 476 public< 477 DatabaseType extends PropertyDatabase<KeyType,Property>, 478 KeyType extends ClassMember, 479 Property 480 > DatabaseType loadPropertyDatabase( 481 DatabaseType database, 482 String fileName, 483 String description) { 484 try { 485 File dbFile = new File (getDatabaseInputDir(), fileName); 486 if (DEBUG) System.out.println("Loading " + description + " from " + dbFile.getPath() + "..."); 487 488 database.readFromFile(dbFile.getPath()); 489 return database; 490 } catch (IOException e) { 491 getLookupFailureCallback().logError("Error loading " + description, e); 492 } catch (PropertyDatabaseFormatException e) { 493 getLookupFailureCallback().logError("Invalid " + description, e); 494 } 495 496 return null; 497 } 498 499 510 public< 511 DatabaseType extends PropertyDatabase<KeyType,Property>, 512 KeyType extends ClassMember, 513 Property 514 > DatabaseType loadPropertyDatabaseFromResource( 515 DatabaseType database, 516 String resourceName, 517 String description) { 518 try { 519 if (DEBUG) System.out.println("Loading default " + description + " from " 520 + resourceName + " @ " 521 + PropertyDatabase.class.getResource(resourceName) + " ... "); 522 InputStream in = PropertyDatabase.class.getResourceAsStream(resourceName); 523 database.read(in); 524 return database; 525 } catch (IOException e) { 526 getLookupFailureCallback().logError("Error loading " + description, e); 527 } catch (PropertyDatabaseFormatException e) { 528 getLookupFailureCallback().logError("Invalid " + description, e); 529 } 530 531 return null; 532 } 533 534 535 545 public< 546 DatabaseType extends PropertyDatabase<KeyType,Property>, 547 KeyType extends ClassMember, 548 Property 549 > void storePropertyDatabase(DatabaseType database, String fileName, String description) { 550 551 try { 552 File dbFile = new File (getDatabaseOutputDir(), fileName); 553 if (DEBUG) System.out.println("Writing " + description + " to " + dbFile.getPath() + "..."); 554 database.writeToFile(dbFile.getPath()); 555 } catch (IOException e) { 556 getLookupFailureCallback().logError("Error writing " + description, e); 557 } 558 } 559 560 561 564 public final Map <Object , Object > getAnalysisLocals() { 565 return analysisLocals; 566 } 567 568 public abstract InnerClassAccessMap getInnerClassAccessMap(); 569 570 575 public static void setCurrentAnalysisContext(AnalysisContext analysisContext) { 576 currentAnalysisContext.set(analysisContext); 577 } 578 579 } 580 581 | Popular Tags |