📄 findbugs.java
字号:
*/ private static String home; /** * File extensions that indicate an archive (zip, jar, or similar). */ private static final Set<String> archiveExtensionSet = new HashSet<String>(); static { archiveExtensionSet.add(".jar"); archiveExtensionSet.add(".zip"); archiveExtensionSet.add(".war"); archiveExtensionSet.add(".ear"); archiveExtensionSet.add(".sar"); } /** * Known URL protocols. * Filename URLs that do not have an explicit protocol are * assumed to be files. */ private static final Set<String> knownURLProtocolSet = new HashSet<String>(); static { knownURLProtocolSet.add("file"); knownURLProtocolSet.add("http"); knownURLProtocolSet.add("https"); knownURLProtocolSet.add("jar"); } private ErrorCountingBugReporter bugReporter; private Project project; private List<ClassObserver> classObserverList; private Detector detectors []; private FindBugsProgress progressCallback; private ClassScreener classScreener; private AnalysisContext analysisContext; private String currentClass; /* ---------------------------------------------------------------------- * Public methods * ---------------------------------------------------------------------- */ /** * Constructor. * * @param bugReporter the BugReporter object that will be used to report * BugInstance objects, analysis errors, class to source mapping, etc. * @param project the Project indicating which files to analyze and * the auxiliary classpath to use; note that the FindBugs * object will create a private copy of the Project object */ public FindBugs(BugReporter bugReporter, Project project) { if (bugReporter == null) throw new IllegalArgumentException("null bugReporter"); if (project == null) throw new IllegalArgumentException("null project"); this.bugReporter = new ErrorCountingBugReporter(bugReporter); this.project = project.duplicate(); this.classObserverList = new LinkedList<ClassObserver>(); // Create a no-op progress callback. this.progressCallback = new FindBugsProgress() { public void reportNumberOfArchives(int numArchives) { } public void finishArchive() { } public void startAnalysis(int numClasses) { } public void finishClass() { } public void finishPerClassAnalysis() { } }; // Class screener this.classScreener = new ClassScreener(); addClassObserver(bugReporter); } /** * Set the progress callback that will be used to keep track * of the progress of the analysis. * * @param progressCallback the progress callback */ public void setProgressCallback(FindBugsProgress progressCallback) { this.progressCallback = progressCallback; } /** * Set filter of bug instances to include or exclude. * * @param filterFileName the name of the filter file * @param include true if the filter specifies bug instances to include, * false if it specifies bug instances to exclude */ public void setFilter(String filterFileName, boolean include) throws IOException, FilterException { Filter filter = new Filter(filterFileName); BugReporter origBugReporter = bugReporter.getRealBugReporter(); BugReporter filterBugReporter = new FilterBugReporter(origBugReporter, filter, include); bugReporter.setRealBugReporter(filterBugReporter); } /** * Add a ClassObserver. * * @param classObserver the ClassObserver */ public void addClassObserver(ClassObserver classObserver) { classObserverList.add(classObserver); } /** * Set the ClassScreener. * This object chooses which individual classes to analyze. * By default, all classes are analyzed. * * @param classScreener the ClassScreener to use */ public void setClassScreener(ClassScreener classScreener) { this.classScreener = classScreener; } /** * Execute FindBugs on the Project. * All bugs found are reported to the BugReporter object which was set * when this object was constructed. * * @throws java.io.IOException if an I/O exception occurs analyzing one of the files * @throws InterruptedException if the thread is interrupted while conducting the analysis */ public void execute() throws java.io.IOException, InterruptedException { // Configure the analysis context analysisContext = new AnalysisContext(bugReporter); analysisContext.setSourcePath(project.getSourceDirList()); // Give the BugReporter a reference to this object, // in case it wants to access information such // as the AnalysisContext bugReporter.setEngine(this); // Create detectors createDetectors(); // Clear the repository of classes clearRepository(); // Get list of files to analyze. // Note that despite the name getJarFileArray(), // they can also be zip files, directories, // and single class files. LinkedList<ArchiveWorkListItem> archiveWorkList = new LinkedList<ArchiveWorkListItem>(); for (Iterator<String> i = project.getFileList().iterator(); i.hasNext(); ) { String fileName = i.next(); archiveWorkList.add(new ArchiveWorkListItem(fileName, true)); } // Report how many archives/directories/files will be analyzed, // for progress dialog in GUI progressCallback.reportNumberOfArchives(archiveWorkList.size()); // Keep track of the names of all classes to be analyzed List<String> repositoryClassList = new LinkedList<String>(); // Record additional entries that should be added to // the aux classpath. These occur when one or more classes // in a directory or archive are skipped, to ensure that // the skipped classes can still be referenced. List<String> additionalAuxClasspathEntryList = new LinkedList<String>(); // Add all classes in analyzed archives/directories/files while (!archiveWorkList.isEmpty()) { ArchiveWorkListItem item = archiveWorkList.removeFirst(); scanArchiveOrDirectory(item, archiveWorkList, repositoryClassList, additionalAuxClasspathEntryList); } // Now that we have scanned all specified archives and directories, // we can set the repository classpath. setRepositoryClassPath(additionalAuxClasspathEntryList); // Callback for progress dialog: analysis is starting progressCallback.startAnalysis(repositoryClassList.size()); // Examine all classes for bugs. // Don't examine the same class more than once. // (The user might specify two jar files that contain // the same class.) Set<String> examinedClassSet = new HashSet<String>(); for (Iterator<String> i = repositoryClassList.iterator(); i.hasNext();) { String className = i.next(); if (examinedClassSet.add(className)) examineClass(className); } // Callback for progress dialog: analysis finished progressCallback.finishPerClassAnalysis(); // Force any detectors which defer work until all classes have // been seen to do that work. this.reportFinal(); // Flush any queued bug reports bugReporter.finish(); // Flush any queued error reports bugReporter.reportQueuedErrors(); // Free up memory for reports clearRepository(); } /** * Get the analysis context. * It is only valid to call this method after the execute() * method has been called. */ public AnalysisContext getAnalysisContext() { return analysisContext; } /** * Get the name of the most recent class to be analyzed. * This is useful for diagnosing an unexpected exception. * Returns null if no class has been analyzed. */ public String getCurrentClass() { return currentClass; } /** * Get the number of bug instances that were reported during analysis. */ public int getBugCount() { return bugReporter.getBugCount(); } /** * Get the number of errors that occurred during analysis. */ public int getErrorCount() { return bugReporter.getErrorCount(); } /** * Get the number of time missing classes were reported during analysis. */ public int getMissingClassCount() { return bugReporter.getMissingClassCount(); } /** * Set the FindBugs home directory. */ public static void setHome(String home) { FindBugs.home = home; } /** * Get the FindBugs home directory. */ public static String getHome() { if (home == null) { home = System.getProperty("findbugs.home"); if (home == null) { System.err.println("Error: The findbugs.home property is not set!"); } } return home; } /* ---------------------------------------------------------------------- * Private methods * ---------------------------------------------------------------------- */ /** * Create Detectors for each DetectorFactory which is enabled. * This will populate the detectors array. */ private void createDetectors() { ArrayList<Detector> result = new ArrayList<Detector>(); Iterator<DetectorFactory> i = DetectorFactoryCollection.instance().factoryIterator(); while (i.hasNext()) { DetectorFactory factory = i.next(); if (factory.getPlugin().isEnabled() && factory.isEnabled()) { Detector detector = factory.create(bugReporter); detector.setAnalysisContext(analysisContext); result.add(detector); } } detectors = result.toArray(new Detector[result.size()]); } /** * Clear the Repository and update it to reflect the classpath * specified by the current project. */ private void clearRepository() { // Purge repository of previous contents Repository.clearCache(); // Clear InnerClassAccessMap cache. InnerClassAccessMap.instance().clearCache(); // Create a URLClassPathRepository based on the current project, // and make it current. URLClassPathRepository repository = new URLClassPathRepository(); Repository.setRepository(repository); } /** * Based on Project settings, set the classpath to be used * by the Repository when looking up classes. * @throws IOException */ private void setRepositoryClassPath(List<String> additionalAuxClasspathEntryList) throws IOException { URLClassPathRepository repository = (URLClassPathRepository) Repository.getRepository(); // Set aux classpath entries addCollectionToClasspath(project.getAuxClasspathEntryList(), repository); // Set implicit classpath entries addCollectionToClasspath(project.getImplicitClasspathEntryList(), repository); // Add "extra" aux classpath entries needed to ensure that // skipped classes can be referenced. addCollectionToClasspath(additionalAuxClasspathEntryList, repository); // Add system classpath entries repository.addSystemClasspathComponents(); } /** * Add all classpath entries in given Collection to the given * URLClassPathRepository. Missing entries are not fatal: * we'll log them as analysis errors, but the analysis can * continue. * * @param collection classpath entries to add * @param repository URLClassPathRepository to add the entries to */ private void addCollectionToClasspath(Collection<String> collection, URLClassPathRepository repository) { for (Iterator<String> i = collection.iterator(); i.hasNext(); ) { String entry = i.next(); try { repository.addURL(entry); } catch (IOException e) { bugReporter.logError("Warning: could not add URL " + entry + " to classpath: " + e.toString()); } } } /** * Add all classes contained in given file or directory to the BCEL Repository. * * @param item work list item representing the file, which may be a jar/zip * archive, a single class file, or a directory to be recursively * searched for class files * @param archiveWorkList work list of archives to analyze: this method * may add to the work list if it finds nested archives * @param repositoryClassList a List to which all classes found in * the archive or directory are added, so we later know * which files to analyze */ private void scanArchiveOrDirectory(ArchiveWorkListItem item, LinkedList<ArchiveWorkListItem> archiveWorkList, List<String> repositoryClassList, List<String> additionalAuxClasspathEntryList) throws IOException, InterruptedException {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -