All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.pmd.PMDConfiguration Maven / Gradle / Ivy

Go to download

PMD is an extensible multilanguage static code analyzer. It finds common programming flaws like unused variables, empty catch blocks, unnecessary object creation, and so forth. It's mainly concerned with Java and Apex, but supports 16 other languages. It comes with 400+ built-in rules. It can be extended with custom rules. It uses JavaCC and Antlr to parse source files into abstract syntax trees (AST) and runs rules against them to find violations. Rules can be written in Java or using a XPath query. Currently, PMD supports Java, JavaScript, Salesforce.com Apex and Visualforce, Kotlin, Swift, Modelica, PLSQL, Apache Velocity, JSP, WSDL, Maven POM, HTML, XML and XSL. Scala is supported, but there are currently no Scala rules available. Additionally, it includes CPD, the copy-paste-detector. CPD finds duplicated code in Coco, C/C++, C#, Dart, Fortran, Gherkin, Go, Groovy, HTML, Java, JavaScript, JSP, Julia, Kotlin, Lua, Matlab, Modelica, Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex and Visualforce, Scala, Swift, T-SQL, Typescript, Apache Velocity, WSDL, XML and XSL.

There is a newer version: 7.5.0-metrics
Show newest version
/**
 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
 */

package net.sourceforge.pmd;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Properties;

import org.checkerframework.checker.nullness.qual.NonNull;
import org.slf4j.LoggerFactory;

import net.sourceforge.pmd.cache.internal.AnalysisCache;
import net.sourceforge.pmd.cache.internal.FileAnalysisCache;
import net.sourceforge.pmd.cache.internal.NoopAnalysisCache;
import net.sourceforge.pmd.internal.util.ClasspathClassLoader;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.PmdCapableLanguage;
import net.sourceforge.pmd.lang.rule.RulePriority;
import net.sourceforge.pmd.lang.rule.RuleSetLoader;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.renderers.RendererFactory;
import net.sourceforge.pmd.util.AssertionUtil;
import net.sourceforge.pmd.util.log.internal.SimpleMessageReporter;

/**
 * This class contains the details for the runtime configuration of a
 * PMD run. Once configured, use {@link PmdAnalysis#create(PMDConfiguration)}
 * in a try-with-resources to execute the analysis (see {@link PmdAnalysis}).
 *
 * 

Rulesets

* *
    *
  • You can configure paths to the rulesets to use with {@link #addRuleSet(String)}. * These can be file paths or classpath resources.
  • *
  • Use {@link #setMinimumPriority(RulePriority)} to control the minimum priority a * rule must have to be included. Defaults to the lowest priority, ie all rules are loaded.
  • *
* *

Source files

* *
    *
  • The default encoding of source files is the system default as * returned by System.getProperty("file.encoding"). * You can set it with {@link #setSourceEncoding(Charset)}.
  • *
  • The source files to analyze can be given in many ways. See * {@link #addInputPath(Path)} {@link #setInputFilePath(Path)}, {@link #setInputUri(URI)}. *
  • Files are assigned a language based on their name. The language * version of languages can be given with * {@link #setDefaultLanguageVersion(LanguageVersion)}. * The default language assignment can be overridden with * {@link #setForceLanguageVersion(LanguageVersion)}.
  • *
* *

Rendering

* *
    *
  • The renderer format to use for Reports. {@link #getReportFormat()}
  • *
  • The file to which the Report should render. {@link #getReportFilePath()}
  • *
  • Configure the root paths that are used to relativize file names in reports via {@link #addRelativizeRoot(Path)}. * This enables to get short names in reports.
  • *
  • The initialization properties to use when creating a Renderer instance. * {@link #getReportProperties()}
  • *
  • An indicator of whether to show suppressed Rule violations in Reports. * {@link #isShowSuppressedViolations()}
  • *
* *

Language configuration

*
    *
  • Use {@link #setSuppressMarker(String)} to change the comment marker for suppression comments. Defaults to {@value #DEFAULT_SUPPRESS_MARKER}.
  • *
  • See {@link #setClassLoader(ClassLoader)} and {@link #prependAuxClasspath(String)} for * information for how to configure classpath for Java analysis.
  • *
  • You can set additional language properties with {@link #getLanguageProperties(Language)}
  • *
* *

Miscellaneous

*
    *
  • Use {@link #setThreads(int)} to control the parallelism of the analysis. Defaults * one thread per available processor. {@link #getThreads()}
  • *
*/ public class PMDConfiguration extends AbstractConfiguration { private static final LanguageRegistry DEFAULT_REGISTRY = LanguageRegistry.PMD; /** The default suppress marker string. */ public static final String DEFAULT_SUPPRESS_MARKER = "NOPMD"; private Path reportFile; // General behavior options private String suppressMarker = DEFAULT_SUPPRESS_MARKER; private int threads = Runtime.getRuntime().availableProcessors(); private ClassLoader classLoader = getClass().getClassLoader(); // Rule and source file options private List ruleSets = new ArrayList<>(); private RulePriority minimumPriority = RulePriority.LOW; // Reporting options private String reportFormat; private Properties reportProperties = new Properties(); private boolean showSuppressedViolations = false; private AnalysisCache analysisCache = new NoopAnalysisCache(); private boolean ignoreIncrementalAnalysis; public PMDConfiguration() { this(DEFAULT_REGISTRY); } public PMDConfiguration(@NonNull LanguageRegistry languageRegistry) { super(languageRegistry, new SimpleMessageReporter(LoggerFactory.getLogger(PmdAnalysis.class))); } /** * Get the suppress marker. This is the source level marker used to indicate * a RuleViolation should be suppressed. * * @return The suppress marker. */ public String getSuppressMarker() { return suppressMarker; } /** * Set the suppress marker. * * @param suppressMarker * The suppress marker to use. */ public void setSuppressMarker(String suppressMarker) { Objects.requireNonNull(suppressMarker, "Suppress marker was null"); this.suppressMarker = suppressMarker; } /** * Get the number of threads to use when processing Rules. * * @return The number of threads. */ public int getThreads() { return threads; } /** * Set the number of threads to use when processing Rules. * * @param threads * The number of threads. */ public void setThreads(int threads) { this.threads = threads; } /** * Get the ClassLoader being used by PMD when processing Rules. * * @return The ClassLoader being used */ public ClassLoader getClassLoader() { return classLoader; } /** * Set the ClassLoader being used by PMD when processing Rules. Setting a * value of null will cause the default ClassLoader to be used. * * @param classLoader * The ClassLoader to use */ public void setClassLoader(ClassLoader classLoader) { if (classLoader == null) { this.classLoader = getClass().getClassLoader(); } else { this.classLoader = classLoader; } } /** * Prepend the specified classpath like string to the current ClassLoader of * the configuration. If no ClassLoader is currently configured, the * ClassLoader used to load the {@link PMDConfiguration} class will be used * as the parent ClassLoader of the created ClassLoader. * *

If the classpath String looks like a URL to a file (i.e. starts with * file://) the file will be read with each line representing * an entry on the classpath.

* *

You can specify multiple class paths separated by `:` on Unix-systems or `;` under Windows. * See {@link File#pathSeparator}. * * @param classpath The prepended classpath. * * @throws IllegalArgumentException if the given classpath is invalid (e.g. does not exist) * @see PMDConfiguration#setClassLoader(ClassLoader) */ public void prependAuxClasspath(String classpath) { try { if (classLoader == null) { classLoader = PMDConfiguration.class.getClassLoader(); } if (classpath != null) { classLoader = new ClasspathClassLoader(classpath, classLoader); } } catch (IOException e) { // Note: IOExceptions shouldn't appear anymore, they should already be converted // to IllegalArgumentException in ClasspathClassLoader. throw new IllegalArgumentException(e); } } /** * Returns the list of ruleset URIs. * * @see RuleSetLoader#loadFromResource(String) */ public @NonNull List<@NonNull String> getRuleSetPaths() { return ruleSets; } /** * Sets the list of ruleset paths to load when starting the analysis. * * @param ruleSetPaths A list of ruleset paths, understandable by {@link RuleSetLoader#loadFromResource(String)}. * * @throws NullPointerException If the parameter is null */ public void setRuleSets(@NonNull List<@NonNull String> ruleSetPaths) { AssertionUtil.requireParamNotNull("ruleSetPaths", ruleSetPaths); AssertionUtil.requireContainsNoNullValue("ruleSetPaths", ruleSetPaths); this.ruleSets = new ArrayList<>(ruleSetPaths); } /** * Add a new ruleset paths to load when starting the analysis. * This list is initially empty. * * @param rulesetPath A ruleset path, understandable by {@link RuleSetLoader#loadFromResource(String)}. * * @throws NullPointerException If the parameter is null */ public void addRuleSet(@NonNull String rulesetPath) { AssertionUtil.requireParamNotNull("rulesetPath", rulesetPath); this.ruleSets.add(rulesetPath); } /** * Get the minimum priority threshold when loading Rules from RuleSets. * * @return The minimum priority threshold. */ public RulePriority getMinimumPriority() { return minimumPriority; } /** * Set the minimum priority threshold when loading Rules from RuleSets. * * @param minimumPriority * The minimum priority. */ public void setMinimumPriority(RulePriority minimumPriority) { this.minimumPriority = minimumPriority; } /** * Create a Renderer instance based upon the configured reporting options. * No writer is created. * * @return renderer */ public Renderer createRenderer() { return createRenderer(false); } /** * Create a Renderer instance based upon the configured reporting options. * If withReportWriter then we'll configure it with a writer for the * reportFile specified. * * @param withReportWriter * whether to configure a writer or not * @return A Renderer instance. */ public Renderer createRenderer(boolean withReportWriter) { Renderer renderer = RendererFactory.createRenderer(reportFormat, reportProperties); renderer.setShowSuppressedViolations(showSuppressedViolations); if (withReportWriter) { renderer.setReportFile(getReportFilePath() != null ? getReportFilePath().toString() : null); } return renderer; } /** * Get the report format. * * @return The report format. */ public String getReportFormat() { return reportFormat; } /** * Set the report format. This should be a name of a Renderer. * * @param reportFormat * The report format. * * @see Renderer */ public void setReportFormat(String reportFormat) { this.reportFormat = reportFormat; } /** * Get whether the report should show suppressed violations. * * @return true if showing suppressed violations, * false otherwise. */ public boolean isShowSuppressedViolations() { return showSuppressedViolations; } /** * Set whether the report should show suppressed violations. * * @param showSuppressedViolations * true if showing suppressed violations, * false otherwise. */ public void setShowSuppressedViolations(boolean showSuppressedViolations) { this.showSuppressedViolations = showSuppressedViolations; } /** * Get the Report properties. These are used to create the Renderer. * * @return The report properties. */ public Properties getReportProperties() { return reportProperties; } /** * Set the Report properties. These are used to create the Renderer. * * @param reportProperties * The Report properties to set. */ public void setReportProperties(Properties reportProperties) { this.reportProperties = reportProperties; } /** * Retrieves the currently used analysis cache. Will never be null. * * @return The currently used analysis cache. Never null. * * @apiNote This is internal API. */ AnalysisCache getAnalysisCache() { // Make sure we are not null if (analysisCache == null || isIgnoreIncrementalAnalysis() && !(analysisCache instanceof NoopAnalysisCache)) { // sets a noop cache setAnalysisCache(new NoopAnalysisCache()); } return analysisCache; } /** * Sets the analysis cache to be used. Setting a * value of {@code null} will cause a Noop AnalysisCache to be used. * If incremental analysis was explicitly disabled ({@link #isIgnoreIncrementalAnalysis()}), * then this method is a noop. * * @param cache The analysis cache to be used. * * @apiNote This is internal API. Use {@link #setAnalysisCacheLocation(String)} to configure a cache. */ void setAnalysisCache(final AnalysisCache cache) { // the doc says it's a noop if incremental analysis was disabled, // but it's actually the getter that enforces that this.analysisCache = cache == null ? new NoopAnalysisCache() : cache; } /** * Sets the location of the analysis cache to be used. This will automatically configure * and appropriate AnalysisCache implementation. Setting a * value of {@code null} will cause a Noop AnalysisCache to be used. * If incremental analysis was explicitly disabled ({@link #isIgnoreIncrementalAnalysis()}), * then this method is a noop. * * @param cacheLocation The location of the analysis cache to be used. Use {@code null} * to disable the cache. */ public void setAnalysisCacheLocation(final String cacheLocation) { setAnalysisCache(cacheLocation == null ? new NoopAnalysisCache() : new FileAnalysisCache(new File(cacheLocation))); } /** * Sets whether the user has explicitly disabled incremental analysis or not. * If so, incremental analysis is not used, and all suggestions to use it are * disabled. The analysis cached location is ignored, even if it's specified. * * @param noCache Whether to ignore incremental analysis or not */ public void setIgnoreIncrementalAnalysis(boolean noCache) { // see #getAnalysisCache for the implementation. this.ignoreIncrementalAnalysis = noCache; } /** * Returns whether incremental analysis was explicitly disabled by the user * or not. * * @return {@code true} if incremental analysis is explicitly disabled */ public boolean isIgnoreIncrementalAnalysis() { return ignoreIncrementalAnalysis; } /** * Get the file to which the report should render. * * @return The file to which to render. */ public Path getReportFilePath() { return reportFile; } /** * Set the file to which the report should render. * * @param reportFile the file to set */ public void setReportFile(Path reportFile) { this.reportFile = reportFile; } @Override protected void checkLanguageIsAcceptable(Language lang) throws UnsupportedOperationException { if (!(lang instanceof PmdCapableLanguage)) { throw new UnsupportedOperationException("Language " + lang.getId() + " does not support analysis with PMD and cannot be used in a PMDConfiguration. " + "You may be able to use it with CPD though."); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy