📄 findbugs.java
字号:
/* * FindBugs - Find bugs in Java programs * Copyright (C) 2003,2004 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;import java.io.BufferedOutputStream;import java.io.DataInputStream;import java.io.File;import java.io.FileFilter;import java.io.FileOutputStream;import java.io.IOException;import java.io.InputStream;import java.io.PrintStream;import java.net.URL;import java.util.ArrayList;import java.util.Collection;import java.util.HashSet;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Set;import java.util.StringTokenizer;import java.util.zip.ZipEntry;import java.util.zip.ZipInputStream;import org.apache.bcel.Repository;import org.apache.bcel.classfile.ClassFormatException;import org.apache.bcel.classfile.ClassParser;import org.apache.bcel.classfile.JavaClass;import edu.umd.cs.findbugs.ba.AnalysisContext;import edu.umd.cs.findbugs.ba.AnalysisException;import edu.umd.cs.findbugs.ba.ClassContext;import edu.umd.cs.findbugs.ba.ClassObserver;import edu.umd.cs.findbugs.ba.InnerClassAccessMap;import edu.umd.cs.findbugs.visitclass.Constants2;/** * An instance of this class is used to apply the selected set of * analyses on some collection of Java classes. It also implements the * comand line interface. * * @author Bill Pugh * @author David Hovemeyer */public class FindBugs implements Constants2, ExitCodes { /* ---------------------------------------------------------------------- * Helper classes * ---------------------------------------------------------------------- */ /** * Delegating InputStream wrapper that never closes the * underlying input stream. */ private static class NoCloseInputStream extends DataInputStream { /** * Constructor. * @param in the real InputStream */ public NoCloseInputStream(InputStream in) { super(in); } public void close() { } } /** * Work list item specifying a file/directory/URL containing * class files to analyze. */ private static class ArchiveWorkListItem { private String fileName; private boolean explicit; /** * Constructor. * * @param fileName file/directory/URL * @param explicit true if this source of classes appeared explicitly * in the project file, false if was found indirectly * (e.g., a nested jar file in a .war file) */ public ArchiveWorkListItem(String fileName, boolean explicit) { this.fileName = fileName; this.explicit = explicit; } /** * Get the file/directory/URL. */ public String getFileName() { return fileName; } /** * Return whether this class source appeared explicitly in * the project file. */ public boolean isExplicit() { return explicit; } } /** * Interface for an object representing a source of class files to analyze. */ private interface ClassProducer { /** * Get the next class to analyze. * * @return the class, or null of there are no more classes for this ClassProducer * @throws IOException if an IOException occurs * @throws InterruptedException if the thread is interrupted */ public JavaClass getNextClass() throws IOException, InterruptedException; /** * Did this class producer scan any Java source files? */ public boolean containsSourceFiles(); /** * Close any internal files or streams. */ public void close(); } /** * ClassProducer for single class files. */ private class SingleClassProducer implements ClassProducer { private URL url; /** * Constructor. * * @param url the single class file to be analyzed */ public SingleClassProducer(URL url) { this.url = url; } public JavaClass getNextClass() throws IOException, InterruptedException { if (url == null) return null; if (Thread.interrupted()) throw new InterruptedException(); URL urlToParse = url; url = null; // don't return it next time // ClassScreener may veto this class. if (!classScreener.matches(urlToParse.toString())) return null; try { return parseClass(urlToParse); } catch (ClassFormatException e) { throw new ClassFormatException("Invalid class file format for " + url.toString() + ": " + e.getMessage()); } } public boolean containsSourceFiles() { return false; } public void close() { // Nothing to do here } } /** * ClassProducer for zip/jar archives. */ private class ZipClassProducer implements ClassProducer { private URL url; private LinkedList<ArchiveWorkListItem> archiveWorkList; private List<String> additionalAuxClasspathEntryList; private ZipInputStream zipInputStream; private boolean containsSourceFiles; public ZipClassProducer(URL url, LinkedList<ArchiveWorkListItem> archiveWorkList, List<String> additionalAuxClasspathEntryList) throws IOException { this.url = url; this.archiveWorkList = archiveWorkList; this.additionalAuxClasspathEntryList = additionalAuxClasspathEntryList; if (DEBUG) System.out.println("Opening jar/zip input stream for " + url.toString()); this.zipInputStream = new ZipInputStream(url.openStream()); this.containsSourceFiles = false; } public JavaClass getNextClass() throws IOException, InterruptedException { for (;;) { if (Thread.interrupted()) throw new InterruptedException(); ZipEntry zipEntry = zipInputStream.getNextEntry(); if (zipEntry == null) return null; try { String entryName = zipEntry.getName(); // ClassScreener may veto this class. if (!classScreener.matches(entryName)) { // Add archive URL to aux classpath if (!additionalAuxClasspathEntryList.contains(url.toString())) { //System.out.println("Adding additional aux classpath entry: " + url.toString()); additionalAuxClasspathEntryList.add(url.toString()); } continue; } String fileExtension = getFileExtension(entryName); if (fileExtension != null) { if (fileExtension.equals(".class")) { return parseClass(url.toString(), new NoCloseInputStream(zipInputStream), entryName); } else if (archiveExtensionSet.contains(fileExtension)) { // Add nested archive to archive work list ArchiveWorkListItem nestedItem = new ArchiveWorkListItem("jar:" + url.toString() + "!/" + entryName, false); archiveWorkList.addFirst(nestedItem); } else if (fileExtension.equals(".java")) { containsSourceFiles = true; } } } finally { zipInputStream.closeEntry(); } } } public boolean containsSourceFiles() { return containsSourceFiles; } public void close() { if (zipInputStream != null) { try { zipInputStream.close(); } catch (IOException ignore) { // Ignore } } } } /** * ClassProducer for directories. * The directory is scanned recursively for class files. */ private class DirectoryClassProducer implements ClassProducer { private String dirName; private List<String> additionalAuxClasspathEntryList; private Iterator<String> rfsIter; private boolean containsSourceFiles; public DirectoryClassProducer(String dirName, List<String> additionalAuxClasspathEntryList) throws InterruptedException { this.dirName = dirName; this.additionalAuxClasspathEntryList = additionalAuxClasspathEntryList; FileFilter filter = new FileFilter() { public boolean accept(File file) { String fileName = file.getName(); if (file.isDirectory() || fileName.endsWith(".class")) return true; if (fileName.endsWith(".java")) containsSourceFiles = true; return false; } }; // This will throw InterruptedException if the thread is // interrupted. RecursiveFileSearch rfs = new RecursiveFileSearch(dirName, filter).search(); this.rfsIter = rfs.fileNameIterator(); this.containsSourceFiles = false; } public JavaClass getNextClass() throws IOException, InterruptedException { String fileName; for (;;) { if (!rfsIter.hasNext()) return null; fileName = rfsIter.next(); if (classScreener.matches(fileName)) { break; } else { // Add directory URL to aux classpath String dirURL= "file:" + dirName; if (!additionalAuxClasspathEntryList.contains(dirURL)) { //System.out.println("Adding additional aux classpath entry: " + dirURL); additionalAuxClasspathEntryList.add(dirURL); } } } try { return parseClass(new URL("file:" + fileName)); } catch (ClassFormatException e) { throw new ClassFormatException("Invalid class file format for " + fileName + ": " + e.getMessage()); } } public boolean containsSourceFiles() { return containsSourceFiles; } public void close() { // Nothing to do here } } /** * A delegating bug reporter which counts reported bug instances, * missing classes, and serious analysis errors. */ private static class ErrorCountingBugReporter extends DelegatingBugReporter { private int bugCount; private int missingClassCount; private int errorCount; private Set<String> missingClassSet = new HashSet<String>(); public ErrorCountingBugReporter(BugReporter realBugReporter) { super(realBugReporter); this.bugCount = 0; this.missingClassCount = 0; this.errorCount = 0; // Add an observer to record when bugs make it through // all priority and filter criteria, so our bug count is // accurate. realBugReporter.addObserver(new BugReporterObserver() { public void reportBug(BugInstance bugInstance) { ++bugCount; } }); } public int getBugCount() { return bugCount; } public int getMissingClassCount() { return missingClassCount; } public int getErrorCount() { return errorCount; } public void logError(String message) { ++errorCount; super.logError(message); } public void reportMissingClass(ClassNotFoundException ex) { String missing = AbstractBugReporter.getMissingClassName(ex); if (missingClassSet.add(missing)) ++missingClassCount;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -