| 1 19 20 package edu.umd.cs.findbugs; 21 22 import java.io.FileInputStream ; 23 import java.io.IOException ; 24 import java.util.Arrays ; 25 import java.util.Collection ; 26 import java.util.HashSet ; 27 import java.util.Iterator ; 28 import java.util.LinkedList ; 29 import java.util.List ; 30 import java.util.Set ; 31 import java.util.TreeSet ; 32 33 import org.apache.bcel.classfile.ClassFormatException; 34 35 import edu.umd.cs.findbugs.ba.AnalysisCacheToAnalysisContextAdapter; 36 import edu.umd.cs.findbugs.ba.AnalysisContext; 37 import edu.umd.cs.findbugs.ba.AnalysisException; 38 import edu.umd.cs.findbugs.ba.SourceInfoMap; 39 import edu.umd.cs.findbugs.classfile.CheckedAnalysisException; 40 import edu.umd.cs.findbugs.classfile.ClassDescriptor; 41 import edu.umd.cs.findbugs.classfile.Global; 42 import edu.umd.cs.findbugs.classfile.IAnalysisCache; 43 import edu.umd.cs.findbugs.classfile.IClassFactory; 44 import edu.umd.cs.findbugs.classfile.IClassObserver; 45 import edu.umd.cs.findbugs.classfile.IClassPath; 46 import edu.umd.cs.findbugs.classfile.IClassPathBuilder; 47 import edu.umd.cs.findbugs.classfile.ICodeBase; 48 import edu.umd.cs.findbugs.classfile.MissingClassException; 49 import edu.umd.cs.findbugs.classfile.ResourceNotFoundException; 50 import edu.umd.cs.findbugs.classfile.analysis.ClassInfo; 51 import edu.umd.cs.findbugs.classfile.impl.ClassFactory; 52 import edu.umd.cs.findbugs.config.AnalysisFeatureSetting; 53 import edu.umd.cs.findbugs.config.UserPreferences; 54 import edu.umd.cs.findbugs.filter.FilterException; 55 import edu.umd.cs.findbugs.plan.AnalysisPass; 56 import edu.umd.cs.findbugs.plan.ExecutionPlan; 57 import edu.umd.cs.findbugs.plan.OrderingConstraintException; 58 import edu.umd.cs.findbugs.util.ClassName; 59 60 68 public class FindBugs2 implements IFindBugsEngine { 69 private static final boolean VERBOSE = SystemProperties.getBoolean("findbugs.verbose"); 70 private static final boolean DEBUG = VERBOSE || SystemProperties.getBoolean("findbugs.debug"); 71 72 private List <IClassObserver> classObserverList; 73 private ErrorCountingBugReporter bugReporter; 74 private Project project; 75 private IClassFactory classFactory; 76 private IClassPath classPath; 77 private IAnalysisCache analysisCache; 78 private List <ClassDescriptor> appClassList; 79 private Set <ClassDescriptor> referencedClassSet; 80 private DetectorFactoryCollection detectorFactoryCollection; 81 private ExecutionPlan executionPlan; 82 private UserPreferences userPreferences; 83 private String currentClassName; 84 private String releaseName; 85 private String sourceInfoFileName; 86 private AnalysisFeatureSetting[] analysisFeatureSettingList; 87 private boolean relaxedReportingMode; 88 private String trainingInputDir; 89 private String trainingOutputDir; 90 private FindBugsProgress progress; 91 private IClassScreener classScreener; 92 private boolean scanNestedArchives; 93 94 97 public FindBugs2() { 98 this.classObserverList = new LinkedList <IClassObserver>(); 99 this.analysisFeatureSettingList = FindBugs.DEFAULT_EFFORT; 100 this.progress = new NoOpFindBugsProgress(); 101 102 this.classScreener = new IClassScreener() { 104 107 public boolean matches(String fileName) { 108 return true; 109 } 110 }; 111 112 this.scanNestedArchives = false; 114 } 115 116 123 public void setDetectorFactoryCollection( 124 DetectorFactoryCollection detectorFactoryCollection) { 125 this.detectorFactoryCollection = detectorFactoryCollection; 126 } 127 128 137 public void execute() throws IOException , InterruptedException { 138 classFactory = ClassFactory.instance(); 140 141 createClassPath(); 143 144 createAnalysisCache(); 146 147 progress.reportNumberOfArchives(project.getFileCount()); 148 149 try { 150 buildClassPath(); 153 154 buildReferencedClassSet(); 156 157 createAnalysisContext(); 159 160 FindBugs.configureBugCollection(this); 162 163 FindBugsAnalysisFeatures.setRelaxedMode(relaxedReportingMode); 165 166 FindBugs.configureTrainingDatabases(this); 168 169 configureAnalysisFeatures(); 171 172 createExecutionPlan(); 174 175 analyzeApplication(); 177 } catch (CheckedAnalysisException e) { 178 IOException ioe = new IOException ("IOException while scanning codebases"); 179 ioe.initCause(e); 180 throw ioe; 181 } finally { 182 classPath.close(); 184 } 185 } 186 187 190 public BugReporter getBugReporter() { 191 return bugReporter; 192 } 193 194 197 public Project getProject() { 198 return project; 199 } 200 201 204 public void addClassObserver(IClassObserver classObserver) { 205 classObserverList.add(classObserver); 206 } 207 208 211 public void addFilter(String filterFileName, boolean include) throws IOException , FilterException { 212 FindBugs.configureFilter(bugReporter, filterFileName, include); 213 } 214 215 218 public void enableTrainingInput(String trainingInputDir) { 219 this.trainingInputDir = trainingInputDir; 220 } 221 222 225 public void enableTrainingOutput(String trainingOutputDir) { 226 this.trainingOutputDir = trainingOutputDir; 227 } 228 229 232 public int getBugCount() { 233 return bugReporter.getBugCount(); 234 } 235 236 239 public String getCurrentClass() { 240 return currentClassName; 241 } 242 243 246 public int getErrorCount() { 247 return bugReporter.getErrorCount(); 248 } 249 250 253 public int getMissingClassCount() { 254 return bugReporter.getMissingClassCount(); 255 } 256 257 260 public String getReleaseName() { 261 return releaseName; 262 } 263 264 267 public void setAnalysisFeatureSettings(AnalysisFeatureSetting[] settingList) { 268 this.analysisFeatureSettingList = settingList; 269 } 270 271 274 public void setBugReporter(BugReporter bugReporter) { 275 this.bugReporter = new ErrorCountingBugReporter(bugReporter); 276 addClassObserver(bugReporter); 277 } 278 279 282 public void setClassScreener(IClassScreener classScreener) { 283 this.classScreener = classScreener; 284 } 285 286 289 public void setProgressCallback(FindBugsProgress progressCallback) { 290 this.progress = progressCallback; 291 } 292 293 296 public void setProject(Project project) { 297 this.project = project; 298 } 299 300 303 public void setRelaxedReportingMode(boolean relaxedReportingMode) { 304 this.relaxedReportingMode = relaxedReportingMode; 305 } 306 307 310 public void setReleaseName(String releaseName) { 311 this.releaseName = releaseName; 312 } 313 314 317 public void setSourceInfoFile(String sourceInfoFile) { 318 this.sourceInfoFileName = sourceInfoFile; 319 } 320 321 324 public void setUserPreferences(UserPreferences userPreferences) { 325 this.userPreferences = userPreferences; 326 } 327 328 331 public boolean emitTrainingOutput() { 332 return trainingOutputDir != null; 333 } 334 335 338 public UserPreferences getUserPreferences() { 339 return userPreferences; 340 } 341 342 345 private void createClassPath() { 346 classPath = classFactory.createClassPath(); 347 } 348 349 352 public String getTrainingInputDir() { 353 return trainingInputDir; 354 } 355 356 359 public String getTrainingOutputDir() { 360 return trainingOutputDir; 361 } 362 363 366 public boolean useTrainingInput() { 367 return trainingInputDir != null; 368 } 369 370 373 public void setScanNestedArchives(boolean scanNestedArchives) { 374 this.scanNestedArchives = scanNestedArchives; 375 } 376 377 380 private void createAnalysisCache() { 381 analysisCache = ClassFactory.instance().createAnalysisCache(classPath, bugReporter); 382 383 new edu.umd.cs.findbugs.classfile.engine.EngineRegistrar().registerAnalysisEngines(analysisCache); 388 new edu.umd.cs.findbugs.classfile.engine.asm.EngineRegistrar().registerAnalysisEngines(analysisCache); 389 new edu.umd.cs.findbugs.classfile.engine.bcel.EngineRegistrar().registerAnalysisEngines(analysisCache); 390 391 Global.setAnalysisCacheForCurrentThread(analysisCache); 392 } 393 394 401 private void buildClassPath() throws InterruptedException , IOException , CheckedAnalysisException { 402 IClassPathBuilder builder = classFactory.createClassPathBuilder(bugReporter); 403 404 for (String path : project.getFileArray()) { 405 builder.addCodeBase(classFactory.createFilesystemCodeBaseLocator(path), true); 406 } 407 for (String path : project.getAuxClasspathEntryList()) { 408 builder.addCodeBase(classFactory.createFilesystemCodeBaseLocator(path), false); 409 } 410 411 builder.scanNestedArchives(scanNestedArchives); 412 413 builder.build(classPath, progress); 414 415 appClassList = builder.getAppClassList(); 416 417 for (Iterator <? extends ICodeBase> i = classPath.appCodeBaseIterator(); i.hasNext(); ){ 422 ICodeBase appCodeBase = i.next(); 423 424 if (appCodeBase.containsSourceFiles()) { 425 String pathName = appCodeBase.getPathName(); 426 if (pathName != null) { 427 project.addSourceDir(pathName); 428 } 429 } 430 431 project.addTimestamp(appCodeBase.getLastModifiedTime()); 432 } 433 434 } 435 436 private void buildReferencedClassSet() throws CheckedAnalysisException, InterruptedException { 437 439 referencedClassSet = new TreeSet <ClassDescriptor>(); 440 441 LinkedList <ClassDescriptor> workList = new LinkedList <ClassDescriptor>(); 442 workList.addAll(appClassList); 443 444 Set <ClassDescriptor> seen = new HashSet <ClassDescriptor>(); 445 Set <ClassDescriptor> appClassSet = new HashSet <ClassDescriptor>(appClassList); 446 447 Set <ClassDescriptor> badAppClassSet = new HashSet <ClassDescriptor>(); 448 449 while (!workList.isEmpty()) { 450 if (Thread.interrupted()) 451 throw new InterruptedException (); 452 ClassDescriptor classDesc = workList.removeFirst(); 453 454 if (seen.contains(classDesc)) { 455 continue; 456 } 457 seen.add(classDesc); 458 459 referencedClassSet.add(classDesc); 460 461 try { 464 ClassInfo classInfo = Global.getAnalysisCache().getClassAnalysis(ClassInfo.class, classDesc); 465 referencedClassSet.addAll(Arrays.asList(classInfo.getReferencedClassDescriptorList())); 466 467 if (classInfo.getSuperclassDescriptor() != null) { 468 workList.addLast(classInfo.getSuperclassDescriptor()); 469 } 470 471 for (ClassDescriptor ifaceDesc : classInfo.getInterfaceDescriptorList()) { 472 workList.addLast(ifaceDesc); 473 } 474 } catch (MissingClassException e) { 475 bugReporter.reportMissingClass(e.getClassDescriptor()); 477 if (appClassSet.contains(classDesc)) { 478 badAppClassSet.add(classDesc); 479 } 480 } catch (CheckedAnalysisException e) { 481 bugReporter.logError("Error scanning " + classDesc + " for referenced classes", e); 483 if (appClassSet.contains(classDesc)) { 484 badAppClassSet.add(classDesc); 485 } 486 } 487 } 488 489 appClassList.removeAll(badAppClassSet); 491 } 492 493 497 private void createAnalysisContext() throws CheckedAnalysisException, IOException { 498 AnalysisCacheToAnalysisContextAdapter analysisContext = 499 new AnalysisCacheToAnalysisContextAdapter(); 500 501 analysisContext.clearRepository(); 504 505 analysisContext.setAppClassList(appClassList); 507 508 if (sourceInfoFileName != null) { 510 SourceInfoMap sourceInfoMap = analysisContext.getSourceInfoMap(); 511 sourceInfoMap.read(new FileInputStream (sourceInfoFileName)); 512 } 513 514 AnalysisContext.setCurrentAnalysisContext(analysisContext); 516 } 517 518 521 private void configureAnalysisFeatures() { 522 for (AnalysisFeatureSetting setting : analysisFeatureSettingList) { 523 setting.configure(AnalysisContext.currentAnalysisContext()); 524 } 525 } 526 527 532 private void createExecutionPlan() throws OrderingConstraintException { 533 executionPlan = new ExecutionPlan(); 534 535 DetectorFactoryChooser detectorFactoryChooser = new DetectorFactoryChooser() { 537 540 public boolean choose(DetectorFactory factory) { 541 return FindBugs.isDetectorEnabled(FindBugs2.this, factory); 542 } 543 }; 544 executionPlan.setDetectorFactoryChooser(detectorFactoryChooser); 545 546 for (Iterator <Plugin> i = detectorFactoryCollection.pluginIterator(); i.hasNext(); ) { 548 Plugin plugin = i.next(); 549 if (DEBUG) { 550 System.out.println("Adding plugin " + plugin.getPluginId() + " to execution plan"); 551 } 552 executionPlan.addPlugin(plugin); 553 } 554 555 executionPlan.build(); 557 558 if (DEBUG) { 559 System.out.println(executionPlan.getNumPasses() + " passes in execution plan"); 560 } 561 } 562 563 566 private void analyzeApplication() throws InterruptedException { 567 int passCount = 0; 568 boolean multiplePasses = executionPlan.getNumPasses() > 1; 569 int [] classesPerPass = new int[executionPlan.getNumPasses()]; 570 classesPerPass[0] = referencedClassSet .size(); 571 for(int i = 0; i < classesPerPass.length; i++) 572 classesPerPass[i] = i == 0 ? referencedClassSet.size() : appClassList.size(); 573 progress.predictPassCount(classesPerPass); 574 for (Iterator <AnalysisPass> i = executionPlan.passIterator(); i.hasNext(); ) { 575 AnalysisPass pass = i.next(); 576 577 Detector2[] detectorList = pass.instantiateDetector2sInPass(bugReporter); 579 580 Collection <ClassDescriptor> classCollection = (multiplePasses && passCount == 0) 584 ? referencedClassSet 585 : appClassList; 586 if (DEBUG) { 587 System.out.println("Pass " + (passCount) + ": " + classCollection.size() + " classes"); 588 } 589 590 progress.startAnalysis(classCollection.size()); 591 592 for (ClassDescriptor classDescriptor : classCollection) { 593 if (DEBUG) { 594 System.out.println("Class " + classDescriptor); 595 } 596 597 if (!classScreener.matches(classDescriptor.toResourceName())) { 598 if (DEBUG) { 599 System.out.println("*** Excluded by class screener"); 600 } 601 continue; 602 } 603 604 currentClassName = ClassName.toDottedClassName(classDescriptor.getClassName()); 605 notifyClassObservers(classDescriptor); 606 607 for (Detector2 detector : detectorList) { 608 if (Thread.interrupted()) 609 throw new InterruptedException (); 610 if (DEBUG) { 611 System.out.println("Applying " + detector.getDetectorClassName() + " to " + classDescriptor); 612 } 613 try { 614 detector.visitClass(classDescriptor); 615 } catch (ClassFormatException e) { 616 logRecoverableException(classDescriptor, detector, e); 617 } catch (MissingClassException e) { 618 Global.getAnalysisCache().getErrorLogger().reportMissingClass(e.getClassDescriptor()); 619 } catch (CheckedAnalysisException e) { 620 logRecoverableException(classDescriptor, detector, e); 621 } catch (AnalysisException e) { 622 logRecoverableException(classDescriptor, detector, e); 623 } catch (ArrayIndexOutOfBoundsException e) { 624 logRecoverableException(classDescriptor, detector, e); 625 } catch (ClassCastException e) { 626 logRecoverableException(classDescriptor, detector, e); 627 } 628 } 629 630 progress.finishClass(); 631 } 632 633 for (Detector2 detector : detectorList) { 635 detector.finishPass(); 636 } 637 638 AnalysisContext.currentAnalysisContext().updateDatabases(passCount); 639 progress.finishPerClassAnalysis(); 640 641 passCount++; 642 } 643 644 bugReporter.finish(); 646 647 bugReporter.reportQueuedErrors(); 649 } 650 651 656 private void notifyClassObservers(ClassDescriptor classDescriptor) { 657 for (IClassObserver observer : classObserverList) { 658 observer.observeClass(classDescriptor); 659 } 660 } 661 662 670 private void logRecoverableException( 671 ClassDescriptor classDescriptor, Detector2 detector, Throwable e) { 672 bugReporter.logError("Exception analyzing " + classDescriptor.toDottedClassName() + 673 " using detector " + detector.getDetectorClassName(), e); 674 } 675 676 public static void main(String [] args) throws Exception { 677 FindBugs2 findBugs = new FindBugs2(); 679 680 TextUICommandLine commandLine = new TextUICommandLine(); 682 FindBugs.processCommandLine(commandLine, args, findBugs); 683 684 FindBugs.runMain(findBugs, commandLine); 686 } 687 } 688 | Popular Tags |