/*
 * FindBugs - Find bugs in Java programs
 * Copyright (C) 2003-2008 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.File;
import java.io.IOException;
import java.util.Collection;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.dom4j.DocumentException;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import edu.umd.cs.findbugs.ba.AnalysisContext;
import edu.umd.cs.findbugs.ba.AnalysisFeatures;
import edu.umd.cs.findbugs.config.AnalysisFeatureSetting;
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.internalAnnotations.StaticConstant;
import edu.umd.cs.findbugs.updates.UpdateChecker;
import edu.umd.cs.findbugs.updates.UpdateChecker.PluginUpdate;
import edu.umd.cs.findbugs.util.FutureValue;

Static methods and fields useful for working with instances of IFindBugsEngine. This class was previously the main driver for FindBugs analyses, but has been replaced by FindBugs2.
Author:Bill Pugh, David Hovemeyer
/** * Static methods and fields useful for working with instances of * IFindBugsEngine. * * This class was previously the main driver for FindBugs analyses, but has been * replaced by {@link FindBugs2 FindBugs2}. * * @author Bill Pugh * @author David Hovemeyer */
public abstract class FindBugs {
Analysis settings for -effort:min.
/** * Analysis settings for -effort:min. */
public static final AnalysisFeatureSetting[] MIN_EFFORT = new AnalysisFeatureSetting[] { new AnalysisFeatureSetting(AnalysisFeatures.CONSERVE_SPACE, true), new AnalysisFeatureSetting(AnalysisFeatures.ACCURATE_EXCEPTIONS, false), new AnalysisFeatureSetting(AnalysisFeatures.MERGE_SIMILAR_WARNINGS, true), new AnalysisFeatureSetting(AnalysisFeatures.MODEL_INSTANCEOF, false), new AnalysisFeatureSetting(AnalysisFeatures.SKIP_HUGE_METHODS, true), new AnalysisFeatureSetting(AnalysisFeatures.INTERATIVE_OPCODE_STACK_ANALYSIS, true), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_GUARANTEED_VALUE_DEREFS_IN_NULL_POINTER_ANALYSIS, false), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_VALUE_NUMBERS_IN_NULL_POINTER_ANALYSIS, false), new AnalysisFeatureSetting(FindBugsAnalysisFeatures.INTERPROCEDURAL_ANALYSIS, false), new AnalysisFeatureSetting(FindBugsAnalysisFeatures.INTERPROCEDURAL_ANALYSIS_OF_REFERENCED_CLASSES, false), };
Analysis settings for -effort:less.
/** * Analysis settings for -effort:less. */
public static final AnalysisFeatureSetting[] LESS_EFFORT = new AnalysisFeatureSetting[] { new AnalysisFeatureSetting(AnalysisFeatures.CONSERVE_SPACE, false), new AnalysisFeatureSetting(AnalysisFeatures.ACCURATE_EXCEPTIONS, true), new AnalysisFeatureSetting(AnalysisFeatures.MERGE_SIMILAR_WARNINGS, true), new AnalysisFeatureSetting(AnalysisFeatures.MODEL_INSTANCEOF, true), new AnalysisFeatureSetting(AnalysisFeatures.SKIP_HUGE_METHODS, true), new AnalysisFeatureSetting(AnalysisFeatures.INTERATIVE_OPCODE_STACK_ANALYSIS, true), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_GUARANTEED_VALUE_DEREFS_IN_NULL_POINTER_ANALYSIS, false), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_VALUE_NUMBERS_IN_NULL_POINTER_ANALYSIS, false), new AnalysisFeatureSetting(FindBugsAnalysisFeatures.INTERPROCEDURAL_ANALYSIS, false), new AnalysisFeatureSetting(FindBugsAnalysisFeatures.INTERPROCEDURAL_ANALYSIS_OF_REFERENCED_CLASSES, false), };
Analysis settings for -effort:default.
/** * Analysis settings for -effort:default. */
public static final AnalysisFeatureSetting[] DEFAULT_EFFORT = new AnalysisFeatureSetting[] { new AnalysisFeatureSetting(AnalysisFeatures.CONSERVE_SPACE, false), new AnalysisFeatureSetting(AnalysisFeatures.ACCURATE_EXCEPTIONS, true), new AnalysisFeatureSetting(AnalysisFeatures.MERGE_SIMILAR_WARNINGS, true), new AnalysisFeatureSetting(AnalysisFeatures.MODEL_INSTANCEOF, true), new AnalysisFeatureSetting(AnalysisFeatures.SKIP_HUGE_METHODS, true), new AnalysisFeatureSetting(AnalysisFeatures.INTERATIVE_OPCODE_STACK_ANALYSIS, true), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_GUARANTEED_VALUE_DEREFS_IN_NULL_POINTER_ANALYSIS, true), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_VALUE_NUMBERS_IN_NULL_POINTER_ANALYSIS, true), new AnalysisFeatureSetting(FindBugsAnalysisFeatures.INTERPROCEDURAL_ANALYSIS, true), new AnalysisFeatureSetting(FindBugsAnalysisFeatures.INTERPROCEDURAL_ANALYSIS_OF_REFERENCED_CLASSES, false), };
Analysis settings for -effort:more.
/** * Analysis settings for -effort:more. */
public static final AnalysisFeatureSetting[] MORE_EFFORT = new AnalysisFeatureSetting[] { new AnalysisFeatureSetting(AnalysisFeatures.CONSERVE_SPACE, false), new AnalysisFeatureSetting(AnalysisFeatures.ACCURATE_EXCEPTIONS, true), new AnalysisFeatureSetting(AnalysisFeatures.MERGE_SIMILAR_WARNINGS, true), new AnalysisFeatureSetting(AnalysisFeatures.MODEL_INSTANCEOF, true), new AnalysisFeatureSetting(AnalysisFeatures.SKIP_HUGE_METHODS, true), new AnalysisFeatureSetting(AnalysisFeatures.INTERATIVE_OPCODE_STACK_ANALYSIS, true), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_GUARANTEED_VALUE_DEREFS_IN_NULL_POINTER_ANALYSIS, true), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_VALUE_NUMBERS_IN_NULL_POINTER_ANALYSIS, true), new AnalysisFeatureSetting(FindBugsAnalysisFeatures.INTERPROCEDURAL_ANALYSIS, true), new AnalysisFeatureSetting(FindBugsAnalysisFeatures.INTERPROCEDURAL_ANALYSIS_OF_REFERENCED_CLASSES, false), };
Analysis settings for -effort:max.
/** * Analysis settings for -effort:max. */
public static final AnalysisFeatureSetting[] MAX_EFFORT = new AnalysisFeatureSetting[] { new AnalysisFeatureSetting(AnalysisFeatures.CONSERVE_SPACE, false), new AnalysisFeatureSetting(AnalysisFeatures.ACCURATE_EXCEPTIONS, true), new AnalysisFeatureSetting(AnalysisFeatures.MERGE_SIMILAR_WARNINGS, true), new AnalysisFeatureSetting(AnalysisFeatures.MODEL_INSTANCEOF, true), new AnalysisFeatureSetting(AnalysisFeatures.SKIP_HUGE_METHODS, false), new AnalysisFeatureSetting(AnalysisFeatures.INTERATIVE_OPCODE_STACK_ANALYSIS, true), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_GUARANTEED_VALUE_DEREFS_IN_NULL_POINTER_ANALYSIS, true), new AnalysisFeatureSetting(AnalysisFeatures.TRACK_VALUE_NUMBERS_IN_NULL_POINTER_ANALYSIS, true), new AnalysisFeatureSetting(FindBugsAnalysisFeatures.INTERPROCEDURAL_ANALYSIS, true), new AnalysisFeatureSetting(FindBugsAnalysisFeatures.INTERPROCEDURAL_ANALYSIS_OF_REFERENCED_CLASSES, true), };
Debug tracing.
/** * Debug tracing. */
public static final boolean DEBUG = Boolean.getBoolean("findbugs.debug");
FindBugs home directory.
/** * FindBugs home directory. */
private static String home = System.getProperty("findbugs.home"); private static boolean noAnalysis = Boolean.getBoolean("findbugs.noAnalysis");
Disable analysis within FindBugs. Turns off loading of bug detectors.
/** * Disable analysis within FindBugs. Turns off loading of bug detectors. */
public static void setNoAnalysis() { noAnalysis = true; }
Returns:Returns the noAnalysis.
/** * @return Returns the noAnalysis. */
public static boolean isNoAnalysis() { return noAnalysis; } private static boolean noMains = Boolean.getBoolean("findbugs.noMains");
Disable loading of FindBugsMain classes.
/** * Disable loading of FindBugsMain classes. */
public static void setNoMains() { noMains = true; }
Returns:Returns the noMains.
/** * @return Returns the noMains. */
public static boolean isNoMains() { return noMains; } public static final Logger LOGGER = Logger.getLogger(FindBugs.class.getPackage().getName()); static { LOGGER.setLevel(Level.WARNING); }
Known URL protocols. Filename URLs that do not have an explicit protocol are assumed to be files.
/** * Known URL protocols. Filename URLs that do not have an explicit protocol * are assumed to be files. */
@StaticConstant static public final Set<String> knownURLProtocolSet = new HashSet<String>(); static { knownURLProtocolSet.add("file"); knownURLProtocolSet.add("http"); knownURLProtocolSet.add("https"); knownURLProtocolSet.add("jar"); }
Set the FindBugs home directory.
/** * Set the FindBugs home directory. */
public static void setHome(String home) { FindBugs.home = home; }
Get the FindBugs home directory.
/** * Get the FindBugs home directory. */
public static String getHome() { return home; }
Configure training databases.
Params:
  • findBugs – the IFindBugsEngine to configure
Throws:
/** * Configure training databases. * * @param findBugs * the IFindBugsEngine to configure * @throws IOException */
public static void configureTrainingDatabases(IFindBugsEngine findBugs) throws IOException { if (findBugs.emitTrainingOutput()) { String trainingOutputDir = findBugs.getTrainingOutputDir(); if (!new File(trainingOutputDir).isDirectory()) { throw new IOException("Training output directory " + trainingOutputDir + " does not exist"); } AnalysisContext.currentAnalysisContext().setDatabaseOutputDir(trainingOutputDir); // XXX: hack System.setProperty("findbugs.checkreturn.savetraining", new File(trainingOutputDir, "checkReturn.db").getPath()); } if (findBugs.useTrainingInput()) { String trainingInputDir = findBugs.getTrainingInputDir(); if (!new File(trainingInputDir).isDirectory()) { throw new IOException("Training input directory " + trainingInputDir + " does not exist"); } AnalysisContext.currentAnalysisContext().setDatabaseInputDir(trainingInputDir); AnalysisContext.currentAnalysisContext().loadInterproceduralDatabases(); // XXX: hack System.setProperty("findbugs.checkreturn.loadtraining", new File(trainingInputDir, "checkReturn.db").getPath()); } else { AnalysisContext.currentAnalysisContext().loadDefaultInterproceduralDatabases(); } }
Determines whether or not given DetectorFactory should be enabled.
Params:
  • findBugs – the IFindBugsEngine
  • factory – the DetectorFactory
  • rankThreshold – TODO
Returns:true if the DetectorFactory should be enabled, false otherwise
/** * Determines whether or not given DetectorFactory should be enabled. * * @param findBugs * the IFindBugsEngine * @param factory * the DetectorFactory * @param rankThreshold * TODO * @return true if the DetectorFactory should be enabled, false otherwise */
public static boolean isDetectorEnabled(IFindBugsEngine findBugs, DetectorFactory factory, int rankThreshold) { if (!findBugs.getUserPreferences().isDetectorEnabled(factory)) { return false; } if (!factory.isEnabledForCurrentJRE()) { return false; } // Slow first pass detectors are usually disabled, but may be explicitly // enabled if (!AnalysisContext.currentAnalysisContext().getBoolProperty(FindBugsAnalysisFeatures.INTERPROCEDURAL_ANALYSIS) && factory.isDetectorClassSubtypeOf(InterproceduralFirstPassDetector.class)) { return false; } int maxRank = Integer.MAX_VALUE; Set<BugPattern> reportedBugPatterns = factory.getReportedBugPatterns(); boolean isNonReportingDetector = factory.isDetectorClassSubtypeOf(FirstPassDetector.class); if (!isNonReportingDetector && !reportedBugPatterns.isEmpty()) { for (BugPattern b : reportedBugPatterns) { int rank = BugRanker.findRank(b, factory); if (maxRank > rank) { maxRank = rank; } } if (maxRank > rankThreshold) { if (false) { System.out.println("Detector " + factory.getShortName() + " has max rank " + maxRank + ", disabling"); System.out.println("Reports : " + reportedBugPatterns); } return false; } } // Training detectors are enabled if, and only if, we are emitting // training output boolean isTrainingDetector = factory.isDetectorClassSubtypeOf(TrainingDetector.class); if (findBugs.emitTrainingOutput()) { return isTrainingDetector || isNonReportingDetector; } if (isTrainingDetector) { return false; } return true; }
Process -bugCategories option.
Params:
  • categories – comma-separated list of bug categories
Returns:Set of categories to be used
/** * Process -bugCategories option. * * @param categories * comma-separated list of bug categories * * @return Set of categories to be used */
public static Set<String> handleBugCategories(String categories) { // Parse list of bug categories Set<String> categorySet = new HashSet<String>(); StringTokenizer tok = new StringTokenizer(categories, ","); while (tok.hasMoreTokens()) { categorySet.add(tok.nextToken()); } return categorySet; }
Process the command line.
Params:
  • commandLine – the TextUICommandLine object which will parse the command line
  • argv – the command line arguments
  • findBugs – the IFindBugsEngine to configure
Throws:
/** * Process the command line. * * @param commandLine * the TextUICommandLine object which will parse the command line * @param argv * the command line arguments * @param findBugs * the IFindBugsEngine to configure * @throws IOException * @throws FilterException */
public static void processCommandLine(TextUICommandLine commandLine, String[] argv, IFindBugsEngine findBugs) throws IOException, FilterException { // Expand option files in command line. // An argument beginning with "@" is treated as specifying // the name of an option file. // Each line of option files are treated as a single argument. // Blank lines and comment lines (beginning with "#") // are ignored. try { argv = commandLine.expandOptionFiles(argv, true, true); } catch (HelpRequestedException e) { showHelp(commandLine); } int argCount = 0; try { argCount = commandLine.parse(argv); } catch (IllegalArgumentException e) { System.out.println(e.getMessage()); showHelp(commandLine); } catch (HelpRequestedException e) { showHelp(commandLine); } Project project = commandLine.getProject(); for (int i = argCount; i < argv.length; ++i) { project.addFile(argv[i]); } commandLine.handleXArgs(); commandLine.configureEngine(findBugs); if (commandLine.getProject().getFileCount() == 0 && !commandLine.justPrintConfiguration() && !commandLine.justPrintVersion()) { System.out.println("No files to be analyzed"); showHelp(commandLine); } }
Show -help message.
Params:
  • commandLine –
/** * Show -help message. * * @param commandLine */
@SuppressFBWarnings("DM_EXIT") public static void showHelp(TextUICommandLine commandLine) { showSynopsis(); ShowHelp.showGeneralOptions(); FindBugs.showCommandLineOptions(commandLine); System.exit(1); }
Given a fully-configured IFindBugsEngine and the TextUICommandLine used to configure it, execute the analysis.
Params:
  • findBugs – a fully-configured IFindBugsEngine
  • commandLine – the TextUICommandLine used to configure the IFindBugsEngine
/** * Given a fully-configured IFindBugsEngine and the TextUICommandLine used * to configure it, execute the analysis. * * @param findBugs * a fully-configured IFindBugsEngine * @param commandLine * the TextUICommandLine used to configure the IFindBugsEngine */
@SuppressFBWarnings("DM_EXIT") public static void runMain(IFindBugsEngine findBugs, TextUICommandLine commandLine) throws IOException { boolean verbose = !commandLine.quiet() || commandLine.setExitCode(); FutureValue<Collection<UpdateChecker.PluginUpdate>> updateHolder = null; if (verbose) { updateHolder = DetectorFactoryCollection.instance().getUpdates(); } try { findBugs.execute(); } catch (InterruptedException e) { assert false; // should not occur checkExitCodeFail(commandLine, e); throw new RuntimeException(e); } catch (RuntimeException e) { checkExitCodeFail(commandLine, e); throw e; } catch (IOException e) { checkExitCodeFail(commandLine, e); throw e; } int bugCount = findBugs.getBugCount(); int missingClassCount = findBugs.getMissingClassCount(); int errorCount = findBugs.getErrorCount(); if (verbose) { if (bugCount > 0) { System.err.println("Warnings generated: " + bugCount); } if (missingClassCount > 0) { System.err.println("Missing classes: " + missingClassCount); } if (errorCount > 0) { System.err.println("Analysis errors: " + errorCount); } if (updateHolder.isDone()) { try { Collection<PluginUpdate> updates = updateHolder.get(); if (!DetectorFactoryCollection.instance().getUpdateChecker().updatesHaveBeenSeenBefore(updates)) { for(UpdateChecker.PluginUpdate u : updates) { System.err.println(u); } } } catch (InterruptedException e) { assert true; } } } if (commandLine.setExitCode()) { int exitCode = 0; System.err.println("Calculating exit code..."); if (errorCount > 0) { exitCode |= ExitCodes.ERROR_FLAG; System.err.println("Setting 'errors encountered' flag (" + ExitCodes.ERROR_FLAG + ")"); } if (missingClassCount > 0) { exitCode |= ExitCodes.MISSING_CLASS_FLAG; System.err.println("Setting 'missing class' flag (" + ExitCodes.MISSING_CLASS_FLAG + ")"); } if (bugCount > 0) { exitCode |= ExitCodes.BUGS_FOUND_FLAG; System.err.println("Setting 'bugs found' flag (" + ExitCodes.BUGS_FOUND_FLAG + ")"); } System.err.println("Exit code set to: " + exitCode); System.exit(exitCode); } }
Params:
  • commandLine –
  • e –
/** * @param commandLine * @param e */
private static void checkExitCodeFail(TextUICommandLine commandLine, Exception e) { if (commandLine.setExitCode()) { e.printStackTrace(System.err); System.exit(ExitCodes.ERROR_FLAG); } }
Print command line options synopses to stdout.
/** * Print command line options synopses to stdout. */
public static void showCommandLineOptions() { showCommandLineOptions(new TextUICommandLine()); }
Print command line options synopses to stdout.
Params:
  • commandLine – the TextUICommandLine whose options should be printed
/** * Print command line options synopses to stdout. * * @param commandLine * the TextUICommandLine whose options should be printed */
public static void showCommandLineOptions(TextUICommandLine commandLine) { commandLine.printUsage(System.out); }
Show the overall FindBugs command synopsis.
/** * Show the overall FindBugs command synopsis. */
public static void showSynopsis() { System.out .println("Usage: findbugs [general options] -textui [command line options...] [jar/zip/class files, directories...]"); }
Configure the (bug instance) Filter for the given DelegatingBugReporter.
Params:
  • bugReporter – a DelegatingBugReporter
  • filterFileName – filter file name
  • include – true if the filter is an include filter, false if it's an exclude filter
Throws:
/** * Configure the (bug instance) Filter for the given DelegatingBugReporter. * * @param bugReporter * a DelegatingBugReporter * @param filterFileName * filter file name * @param include * true if the filter is an include filter, false if it's an * exclude filter * @throws java.io.IOException * @throws edu.umd.cs.findbugs.filter.FilterException */
public static BugReporter configureFilter(BugReporter bugReporter, String filterFileName, boolean include) throws IOException, FilterException { Filter filter = new Filter(filterFileName); return new FilterBugReporter(bugReporter, filter, include); }
Configure a baseline bug instance filter.
Params:
  • bugReporter – a DelegatingBugReporter
  • baselineFileName – filename of baseline Filter
Throws:
/** * Configure a baseline bug instance filter. * * @param bugReporter * a DelegatingBugReporter * @param baselineFileName * filename of baseline Filter * @throws java.io.IOException * @throws org.dom4j.DocumentException */
public static BugReporter configureBaselineFilter(BugReporter bugReporter, String baselineFileName) throws IOException, DocumentException { return new ExcludingHashesBugReporter(bugReporter, baselineFileName); }
Configure the BugCollection (if the BugReporter being used is constructing one).
Params:
  • findBugs – the IFindBugsEngine
/** * Configure the BugCollection (if the BugReporter being used is * constructing one). * * @param findBugs * the IFindBugsEngine */
public static void configureBugCollection(IFindBugsEngine findBugs) { BugCollection bugs = findBugs.getBugReporter().getBugCollection(); if (bugs != null) { bugs.setReleaseName(findBugs.getReleaseName()); Project project = findBugs.getProject(); String projectName = project.getProjectName(); if (projectName == null) { projectName = findBugs.getProjectName(); project.setProjectName(projectName); } long timestamp = project.getTimestamp(); if (FindBugs.validTimestamp(timestamp)) { bugs.setTimestamp(timestamp); bugs.getProjectStats().setTimestamp(timestamp); } } }
Date of release of Java 1.0
/** Date of release of Java 1.0 */
public final static long MINIMUM_TIMESTAMP = new GregorianCalendar(1996, 0, 23).getTime().getTime(); public static boolean validTimestamp(long timestamp) { return timestamp > MINIMUM_TIMESTAMP; } }