📄 findbugs.java
字号:
/* * FindBugs - Find bugs in Java programs * 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;import java.io.DataInputStream;import java.io.File;import java.io.FileFilter;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Constructor;import java.net.URL;import java.net.URLConnection;import java.util.ArrayList;import java.util.Collection;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.LinkedList;import java.util.List;import java.util.Map;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 org.apache.bcel.util.ClassPath;import edu.umd.cs.findbugs.annotations.SuppressWarnings;import edu.umd.cs.findbugs.ba.AbstractClassMember;import edu.umd.cs.findbugs.ba.AnalysisContext;import edu.umd.cs.findbugs.ba.AnalysisException;import edu.umd.cs.findbugs.ba.AnalysisFeatures;import edu.umd.cs.findbugs.ba.ClassContext;import edu.umd.cs.findbugs.ba.URLClassPath;import edu.umd.cs.findbugs.ba.URLClassPathRepository;import edu.umd.cs.findbugs.classfile.ClassDescriptor;import edu.umd.cs.findbugs.classfile.IClassObserver;import edu.umd.cs.findbugs.config.AnalysisFeatureSetting;import edu.umd.cs.findbugs.config.CommandLine;import edu.umd.cs.findbugs.config.UserPreferences;import edu.umd.cs.findbugs.config.CommandLine.HelpRequestedException;import edu.umd.cs.findbugs.filter.Filter;import edu.umd.cs.findbugs.filter.FilterException;import edu.umd.cs.findbugs.plan.AnalysisPass;import edu.umd.cs.findbugs.plan.ExecutionPlan;import edu.umd.cs.findbugs.plan.OrderingConstraintException;import edu.umd.cs.findbugs.util.Archive;import edu.umd.cs.findbugs.util.ClassName;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 * command line interface. * * Much of the active work has migrated to the FindBugs2 engine, and that should be used * instead of FindBugs if possible. * * @author Bill Pugh * @author David Hovemeyer * */public class FindBugs implements Constants2, ExitCodes, IFindBugsEngine { /* ---------------------------------------------------------------------- * 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); } @Override 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(); /** * Return the latest creation/modification time of any of the class files scanned. * @return the last modification time */ public long getLastModificationTime(); /** * Close any internal files or streams. */ public void close(); } /** * ClassProducer for single class files. */ private class SingleClassProducer implements ClassProducer { private URL url; long time = 0; /** * 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 { URLConnection u = urlToParse.openConnection(); time = u.getLastModified(); return parseFromStream(u.getInputStream(), urlToParse.toString()); } catch (ClassFormatException e) { throw new ClassFormatException("Invalid class file format for " + urlToParse.toString() + ": " + e.getMessage()); } } public boolean containsSourceFiles() { return false; } public void close() { // Nothing to do here } /* (non-Javadoc) * @see edu.umd.cs.findbugs.FindBugs.ClassProducer#getLatestTimeOfClass() */ public long getLastModificationTime() { return time; } } /** * 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; private long time = 0; private long zipTime = 0; 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()); URLConnection u = url.openConnection(); this.zipTime = u.getLastModified(); this.zipInputStream = new ZipInputStream(u.getInputStream()); 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 = URLClassPath.getFileExtension(entryName); if (fileExtension != null) { if (fileExtension.equals(".class")) { long modTime = zipEntry.getTime(); if (modTime > time) time = modTime; return parseClass(url.toString(), new NoCloseInputStream(zipInputStream), entryName); } else if (Archive.ARCHIVE_EXTENSION_SET.contains(fileExtension)) { // Add nested archive to archive work list if (url.toString().indexOf("!/") < 0) { 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 } } } static final long millisecondsInAYear = 31556926000L; /* (non-Javadoc) * @see edu.umd.cs.findbugs.FindBugs.ClassProducer#getLastModificationTime() */ public long getLastModificationTime() { if (time + millisecondsInAYear > zipTime) return time; return zipTime; } } /** * 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; private long time; 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 { long modTime = new File(fileName).lastModified(); if (time < modTime) time = modTime; 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 } /* (non-Javadoc) * @see edu.umd.cs.findbugs.FindBugs.ClassProducer#getLastModificationTime() */ public long getLastModificationTime() { return time; } } public static final AnalysisFeatureSetting[] MIN_EFFORT = new AnalysisFeatureSetting[]{ new AnalysisFeatureSetting(AnalysisFeatures.CONSERVE_SPACE, true), new AnalysisFeatureSetting(AnalysisFeatures.ACCURATE_EXCEPTIONS, false), new AnalysisFeatureSetting(AnalysisFeatures.MODEL_INSTANCEOF, false), new AnalysisFeatureSetting(AnalysisFeatures.SKIP_HUGE_METHODS, true), new AnalysisFeatureSetting(AnalysisFeatures.INTERATIVE_OPCODE_STACK_ANALYSIS, false), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_GUARANTEED_VALUE_DEREFS_IN_NULL_POINTER_ANALYSIS, false), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_VALUE_NUMBERS_IN_NULL_POINTER_ANALYSIS, false),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -