Merge branch 'master' into pmd/7.0.x

This commit is contained in:
Andreas Dangel 2020-12-11 19:48:54 +01:00
commit 384d32ddd0
44 changed files with 754 additions and 257 deletions

View File

@ -1,5 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: Question
url: https://github.com/pmd/pmd/discussions?discussions_q=category%3AQ%26A
about: Feel free to ask any question about PMD and its usage
- name: PMD Designer Issues
url: https://github.com/pmd/pmd-designer/issues
about: Issues about the rule designer

View File

@ -1,14 +0,0 @@
---
name: Question
about: Feel free to ask any question about PMD and its usage
title: ''
labels: 'a:question'
assignees: ''
---
<!-- Have a look at https://github.com/pmd/pmd/issues?utf8=%E2%9C%93&q=label%3Aa%3Aquestion if there is already
a similar question -->
**Description:**

View File

@ -3,7 +3,7 @@
![PMD Logo](https://raw.githubusercontent.com/pmd/pmd/pmd/7.0.x/docs/images/logo/pmd-logo-300px.png)
[![Join the chat at https://gitter.im/pmd/pmd](https://badges.gitter.im/pmd/pmd.svg)](https://gitter.im/pmd/pmd?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://github.com/pmd/pmd/workflows/.github/workflows/pushes.yml/badge.svg?branch=master)](https://github.com/pmd/pmd/actions)
[![Build Status](https://github.com/pmd/pmd/workflows/Pushes/badge.svg?branch=master)](https://github.com/pmd/pmd/actions)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/net.sourceforge.pmd/pmd/badge.svg)](https://maven-badges.herokuapp.com/maven-central/net.sourceforge.pmd/pmd)
[![Reproducible Builds](https://img.shields.io/badge/Reproducible_Builds-ok-green?labelColor=blue)](https://github.com/jvm-repo-rebuild/reproducible-central#net.sourceforge.pmd:pmd)
[![Coverage Status](https://coveralls.io/repos/github/pmd/pmd/badge.svg)](https://coveralls.io/github/pmd/pmd)

View File

@ -58,6 +58,23 @@ Thanks to Jeff Bartolotta and Roopa Mohan for contributing this!
#### Deprecated API
##### Around RuleSet parsing
* {% jdoc core::RuleSetFactory %} and {% jdoc core::RuleSetFactoryUtils %} have been deprecated in favor of {% jdoc core::RuleSetLoader %}. This is easier to configure, and more maintainable than the multiple overloads of `RuleSetFactoryUtils`.
* Some static creation methods have been added to {% jdoc core::RuleSet %} for simple cases, eg {% jdoc core::RuleSet#forSingleRule(core::Rule) %}. These replace some counterparts in {% jdoc core::RuleSetFactory %}
* Since {% jdoc core::RuleSets %} is also deprecated, many APIs that require a RuleSets instance now are deprecated, and have a counterpart that expects a `List<RuleSet>`.
* {% jdoc core::RuleSetReferenceId %}, {% jdoc core::RuleSetReference %}, {% jdoc core::RuleSetFactoryCompatibility %} are deprecated. They are most likely not relevant outside of the implementation of pmd-core.
##### Around the `PMD` class
Many classes around PMD's entry point ({% jdoc core::PMD %}) have been deprecated as internal, including:
* The contents of the packages {% jdoc_package core::cli %}, {% jdoc_package core::processor %}
* {% jdoc core::SourceCodeProcessor %}
* The constructors of {% jdoc core::PMD %} (the class will be made a utility class)
##### Miscellaneous
* {% jdoc !!java::lang.java.ast.ASTPackageDeclaration#getPackageNameImage() %},
{% jdoc !!java::lang.java.ast.ASTTypeParameter#getParameterName() %}
and the corresponding XPath attributes. In both cases they're replaced with a new method `getName`,
@ -89,5 +106,6 @@ You can identify them with the `@InternalApi` annotation. You'll also get a depr
* [#2936](https://github.com/pmd/pmd/pull/2936): \[java] (doc) Fix typo: "an accessor" not "a" - [Igor Moreno](https://github.com/igormoreno)
* [#2938](https://github.com/pmd/pmd/pull/2938): \[cs] CPD: fix issue where ignoring using directives could not be disabled - [Maikel Steneker](https://github.com/maikelsteneker)
* [#2945](https://github.com/pmd/pmd/pull/2945): \[cs] Add option to ignore sequences of literals - [Maikel Steneker](https://github.com/maikelsteneker)
* [#2962](https://github.com/pmd/pmd/pull/2962): \[cpp] Add support for C++ 14 binary literals - [Maikel Steneker](https://github.com/maikelsteneker)
{% endtocmaker %}

View File

@ -14,16 +14,15 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.contrib.java.lang.system.SystemErrRule;
import net.sourceforge.pmd.RulePriority;
import net.sourceforge.pmd.RuleSet;
import net.sourceforge.pmd.RuleSetFactory;
import net.sourceforge.pmd.RulesetsFactoryUtils;
import net.sourceforge.pmd.RuleSetLoader;
public class DefaultRulesetTest {
@Rule
public final SystemErrRule systemErrRule = new SystemErrRule().enableLog().muteForSuccessfulTests();
private RuleSetFactory factory = RulesetsFactoryUtils.createFactory(RulePriority.LOW, true, false);
private RuleSetFactory factory = new RuleSetLoader().enableCompatibility(false).toFactory();
@Test
public void loadDefaultRuleset() throws Exception {

View File

@ -11,16 +11,18 @@ import java.io.Writer;
import java.net.URISyntaxException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.benchmark.TextTimingReportRenderer;
import net.sourceforge.pmd.benchmark.TimeTracker;
import net.sourceforge.pmd.benchmark.TimedOperation;
@ -44,7 +46,6 @@ import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.util.ClasspathClassLoader;
import net.sourceforge.pmd.util.FileUtil;
import net.sourceforge.pmd.util.IOUtil;
import net.sourceforge.pmd.util.ResourceLoader;
import net.sourceforge.pmd.util.database.DBMSMetadata;
import net.sourceforge.pmd.util.database.DBURI;
import net.sourceforge.pmd.util.database.SourceObject;
@ -88,7 +89,10 @@ public class PMD {
/**
* Create a PMD instance using a default Configuration. Changes to the
* configuration may be required.
*
* @deprecated Just use the static methods, and maintain your {@link PMDConfiguration} separately.
*/
@Deprecated
public PMD() {
this(new PMDConfiguration());
}
@ -96,9 +100,11 @@ public class PMD {
/**
* Create a PMD instance using the specified Configuration.
*
* @param configuration
* The runtime Configuration of PMD to use.
* @param configuration The runtime Configuration of PMD to use.
*
* @deprecated Just use the static methods, and maintain your {@link PMDConfiguration} separately.
*/
@Deprecated
public PMD(PMDConfiguration configuration) {
this.configuration = configuration;
this.rulesetsFileProcessor = new SourceCodeProcessor(configuration);
@ -114,7 +120,10 @@ public class PMD {
* @throws PMDException
* if the URI couldn't be parsed
* @see DBURI
*
* @deprecated Will be hidden as part of the parsing of {@link PMD#getApplicableFiles(PMDConfiguration, Set)}
*/
@Deprecated
public static List<DataSource> getURIDataSources(String uriString) throws PMDException {
List<DataSource> dataSources = new ArrayList<>();
@ -160,7 +169,11 @@ public class PMD {
* @param configuration
* the given configuration
* @return the pre-configured parser
*
* @deprecated This is internal
*/
@Deprecated
@InternalApi
public static Parser parserFor(LanguageVersion languageVersion, PMDConfiguration configuration) {
// TODO Handle Rules having different parser options.
@ -178,7 +191,10 @@ public class PMD {
*
* @return The configuration.
* @see PMDConfiguration
*
* @deprecated Don't create a PMD instance just to create a {@link PMDConfiguration}
*/
@Deprecated
public PMDConfiguration getConfiguration() {
return configuration;
}
@ -187,7 +203,9 @@ public class PMD {
* Gets the source code processor.
*
* @return SourceCodeProcessor
* @deprecated Source code processor is internal
*/
@Deprecated
public SourceCodeProcessor getSourceCodeProcessor() {
return rulesetsFileProcessor;
}
@ -201,10 +219,8 @@ public class PMD {
public static int doPMD(final PMDConfiguration configuration) {
// Load the RuleSets
final RuleSetFactory ruleSetFactory =
RulesetsFactoryUtils.getRulesetFactory(configuration, new ResourceLoader());
final RuleSets ruleSets =
RulesetsFactoryUtils.getRuleSetsWithBenchmark(configuration.getRuleSets(), ruleSetFactory);
final RuleSetFactory ruleSetFactory = RuleSetLoader.fromPmdConfig(configuration).toFactory();
final RuleSets ruleSets = RulesetsFactoryUtils.getRuleSetsWithBenchmark(configuration.getRuleSets(), ruleSetFactory);
if (ruleSets == null) {
return PMDCommandLineInterface.NO_ERRORS_STATUS;
}
@ -222,24 +238,15 @@ public class PMD {
renderer.start();
}
final RuleContext ctx = new RuleContext();
final AtomicInteger violations = new AtomicInteger(0);
ctx.getReport().addListener(new ThreadSafeReportListener() {
@Override
public void ruleViolationAdded(final RuleViolation ruleViolation) {
violations.getAndIncrement();
}
});
Report report;
try (TimedOperation to = TimeTracker.startOperation(TimedOperationCategory.FILE_PROCESSING)) {
processFiles(configuration, ruleSetFactory, files, ctx, renderers);
report = processFiles(configuration, Arrays.asList(ruleSets.getAllRuleSets()), files, renderers);
}
try (TimedOperation rto = TimeTracker.startOperation(TimedOperationCategory.REPORTING)) {
renderer.end();
renderer.flush();
return violations.get();
return report.getViolations().size();
}
} catch (final Exception e) {
String message = e.getMessage();
@ -271,7 +278,10 @@ public class PMD {
* @param sourceCodeFile
* the source code file
* @return the rule context
*
* @deprecated Not useful
*/
@Deprecated
public static RuleContext newRuleContext(String sourceCodeFilename, File sourceCodeFile) {
RuleContext context = new RuleContext();
@ -294,19 +304,60 @@ public class PMD {
* RuleContext
* @param renderers
* List of {@link Renderer}s
*
* @deprecated Use {@link #processFiles(PMDConfiguration, List, Collection, List)}
* so as not to depend on {@link RuleSetFactory}. Note that this sorts the list of data sources in-place,
* which won't be fixed
*/
@Deprecated
public static void processFiles(final PMDConfiguration configuration, final RuleSetFactory ruleSetFactory,
final List<DataSource> files, final RuleContext ctx, final List<Renderer> renderers) {
final List<DataSource> files, final RuleContext ctx, final List<Renderer> renderers) {
// Note that this duplicates the other routine, because the old behavior was
// that we parsed rulesets (a second time) inside the processor execution.
// To not mess up error handling, we keep this behavior.
encourageToUseIncrementalAnalysis(configuration);
sortFiles(configuration, files);
// Make sure the cache is listening for analysis results
ctx.getReport().addListener(configuration.getAnalysisCache());
final RuleSetFactory silentFactory = new RuleSetFactory(ruleSetFactory, false);
final RuleSetFactory silentFactory = ruleSetFactory.toLoader().warnDeprecated(false).toFactory();
newFileProcessor(configuration).processFiles(silentFactory, files, ctx, renderers);
configuration.getAnalysisCache().persist();
}
/**
* Run PMD using the given configuration. This replaces the other overload.
*
* @param configuration Configuration for the run. Note that the files,
* and rulesets, are ignored, as they are supplied
* as parameters
* @param rulesets Parsed rulesets
* @param files Files to process, will be closed by this method.
* @param renderers Renderers that render the report
*
* @return Report in which violations are accumulated
*
* @throws RuntimeException If processing fails
*/
public static Report processFiles(final PMDConfiguration configuration,
final List<RuleSet> rulesets,
final Collection<? extends DataSource> files,
final List<Renderer> renderers) {
encourageToUseIncrementalAnalysis(configuration);
Report report = new Report();
report.addListener(configuration.getAnalysisCache());
List<DataSource> sortedFiles = new ArrayList<>(files);
sortFiles(configuration, sortedFiles);
RuleContext ctx = new RuleContext();
ctx.setReport(report);
newFileProcessor(configuration).processFiles(new RuleSets(rulesets), sortedFiles, ctx, renderers);
configuration.getAnalysisCache().persist();
return report;
}
private static void sortFiles(final PMDConfiguration configuration, final List<DataSource> files) {
if (configuration.isStressTest()) {
// randomize processing order
@ -439,7 +490,7 @@ public class PMD {
}
/**
* Entry to invoke PMD as command line tool
* Entry to invoke PMD as command line tool. Note that this will invoke {@link System#exit(int)}.
*
* @param args
* command line arguments
@ -449,7 +500,8 @@ public class PMD {
}
/**
* Parses the command line arguments and executes PMD.
* Parses the command line arguments and executes PMD. Returns the
* exit code without exiting the VM.
*
* @param args
* command line arguments

View File

@ -13,6 +13,7 @@ package net.sourceforge.pmd;
* @version $Revision$, $Date$
* @since August 30, 2002
*/
@Deprecated
public class PMDException extends Exception {
private static final long serialVersionUID = 6938647389367956874L;

View File

@ -27,6 +27,7 @@ public class Report {
private final List<SuppressedViolation> suppressedRuleViolations = new ArrayList<>();
private final List<ProcessingError> errors = new ArrayList<>();
private final List<ConfigurationError> configErrors = new ArrayList<>();
private final Object lock = new Object();
/**
* Creates a new, initialized, empty report for the given file name.
@ -218,18 +219,23 @@ public class Report {
* summary over all violations is needed as PMD creates one report per file
* by default.
*
* @param r
* the report to be merged into this.
* <p>This is synchronized on an internal lock (note that other mutation
* operations are not synchronized, todo for pmd 7).
*
* @param r the report to be merged into this.
*
* @see AbstractAccumulatingRenderer
*/
public void merge(Report r) {
errors.addAll(r.errors);
configErrors.addAll(r.configErrors);
suppressedRuleViolations.addAll(r.suppressedRuleViolations);
synchronized (lock) {
errors.addAll(r.errors);
configErrors.addAll(r.configErrors);
suppressedRuleViolations.addAll(r.suppressedRuleViolations);
for (RuleViolation violation : r.getViolations()) {
int index = Collections.binarySearch(violations, violation, RuleViolation.DEFAULT_COMPARATOR);
violations.add(index < 0 ? -index - 1 : index, violation);
for (RuleViolation violation : r.getViolations()) {
int index = Collections.binarySearch(violations, violation, RuleViolation.DEFAULT_COMPARATOR);
violations.add(index < 0 ? -index - 1 : index, violation);
}
}
}

View File

@ -25,6 +25,7 @@ import net.sourceforge.pmd.internal.util.PredicateUtil;
import net.sourceforge.pmd.lang.LanguageVersion;
import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.rule.RuleReference;
import net.sourceforge.pmd.lang.rule.XPathRule;
/**
* This class represents a collection of rules along with some optional filter
@ -91,6 +92,89 @@ public class RuleSet implements ChecksumAware {
filter = rs.filter; // filters are immutable, can be shared
}
/**
* Creates a new ruleset containing a single rule. The ruleset will
* have default description, name, and null file name.
*
* @param rule The rule being created
*
* @return The newly created RuleSet
*/
public static RuleSet forSingleRule(final Rule rule) {
final long checksum;
if (rule instanceof XPathRule) {
checksum = ((XPathRule) rule).getXPathExpression().hashCode();
} else {
// TODO : Is this good enough? all properties' values + rule name
checksum = rule.getPropertiesByPropertyDescriptor().values().hashCode() * 31 + rule.getName().hashCode();
}
final RuleSetBuilder builder =
new RuleSetBuilder(checksum)
.withName(rule.getName())
.withDescription("RuleSet for " + rule.getName());
builder.addRule(rule);
return builder.build();
}
/**
* Creates a new ruleset with the given metadata such as name, description,
* fileName, exclude/include patterns are used. The rules are taken from the given
* collection.
*
* <p><strong>Note:</strong> The rule instances are shared between the collection
* and the new ruleset (copy-by-reference). This might lead to concurrency issues,
* if the rules of the collection are also referenced by other rulesets and used
* in different threads.
* </p>
*
* @param name the name of the ruleset
* @param description the description
* @param fileName the filename
* @param excludePatterns list of exclude patterns
* @param includePatterns list of include patterns, that override the exclude patterns
* @param rules the collection with the rules to add to the new ruleset
*
* @return the new ruleset
*
* @throws NullPointerException If any parameter is null, or the collections contain null elements
*/
public static RuleSet create(String name,
String description,
String fileName,
Collection<Pattern> excludePatterns,
Collection<Pattern> includePatterns,
Iterable<? extends Rule> rules) {
RuleSetBuilder builder = new RuleSetBuilder(0L); // TODO: checksum missing
builder.withName(name)
.withDescription(description)
.withFileName(fileName)
.replaceFileExclusions(excludePatterns)
.replaceFileInclusions(includePatterns);
for (Rule rule : rules) {
builder.addRule(rule);
}
return builder.build();
}
/**
* Creates a copy of the given ruleset. All properties like name, description, fileName
* and exclude/include patterns are copied.
*
* <p><strong>Note:</strong> The rule instances are shared between the original
* and the new ruleset (copy-by-reference). This might lead to concurrency issues,
* if the original ruleset and the new ruleset are used in different threads.
* </p>
*
* @param original the original rule set to copy from
*
* @return the copy
*/
public static RuleSet copy(RuleSet original) {
return new RuleSet(original);
}
/* package */ static class RuleSetBuilder {
public String description;

View File

@ -13,7 +13,6 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
@ -34,21 +33,19 @@ import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import net.sourceforge.pmd.RuleSet.RuleSetBuilder;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.rule.RuleReference;
import net.sourceforge.pmd.lang.rule.XPathRule;
import net.sourceforge.pmd.rules.RuleFactory;
import net.sourceforge.pmd.util.ResourceLoader;
/**
* RuleSetFactory is responsible for creating RuleSet instances from XML
* content. By default Rules will be loaded using the {@link RulePriority#LOW} priority,
* with Rule deprecation warnings off;
* the ruleset compatibility filter is active, too (see {@link RuleSetFactoryCompatibility});
* if the ruleset contains rule references (e.g. for renamed or moved rules), these
* are ignored by default.
* content. See {@link RuleSetLoader} for configuration options and
* their defaults.
*
* @deprecated Use a {@link RuleSetLoader} instead. This will be hidden in PMD 7
* (it's the implementation, while {@link RuleSetLoader} is the API).
*/
@Deprecated
public class RuleSetFactory {
private static final Logger LOG = Logger.getLogger(RuleSetFactory.class.getName());
@ -66,7 +63,7 @@ public class RuleSetFactory {
private final Map<RuleSetReferenceId, RuleSet> parsedRulesets = new HashMap<>();
/**
* @deprecated Use {@link RulesetsFactoryUtils#defaultFactory()}
* @deprecated Use a {@link RuleSetLoader} to build a new factory
*/
@Deprecated // to be removed with PMD 7.0.0.
public RuleSetFactory() {
@ -74,8 +71,7 @@ public class RuleSetFactory {
}
/**
* @deprecated Use {@link RulesetsFactoryUtils#createFactory(ClassLoader, RulePriority, boolean, boolean)}
* or {@link RulesetsFactoryUtils#createFactory(RulePriority, boolean, boolean)}
* @deprecated Use a {@link RuleSetLoader} to build a new factory
*/
@Deprecated // to be removed with PMD 7.0.0.
public RuleSetFactory(final ClassLoader classLoader, final RulePriority minimumPriority,
@ -84,8 +80,7 @@ public class RuleSetFactory {
}
/**
* @deprecated Use {@link RulesetsFactoryUtils#createFactory(ClassLoader, RulePriority, boolean, boolean)}
* or {@link RulesetsFactoryUtils#createFactory(RulePriority, boolean, boolean)}
* @deprecated Use a {@link RuleSetLoader} to build a new factory
*/
@Deprecated // to be hidden with PMD 7.0.0.
public RuleSetFactory(final ResourceLoader resourceLoader, final RulePriority minimumPriority,
@ -110,16 +105,18 @@ public class RuleSetFactory {
/**
* Constructor copying all configuration from another factory.
*
* @param factory
* The factory whose configuration to copy.
* @param warnDeprecated
* Whether deprecation warnings are to be produced by this
* factory.
* @param factory The factory whose configuration to copy.
* @param warnDeprecated Whether deprecation warnings are to be produced by this
* factory
*
* @deprecated Use {@link #toLoader()} to rebuild a factory from a configuration
*/
@Deprecated
public RuleSetFactory(final RuleSetFactory factory, final boolean warnDeprecated) {
this(factory.resourceLoader, factory.minimumPriority, warnDeprecated, factory.compatibilityFilter != null);
}
/**
* Gets the compatibility filter in order to adjust it, e.g. add additional
* filters.
@ -137,28 +134,12 @@ public class RuleSetFactory {
* @return An Iterator of RuleSet objects.
*
* @throws RuleSetNotFoundException if the ruleset file could not be found
*
* @deprecated Use {@link RuleSetLoader#getStandardRuleSets()}
*/
@Deprecated
public Iterator<RuleSet> getRegisteredRuleSets() throws RuleSetNotFoundException {
String rulesetsProperties = null;
List<RuleSetReferenceId> ruleSetReferenceIds = new ArrayList<>();
for (Language language : LanguageRegistry.getLanguages()) {
Properties props = new Properties();
rulesetsProperties = "category/" + language.getTerseName() + "/categories.properties";
try (InputStream inputStream = resourceLoader.loadClassPathResourceAsStreamOrThrow(rulesetsProperties)) {
props.load(inputStream);
String rulesetFilenames = props.getProperty("rulesets.filenames");
if (rulesetFilenames != null) {
ruleSetReferenceIds.addAll(RuleSetReferenceId.parse(rulesetFilenames));
}
} catch (RuleSetNotFoundException e) {
LOG.warning("The language " + language.getTerseName() + " provides no " + rulesetsProperties + ".");
} catch (IOException ioe) {
throw new RuntimeException("Couldn't find " + rulesetsProperties
+ "; please ensure that the directory is on the classpath. The current classpath is: "
+ System.getProperty("java.class.path"));
}
}
return createRuleSets(ruleSetReferenceIds).getRuleSetsIterator();
return toLoader().getStandardRuleSets().iterator();
}
/**
@ -173,7 +154,11 @@ public class RuleSetFactory {
* @return The new RuleSets.
* @throws RuleSetNotFoundException
* if unable to find a resource.
*
* @deprecated Use {@link RuleSetLoader#loadFromResource(String)},
* but note that that method does not split on commas
*/
@Deprecated
public RuleSets createRuleSets(String referenceString) throws RuleSetNotFoundException {
return createRuleSets(RuleSetReferenceId.parse(referenceString));
}
@ -187,7 +172,10 @@ public class RuleSetFactory {
* @return The new RuleSets.
* @throws RuleSetNotFoundException
* if unable to find a resource.
*
* @deprecated Will not be replaced
*/
@Deprecated
public RuleSets createRuleSets(List<RuleSetReferenceId> ruleSetReferenceIds) throws RuleSetNotFoundException {
List<RuleSet> ruleSets = new ArrayList<>();
for (RuleSetReferenceId ruleSetReferenceId : ruleSetReferenceIds) {
@ -209,7 +197,10 @@ public class RuleSetFactory {
* @return A new RuleSet.
* @throws RuleSetNotFoundException
* if unable to find a resource.
*
* @deprecated Use {@link RuleSetLoader#loadFromResource(String)} and discard the rest of the list.
*/
@Deprecated
public RuleSet createRuleSet(String referenceString) throws RuleSetNotFoundException {
List<RuleSetReferenceId> references = RuleSetReferenceId.parse(referenceString);
if (references.isEmpty()) {
@ -228,7 +219,10 @@ public class RuleSetFactory {
* @return A new RuleSet.
* @throws RuleSetNotFoundException
* if unable to find a resource.
*
* @deprecated Will not be replaced
*/
@Deprecated
public RuleSet createRuleSet(RuleSetReferenceId ruleSetReferenceId) throws RuleSetNotFoundException {
return createRuleSet(ruleSetReferenceId, includeDeprecatedRuleReferences);
}
@ -249,7 +243,10 @@ public class RuleSetFactory {
*
* @param original the original rule set to copy from
* @return the copy
*
* @deprecated Use {@link RuleSet#copy(RuleSet)}
*/
@Deprecated
public RuleSet createRuleSetCopy(RuleSet original) {
RuleSetBuilder builder = new RuleSetBuilder(original);
return builder.build();
@ -273,23 +270,17 @@ public class RuleSetFactory {
* @param includePatterns list of include patterns, if any is not a valid regular expression, it will be ignored
* @param rules the collection with the rules to add to the new ruleset
* @return the new ruleset
*
* @deprecated Use {@link RuleSet#create(String, String, String, Collection, Collection, Iterable)}
*/
@Deprecated
public RuleSet createNewRuleSet(String name,
String description,
String fileName,
Collection<String> excludePatterns,
Collection<String> includePatterns,
Collection<Rule> rules) {
RuleSetBuilder builder = new RuleSetBuilder(0L); // TODO: checksum missing
builder.withName(name)
.withDescription(description)
.withFileName(fileName)
.replaceFileExclusions(toPatterns(excludePatterns))
.replaceFileInclusions(toPatterns(includePatterns));
for (Rule rule : rules) {
builder.addRule(rule);
}
return builder.build();
return RuleSet.create(name, description, fileName, toPatterns(excludePatterns), toPatterns(includePatterns), rules);
}
private Collection<Pattern> toPatterns(Collection<String> sources) {
@ -307,24 +298,15 @@ public class RuleSetFactory {
/**
* Creates a new RuleSet containing a single rule.
*
* @param rule
* The rule being created
* @param rule The rule being created
*
* @return The newly created RuleSet
*
* @deprecated Use {@link RuleSet#forSingleRule(Rule)}
*/
public RuleSet createSingleRuleRuleSet(final Rule rule) { // TODO make static?
final long checksum;
if (rule instanceof XPathRule) {
checksum = ((XPathRule) rule).getXPathExpression().hashCode();
} else {
// TODO : Is this good enough? all properties' values + rule name
checksum = rule.getPropertiesByPropertyDescriptor().values().hashCode() * 31 + rule.getName().hashCode();
}
final RuleSetBuilder builder = new RuleSetBuilder(checksum)
.withName(rule.getName())
.withDescription("RuleSet for " + rule.getName());
builder.addRule(rule);
return builder.build();
@Deprecated
public RuleSet createSingleRuleRuleSet(final Rule rule) {
return RuleSet.forSingleRule(rule);
}
/**
@ -347,7 +329,8 @@ public class RuleSetFactory {
private Rule createRule(RuleSetReferenceId ruleSetReferenceId, boolean withDeprecatedRuleReferences)
throws RuleSetNotFoundException {
if (ruleSetReferenceId.isAllRules()) {
throw new IllegalArgumentException("Cannot parse a single Rule from an all Rule RuleSet reference: <" + ruleSetReferenceId + ">.");
throw new IllegalArgumentException(
"Cannot parse a single Rule from an all Rule RuleSet reference: <" + ruleSetReferenceId + ">.");
}
RuleSet ruleSet;
// java8: computeIfAbsent
@ -437,9 +420,6 @@ public class RuleSetFactory {
ruleSetBuilder.filterRulesByPriority(minimumPriority);
return ruleSetBuilder.build();
} catch (ReflectiveOperationException ex) {
ex.printStackTrace();
throw new RuntimeException("Couldn't find the class " + ex.getMessage(), ex);
} catch (ParserConfigurationException | IOException | SAXException ex) {
ex.printStackTrace();
throw new RuntimeException("Couldn't read the ruleset " + ruleSetReferenceId + ": " + ex.getMessage(), ex);
@ -511,7 +491,7 @@ public class RuleSetFactory {
*/
private void parseRuleNode(RuleSetReferenceId ruleSetReferenceId, RuleSetBuilder ruleSetBuilder, Node ruleNode,
boolean withDeprecatedRuleReferences, Set<String> rulesetReferences)
throws ClassNotFoundException, InstantiationException, IllegalAccessException, RuleSetNotFoundException {
throws RuleSetNotFoundException {
Element ruleElement = (Element) ruleNode;
String ref = ruleElement.getAttribute("ref");
if (ref.endsWith("xml")) {
@ -556,7 +536,7 @@ public class RuleSetFactory {
// load the ruleset with minimum priority low, so that we get all rules, to be able to exclude any rule
// minimum priority will be applied again, before constructing the final ruleset
RuleSetFactory ruleSetFactory = new RuleSetFactory(resourceLoader, RulePriority.LOW, false, this.compatibilityFilter != null);
RuleSetFactory ruleSetFactory = toLoader().filterAbovePriority(RulePriority.LOW).warnDeprecated(false).toFactory();
RuleSet otherRuleSet = ruleSetFactory.createRuleSet(RuleSetReferenceId.parse(ref).get(0));
List<RuleReference> potentialRules = new ArrayList<>();
int countDeprecated = 0;
@ -619,7 +599,7 @@ public class RuleSetFactory {
* Must be a rule element node.
*/
private void parseSingleRuleNode(RuleSetReferenceId ruleSetReferenceId, RuleSetBuilder ruleSetBuilder,
Node ruleNode) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Node ruleNode) {
Element ruleElement = (Element) ruleNode;
// Stop if we're looking for a particular Rule, and this element is not
@ -671,7 +651,7 @@ public class RuleSetFactory {
// load the ruleset with minimum priority low, so that we get all rules, to be able to exclude any rule
// minimum priority will be applied again, before constructing the final ruleset
RuleSetFactory ruleSetFactory = new RuleSetFactory(resourceLoader, RulePriority.LOW, false, this.compatibilityFilter != null);
RuleSetFactory ruleSetFactory = toLoader().filterAbovePriority(RulePriority.LOW).warnDeprecated(false).toFactory();
boolean isSameRuleSet = false;
RuleSetReferenceId otherRuleSetReferenceId = RuleSetReferenceId.parse(ref).get(0);
@ -824,4 +804,19 @@ public class RuleSetFactory {
return false;
}
}
/**
* Create a new {@link RuleSetLoader} with the same config as this
* factory. This is a transitional API.
*/
public RuleSetLoader toLoader() {
return new RuleSetLoader().loadResourcesWith(resourceLoader)
.filterAbovePriority(minimumPriority)
.warnDeprecated(warnDeprecated)
.enableCompatibility(compatibilityFilter != null)
.includeDeprecatedRuleReferences(includeDeprecatedRuleReferences);
}
}

View File

@ -18,13 +18,20 @@ import java.util.regex.Pattern;
import org.apache.commons.io.IOUtils;
import net.sourceforge.pmd.annotation.InternalApi;
/**
* Provides a simple filter mechanism to avoid failing to parse an old ruleset,
* which references rules, that have either been removed from PMD already or
* renamed or moved to another ruleset.
*
* @see <a href="https://sourceforge.net/p/pmd/bugs/1360/">issue 1360</a>
*
* @deprecated Use {@link RuleSetLoader#enableCompatibility(boolean)} to enable this feature.
* This implementation is internal API.
*/
@InternalApi
@Deprecated
public class RuleSetFactoryCompatibility {
private static final Logger LOG = Logger.getLogger(RuleSetFactoryCompatibility.class.getName());

View File

@ -0,0 +1,32 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd;
import net.sourceforge.pmd.annotation.InternalApi;
/**
* An exception that is thrown when something wrong occurs while
* {@linkplain RuleSetLoader loading rulesets}. This may be because the
* XML is not well-formed, does not respect the ruleset schema, is
* not a valid ruleset or is otherwise unparsable.
*
* <p>In the new {@link RuleSetLoader} API, this is thrown instead of
* {@link RuleSetNotFoundException}.
*/
public final class RuleSetLoadException extends RuntimeException {
/** Constructors are internal. */
@InternalApi
public RuleSetLoadException(String message, Throwable cause) {
super(message, cause);
}
/** Constructors are internal. */
@InternalApi
public RuleSetLoadException(String message) {
super(message);
}
}

View File

@ -0,0 +1,225 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.util.CollectionUtil;
import net.sourceforge.pmd.util.ResourceLoader;
/**
* Configurable object to load rulesets from XML resources.
* This can be configured using a fluent API, see eg {@link #warnDeprecated(boolean)}.
* To create a new ruleset, use {@link #loadFromResource(String)}
* or some such overload.
*/
public final class RuleSetLoader {
private static final Logger LOG = Logger.getLogger(RuleSetLoader.class.getName());
private ResourceLoader resourceLoader = new ResourceLoader(RuleSetLoader.class.getClassLoader());
private RulePriority minimumPriority = RulePriority.LOW;
private boolean warnDeprecated = true;
private boolean enableCompatibility = true;
private boolean includeDeprecatedRuleReferences = false;
/**
* Specify that the given classloader should be used to resolve
* paths to external ruleset references. The default uses PMD's
* own classpath.
*/
public RuleSetLoader loadResourcesWith(ClassLoader classLoader) {
this.resourceLoader = new ResourceLoader(classLoader);
return this;
}
// internal
RuleSetLoader loadResourcesWith(ResourceLoader loader) {
this.resourceLoader = loader;
return this;
}
/**
* Filter loaded rules to only those that match or are above
* the given priority. The default is {@link RulePriority#LOW},
* ie, no filtering occurs.
*
* @return This instance, modified
*/
public RuleSetLoader filterAbovePriority(RulePriority minimumPriority) {
this.minimumPriority = minimumPriority;
return this;
}
/**
* Log a warning when referencing a deprecated rule.
* This is enabled by default.
*
* @return This instance, modified
*/
public RuleSetLoader warnDeprecated(boolean warn) {
this.warnDeprecated = warn;
return this;
}
/**
* Enable translating old rule references to newer ones, if they have
* been moved or renamed. This is enabled by default, if disabled,
* unresolved references will not be translated and will produce an
* error.
*
* @return This instance, modified
*/
public RuleSetLoader enableCompatibility(boolean enable) {
this.enableCompatibility = enable;
return this;
}
/**
* Follow deprecated rule references. By default this is off,
* and those references will be ignored (with a warning depending
* on {@link #enableCompatibility(boolean)}).
*
* @return This instance, modified
*/
public RuleSetLoader includeDeprecatedRuleReferences(boolean enable) {
this.includeDeprecatedRuleReferences = enable;
return this;
}
/**
* Create a new rule set factory, if you have to (that class is deprecated).
* That factory will use the configuration that was set using the setters of this.
*
* @deprecated {@link RuleSetFactory} is deprecated, replace its usages
* with usages of this class, or of static factory methods of {@link RuleSet}
*/
@Deprecated
public RuleSetFactory toFactory() {
return new RuleSetFactory(
this.resourceLoader,
this.minimumPriority,
this.warnDeprecated,
this.enableCompatibility,
this.includeDeprecatedRuleReferences
);
}
/**
* Parses and returns a ruleset from its location. The location may
* be a file system path, or a resource path (see {@link #loadResourcesWith(ClassLoader)}).
*
* <p>This replaces {@link RuleSetFactory#createRuleSet(String)},
* but does not split commas.
*
* @param rulesetPath A reference to a single ruleset
*
* @throws RuleSetLoadException If any error occurs (eg, invalid syntax, or resource not found)
*/
public RuleSet loadFromResource(String rulesetPath) {
return loadFromResource(new RuleSetReferenceId(rulesetPath));
}
/**
* Parses several resources into a list of rulesets.
*
* @param paths Paths
*
* @throws RuleSetLoadException If any error occurs (eg, invalid syntax, or resource not found),
* for any of the parameters
* @throws NullPointerException If the parameter, or any component is null
*/
public List<RuleSet> loadFromResources(Collection<String> paths) {
List<RuleSet> ruleSets = new ArrayList<>(paths.size());
for (String path : paths) {
ruleSets.add(loadFromResource(path));
}
return ruleSets;
}
/**
* Parses several resources into a list of rulesets.
*
* @param first First path
* @param rest Paths
*
* @throws RuleSetLoadException If any error occurs (eg, invalid syntax, or resource not found),
* for any of the parameters
* @throws NullPointerException If the parameter, or any component is null
*/
public List<RuleSet> loadFromResources(String first, String... rest) {
return loadFromResources(CollectionUtil.listOf(first, rest));
}
// package private
RuleSet loadFromResource(RuleSetReferenceId ruleSetReferenceId) {
try {
return toFactory().createRuleSet(ruleSetReferenceId);
} catch (Exception e) {
throw new RuleSetLoadException("Cannot parse " + ruleSetReferenceId, e);
}
}
/**
* Configure a new ruleset factory builder according to the parameters
* of the given PMD configuration.
*/
public static RuleSetLoader fromPmdConfig(PMDConfiguration configuration) {
return new RuleSetLoader().filterAbovePriority(configuration.getMinimumPriority())
.enableCompatibility(configuration.isRuleSetFactoryCompatibilityEnabled());
}
/**
* Returns an Iterator of RuleSet objects loaded from descriptions from the
* "categories.properties" resource for each language. This
* uses the classpath of the resource loader ({@link #loadResourcesWith(ClassLoader)}).
*
* @return A list of all category rulesets
*
* @throws RuleSetLoadException If a standard ruleset cannot be loaded.
* This is a corner case, that probably should not be caught by clients.
* The standard rulesets are well-formed, at least in stock PMD distributions.
*
*/
public List<RuleSet> getStandardRuleSets() {
String rulesetsProperties;
List<RuleSetReferenceId> ruleSetReferenceIds = new ArrayList<>();
for (Language language : LanguageRegistry.getLanguages()) {
Properties props = new Properties();
rulesetsProperties = "category/" + language.getTerseName() + "/categories.properties";
try (InputStream inputStream = resourceLoader.loadClassPathResourceAsStreamOrThrow(rulesetsProperties)) {
props.load(inputStream);
String rulesetFilenames = props.getProperty("rulesets.filenames");
if (rulesetFilenames != null) {
ruleSetReferenceIds.addAll(RuleSetReferenceId.parse(rulesetFilenames));
}
} catch (RuleSetNotFoundException e) {
LOG.warning("The language " + language.getTerseName() + " provides no " + rulesetsProperties + ".");
} catch (IOException ioe) {
throw new RuntimeException("Couldn't find " + rulesetsProperties
+ "; please ensure that the directory is on the classpath. The current classpath is: "
+ System.getProperty("java.class.path"));
}
}
List<RuleSet> ruleSets = new ArrayList<>();
for (RuleSetReferenceId id : ruleSetReferenceIds) {
ruleSets.add(loadFromResource(id)); // may throw
}
return ruleSets;
}
}

View File

@ -4,10 +4,20 @@
package net.sourceforge.pmd;
/**
* @deprecated This is now only thrown by deprecated apis. {@link RuleSetLoader}
* throws {@link RuleSetLoadException} instead
*/
@Deprecated
public class RuleSetNotFoundException extends Exception {
private static final long serialVersionUID = -4617033110919250810L;
public RuleSetNotFoundException(String msg) {
super(msg);
}
public RuleSetNotFoundException(String msg, Throwable cause) {
super(msg, cause);
}
}

View File

@ -8,9 +8,15 @@ import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import net.sourceforge.pmd.annotation.InternalApi;
/**
* This class represents a reference to RuleSet.
*
* @deprecated This is part of the internals of the {@link RuleSetLoader}.
*/
@Deprecated
@InternalApi
public class RuleSetReference {
private final String ruleSetFileName;
private final boolean allRules;

View File

@ -14,6 +14,7 @@ import java.util.List;
import org.apache.commons.lang3.StringUtils;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.util.ResourceLoader;
/**
@ -78,7 +79,11 @@ import net.sourceforge.pmd.util.ResourceLoader;
* </tr>
* </tbody>
* </table>
*
* @deprecated This is part of the internals of the {@link RuleSetLoader}.
*/
@Deprecated
@InternalApi
public class RuleSetReferenceId {
private final boolean external;
private final String ruleSetFileName;

View File

@ -74,6 +74,11 @@ public class RuleSets {
return ruleSets.toArray(new RuleSet[0]);
}
// internal
List<RuleSet> getRuleSetsInternal() {
return ruleSets;
}
public Iterator<RuleSet> getRuleSetsIterator() {
return ruleSets.iterator();
}

View File

@ -13,6 +13,10 @@ import net.sourceforge.pmd.benchmark.TimedOperation;
import net.sourceforge.pmd.benchmark.TimedOperationCategory;
import net.sourceforge.pmd.util.ResourceLoader;
/**
* @deprecated Use a {@link RuleSetLoader} instead
*/
@Deprecated
public final class RulesetsFactoryUtils {
private static final Logger LOG = Logger.getLogger(RulesetsFactoryUtils.class.getName());
@ -76,7 +80,7 @@ public final class RulesetsFactoryUtils {
}
/**
* @deprecated Use {@link #createFactory(PMDConfiguration)} or {@link #createFactory(PMDConfiguration, ClassLoader)}
* @deprecated Use a {@link RuleSetLoader}
*/
@InternalApi
@Deprecated
@ -96,7 +100,10 @@ public final class RulesetsFactoryUtils {
* @return A ruleset factory
*
* @see #createFactory(PMDConfiguration, ClassLoader)
*
* @deprecated Use {@link RuleSetLoader#fromPmdConfig(PMDConfiguration)}
*/
@Deprecated
public static RuleSetFactory createFactory(final PMDConfiguration configuration) {
return createFactory(configuration, RulesetsFactoryUtils.class.getClassLoader());
}
@ -107,7 +114,7 @@ public final class RulesetsFactoryUtils {
*
* @return A ruleset factory
*
* @see #createFactory(PMDConfiguration, ClassLoader)
* @see RuleSetLoader
*/
public static RuleSetFactory defaultFactory() {
return new RuleSetFactory();
@ -124,7 +131,10 @@ public final class RulesetsFactoryUtils {
* @return A ruleset factory
*
* @see #createFactory(PMDConfiguration)
*
* @deprecated Use a {@link RuleSetLoader}
*/
@Deprecated
public static RuleSetFactory createFactory(final PMDConfiguration configuration, ClassLoader classLoader) {
return createFactory(classLoader,
configuration.getMinimumPriority(),
@ -145,7 +155,10 @@ public final class RulesetsFactoryUtils {
* @return A ruleset factory
*
* @see #createFactory(PMDConfiguration)
*
* @deprecated Use a {@link RuleSetLoader}
*/
@Deprecated
public static RuleSetFactory createFactory(ClassLoader classLoader,
RulePriority minimumPriority,
boolean warnDeprecated,
@ -166,11 +179,13 @@ public final class RulesetsFactoryUtils {
* @return A ruleset factory
*
* @see #createFactory(PMDConfiguration)
*
* @deprecated Use a {@link RuleSetLoader}
*/
@Deprecated
public static RuleSetFactory createFactory(RulePriority minimumPriority,
boolean warnDeprecated,
boolean enableCompatibility) {
return new RuleSetFactory(new ResourceLoader(), minimumPriority, warnDeprecated, enableCompatibility);
}
@ -190,14 +205,16 @@ public final class RulesetsFactoryUtils {
* @return A ruleset factory
*
* @see #createFactory(PMDConfiguration)
* @deprecated Use a {@link RuleSetLoader}
*/
@Deprecated
public static RuleSetFactory createFactory(RulePriority minimumPriority,
boolean warnDeprecated,
boolean enableCompatibility,
boolean includeDeprecatedRuleReferences) {
return new RuleSetFactory(new ResourceLoader(), minimumPriority, warnDeprecated, enableCompatibility,
includeDeprecatedRuleReferences);
includeDeprecatedRuleReferences);
}
/**

View File

@ -10,6 +10,7 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.util.Collections;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.benchmark.TimeTracker;
import net.sourceforge.pmd.benchmark.TimedOperation;
import net.sourceforge.pmd.benchmark.TimedOperationCategory;
@ -21,6 +22,11 @@ import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.ast.ParseException;
import net.sourceforge.pmd.lang.ast.RootNode;
/**
* Source code processor is internal.
*/
@Deprecated
@InternalApi
public class SourceCodeProcessor {
private final PMDConfiguration configuration;

View File

@ -9,11 +9,12 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ContextedRuntimeException;
import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
@ -25,11 +26,9 @@ import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.RulePriority;
import net.sourceforge.pmd.RuleSet;
import net.sourceforge.pmd.RuleSetFactory;
import net.sourceforge.pmd.RuleSetNotFoundException;
import net.sourceforge.pmd.RuleSetLoader;
import net.sourceforge.pmd.RuleSets;
import net.sourceforge.pmd.RulesetsFactoryUtils;
import net.sourceforge.pmd.ant.Formatter;
@ -42,7 +41,6 @@ import net.sourceforge.pmd.renderers.AbstractRenderer;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.util.ClasspathClassLoader;
import net.sourceforge.pmd.util.IOUtil;
import net.sourceforge.pmd.util.ResourceLoader;
import net.sourceforge.pmd.util.datasource.DataSource;
import net.sourceforge.pmd.util.datasource.FileDataSource;
import net.sourceforge.pmd.util.log.AntLogHandler;
@ -106,22 +104,20 @@ public class PMDTaskImpl {
setupClassLoader();
// Setup RuleSetFactory and validate RuleSets
final ResourceLoader rl = setupResourceLoader();
RuleSetFactory ruleSetFactory = RulesetsFactoryUtils.getRulesetFactory(configuration, rl);
RuleSetLoader rulesetLoader = RuleSetLoader.fromPmdConfig(configuration)
.loadResourcesWith(setupResourceLoader());
try {
// This is just used to validate and display rules. Each thread will create its own ruleset
String ruleSets = configuration.getRuleSets();
if (StringUtils.isNotBlank(ruleSets)) {
// Substitute env variables/properties
configuration.setRuleSets(project.replaceProperties(ruleSets));
}
RuleSets rules = ruleSetFactory.createRuleSets(configuration.getRuleSets());
logRulesUsed(rules);
} catch (RuleSetNotFoundException e) {
throw new BuildException(e.getMessage(), e);
// This is just used to validate and display rules. Each thread will create its own ruleset
String ruleSetString = configuration.getRuleSets();
if (StringUtils.isNotBlank(ruleSetString)) {
// Substitute env variables/properties
configuration.setRuleSets(project.replaceProperties(ruleSetString));
}
final RuleSets ruleSets = RulesetsFactoryUtils.getRuleSets(configuration.getRuleSets(), rulesetLoader.toFactory());
List<RuleSet> rulesetList = Arrays.asList(ruleSets.getAllRuleSets());
logRulesUsed(ruleSets);
if (configuration.getSuppressMarker() != null) {
project.log("Setting suppress marker to be " + configuration.getSuppressMarker(), Project.MSG_VERBOSE);
}
@ -137,9 +133,8 @@ public class PMDTaskImpl {
// TODO Do we really need all this in a loop over each FileSet? Seems
// like a lot of redundancy
RuleContext ctx = new RuleContext();
Report errorReport = new Report();
final AtomicInteger reportSize = new AtomicInteger();
int problemCount = 0;
final String separator = System.getProperty("file.separator");
for (FileSet fs : filesets) {
@ -172,10 +167,7 @@ public class PMDTaskImpl {
@Override
public void renderFileReport(Report r) {
int size = r.getViolations().size();
if (size > 0) {
reportSize.addAndGet(size);
}
// Nothing to do
}
@Override
@ -196,13 +188,19 @@ public class PMDTaskImpl {
renderers.add(renderer);
}
try {
PMD.processFiles(configuration, ruleSetFactory, files, ctx, renderers);
Report report = PMD.processFiles(configuration, rulesetList, files, renderers);
problemCount += report.getViolations().size();
} catch (ContextedRuntimeException e) {
if (e.getFirstContextValue("filename") instanceof String) {
handleError((String) e.getFirstContextValue("filename"), errorReport, e);
} else {
handleError("(unknown file)", errorReport, e);
}
} catch (RuntimeException pmde) {
handleError(ctx, errorReport, pmde);
handleError("(unknown file)", errorReport, pmde);
}
}
int problemCount = reportSize.get();
project.log(problemCount + " problems found", Project.MSG_VERBOSE);
for (Formatter formatter : formatters) {
@ -219,7 +217,7 @@ public class PMDTaskImpl {
}
}
private ResourceLoader setupResourceLoader() {
private ClassLoader setupResourceLoader() {
if (classpath == null) {
classpath = new Path(project);
}
@ -236,11 +234,11 @@ public class PMDTaskImpl {
// are loaded twice
// and exist in multiple class loaders
final boolean parentFirst = true;
return new ResourceLoader(new AntClassLoader(Thread.currentThread().getContextClassLoader(),
project, classpath, parentFirst));
return new AntClassLoader(Thread.currentThread().getContextClassLoader(),
project, classpath, parentFirst);
}
private void handleError(RuleContext ctx, Report errorReport, RuntimeException pmde) {
private void handleError(String filename, Report errorReport, RuntimeException pmde) {
pmde.printStackTrace();
project.log(pmde.toString(), Project.MSG_VERBOSE);
@ -263,7 +261,7 @@ public class PMDTaskImpl {
if (failOnError) {
throw new BuildException(pmde);
}
errorReport.addError(new Report.ProcessingError(pmde, String.valueOf(ctx.getSourceCodeFile())));
errorReport.addError(new Report.ProcessingError(pmde, filename));
}
private void setupClassLoader() {
@ -282,6 +280,10 @@ public class PMDTaskImpl {
final ScopedLogHandlersManager logManager = new ScopedLogHandlersManager(antLogHandler.getAntLogLevel(), antLogHandler);
try {
doTask();
} catch (BuildException e) {
throw e;
} catch (Exception other) {
throw new BuildException(other);
} finally {
logManager.close();
// only close the classloader, if it is ours. Otherwise we end up with class not found

View File

@ -9,6 +9,7 @@ import java.util.stream.Collectors;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.PMDVersion;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.properties.PropertyDescriptor;
@ -21,7 +22,10 @@ import com.beust.jcommander.ParameterException;
/**
* @author Romain Pelisse &lt;belaran@gmail.com&gt;
*
* @deprecated Internal API. Use {@link PMD#run(String[])} or {@link PMD#main(String[])}
*/
@Deprecated
@InternalApi
public final class PMDCommandLineInterface {
public static final String PROG_NAME = "pmd";

View File

@ -11,8 +11,10 @@ import java.util.Properties;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.RulePriority;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.lang.LanguageVersion;
@ -23,6 +25,11 @@ import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParameterException;
import com.beust.jcommander.validators.PositiveInteger;
/**
* @deprecated Internal API. Use {@link PMD#run(String[])} or {@link PMD#main(String[])}
*/
@Deprecated
@InternalApi
public class PMDParameters {
@Parameter(names = { "-rulesets", "-R" }, description = "Comma separated list of ruleset names to use.",

View File

@ -12,6 +12,7 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.exception.ContextedRuntimeException;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.Report;
@ -21,6 +22,7 @@ import net.sourceforge.pmd.RuleSetFactory;
import net.sourceforge.pmd.RuleSets;
import net.sourceforge.pmd.RulesetsFactoryUtils;
import net.sourceforge.pmd.SourceCodeProcessor;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.benchmark.TimeTracker;
import net.sourceforge.pmd.benchmark.TimedOperation;
import net.sourceforge.pmd.benchmark.TimedOperationCategory;
@ -30,7 +32,10 @@ import net.sourceforge.pmd.util.datasource.DataSource;
/**
* @author Romain Pelisse &lt;belaran@gmail.com&gt;
*
* @deprecated Is internal API
*/
@Deprecated
@InternalApi
public abstract class AbstractPMDProcessor {
private static final Logger LOG = Logger.getLogger(AbstractPMDProcessor.class.getName());
@ -75,13 +80,15 @@ public abstract class AbstractPMDProcessor {
*/
protected RuleSets createRuleSets(RuleSetFactory factory, Report report) {
final RuleSets rs = RulesetsFactoryUtils.getRuleSets(configuration.getRuleSets(), factory);
reportBrokenRules(report, rs);
return rs;
}
public static void reportBrokenRules(Report report, RuleSets rs) {
final Set<Rule> brokenRules = removeBrokenRules(rs);
for (final Rule rule : brokenRules) {
report.addConfigError(new Report.ConfigurationError(rule, rule.dysfunctionReason()));
}
return rs;
}
/**
@ -91,7 +98,7 @@ public abstract class AbstractPMDProcessor {
* @param ruleSets RuleSets to prune of broken rules.
* @return Set<Rule>
*/
private Set<Rule> removeBrokenRules(final RuleSets ruleSets) {
private static Set<Rule> removeBrokenRules(final RuleSets ruleSets) {
final Set<Rule> brokenRules = new HashSet<>();
ruleSets.removeDysfunctionalRules(brokenRules);
@ -105,28 +112,37 @@ public abstract class AbstractPMDProcessor {
return brokenRules;
}
@Deprecated
public void processFiles(RuleSetFactory ruleSetFactory, List<DataSource> files, RuleContext ctx,
List<Renderer> renderers) {
RuleSets rs = createRuleSets(ruleSetFactory, ctx.getReport());
processFiles(rs, files, ctx, renderers);
}
@SuppressWarnings("PMD.CloseResource")
// the data sources must only be closed after the threads are finished
// this is done manually without a try-with-resources
public void processFiles(RuleSetFactory ruleSetFactory, List<DataSource> files, RuleContext ctx,
List<Renderer> renderers) {
public void processFiles(RuleSets rulesets, List<DataSource> files, RuleContext ctx, List<Renderer> renderers) {
try {
final RuleSets rs = createRuleSets(ruleSetFactory, ctx.getReport());
configuration.getAnalysisCache().checkValidity(rs, configuration.getClassLoader());
reportBrokenRules(ctx.getReport(), rulesets);
// render base report first - general errors
renderReports(renderers, ctx.getReport());
configuration.getAnalysisCache().checkValidity(rulesets, configuration.getClassLoader());
final SourceCodeProcessor processor = new SourceCodeProcessor(configuration);
for (final DataSource dataSource : files) {
// this is the real, canonical and absolute filename (not shortened)
String realFileName = dataSource.getNiceFileName(false, null);
runAnalysis(new PmdRunnable(dataSource, realFileName, renderers, ctx, rs, processor));
runAnalysis(new PmdRunnable(dataSource, realFileName, renderers, ctx, rulesets, processor));
}
// render base report first - general errors
renderReports(renderers, ctx.getReport());
// then add analysis results per file
collectReports(renderers);
} catch (RuntimeException e) {
throw new ContextedRuntimeException(e).addContextValue("filename", String.valueOf(ctx.getSourceCodeFile()));
} finally {
// in case we analyzed files within Zip Files/Jars, we need to close them after
// the analysis is finished

View File

@ -9,12 +9,15 @@ import java.util.List;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.renderers.Renderer;
/**
* @author Romain Pelisse &lt;belaran@gmail.com&gt;
*
* @deprecated Is internal API
*/
@Deprecated
@InternalApi
public final class MonoThreadProcessor extends AbstractPMDProcessor {
private final List<Report> reports = new ArrayList<>();

View File

@ -13,12 +13,16 @@ import java.util.concurrent.Executors;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.renderers.Renderer;
/**
* @author Romain Pelisse &lt;belaran@gmail.com&gt;
* @deprecated Is internal API
*/
@Deprecated
@InternalApi
public class MultiThreadProcessor extends AbstractPMDProcessor {
private final ExecutorService executor;
private final CompletionService<Report> completionService;

View File

@ -17,10 +17,17 @@ import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.RuleSets;
import net.sourceforge.pmd.SourceCodeProcessor;
import net.sourceforge.pmd.annotation.InternalApi;
import net.sourceforge.pmd.benchmark.TimeTracker;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.util.datasource.DataSource;
/**
*
* @deprecated Is internal API
*/
@Deprecated
@InternalApi
public class PmdRunnable implements Callable<Report> {
private static final Logger LOG = Logger.getLogger(PmdRunnable.class.getName());
@ -86,6 +93,9 @@ public class PmdRunnable implements Callable<Report> {
TimeTracker.finishThread();
// merge the sub-report into the global report (thread-safe)
ruleContext.getReport().merge(report);
return report;
}

View File

@ -7,6 +7,14 @@ package net.sourceforge.pmd.processor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicInteger;
import net.sourceforge.pmd.annotation.InternalApi;
/**
*
* @deprecated Is internal API
*/
@Deprecated
@InternalApi
public class PmdThreadFactory implements ThreadFactory {
private final AtomicInteger counter = new AtomicInteger();

View File

@ -495,40 +495,40 @@ public class RuleSetFactoryTest {
@Test
public void testReferencePriority() throws RuleSetNotFoundException {
ResourceLoader rl = new ResourceLoader();
RuleSetFactory rsf = new RuleSetFactory(rl, RulePriority.LOW, false, true);
RuleSetLoader config = new RuleSetLoader().warnDeprecated(false).enableCompatibility(true);
RuleSetFactory rsf = config.filterAbovePriority(RulePriority.LOW).toFactory();
RuleSet ruleSet = rsf.createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_INTERNAL_CHAIN));
assertEquals("Number of Rules", 3, ruleSet.getRules().size());
assertNotNull(ruleSet.getRuleByName("MockRuleName"));
assertNotNull(ruleSet.getRuleByName("MockRuleNameRef"));
assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef"));
rsf = new RuleSetFactory(rl, RulePriority.MEDIUM_HIGH, false, true);
rsf = config.filterAbovePriority(RulePriority.MEDIUM_HIGH).toFactory();
ruleSet = rsf.createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_INTERNAL_CHAIN));
assertEquals("Number of Rules", 2, ruleSet.getRules().size());
assertNotNull(ruleSet.getRuleByName("MockRuleNameRef"));
assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef"));
rsf = new RuleSetFactory(rl, RulePriority.HIGH, false, true);
rsf = config.filterAbovePriority(RulePriority.HIGH).toFactory();
ruleSet = rsf.createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_INTERNAL_CHAIN));
assertEquals("Number of Rules", 1, ruleSet.getRules().size());
assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef"));
rsf = new RuleSetFactory(rl, RulePriority.LOW, false, true);
rsf = config.filterAbovePriority(RulePriority.LOW).toFactory();
ruleSet = rsf.createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_EXTERNAL_CHAIN));
assertEquals("Number of Rules", 3, ruleSet.getRules().size());
assertNotNull(ruleSet.getRuleByName("ExternalRefRuleName"));
assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRef"));
assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef"));
rsf = new RuleSetFactory(rl, RulePriority.MEDIUM_HIGH, false, true);
rsf = config.filterAbovePriority(RulePriority.MEDIUM_HIGH).toFactory();
ruleSet = rsf.createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_EXTERNAL_CHAIN));
assertEquals("Number of Rules", 2, ruleSet.getRules().size());
assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRef"));
assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef"));
rsf = new RuleSetFactory(rl, RulePriority.HIGH, false, true);
rsf = config.filterAbovePriority(RulePriority.HIGH).toFactory();
ruleSet = rsf.createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_EXTERNAL_CHAIN));
assertEquals("Number of Rules", 1, ruleSet.getRules().size());
assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef"));
@ -536,7 +536,7 @@ public class RuleSetFactoryTest {
@Test
public void testOverridePriorityLoadWithMinimum() throws RuleSetNotFoundException {
RuleSetFactory rsf = new RuleSetFactory(new ResourceLoader(), RulePriority.MEDIUM_LOW, true, true);
RuleSetFactory rsf = new RuleSetLoader().filterAbovePriority(RulePriority.MEDIUM_LOW).warnDeprecated(true).enableCompatibility(true).toFactory();
RuleSet ruleset = rsf.createRuleSet("net/sourceforge/pmd/rulesets/ruleset-minimum-priority.xml");
// only one rule should remain, since we filter out the other rule by minimum priority
assertEquals("Number of Rules", 1, ruleset.getRules().size());
@ -557,13 +557,13 @@ public class RuleSetFactoryTest {
@Test
public void testExcludeWithMinimumPriority() throws RuleSetNotFoundException {
RuleSetFactory rsf = RulesetsFactoryUtils.createFactory(RulePriority.HIGH, true, true);
RuleSetFactory rsf = new RuleSetLoader().filterAbovePriority(RulePriority.HIGH).toFactory();
RuleSet ruleset = rsf.createRuleSet("net/sourceforge/pmd/rulesets/ruleset-minimum-priority-exclusion.xml");
// no rules should be loaded
assertEquals("Number of Rules", 0, ruleset.getRules().size());
// now, load with default minimum priority
rsf = RulesetsFactoryUtils.defaultFactory();
rsf = new RuleSetLoader().filterAbovePriority(RulePriority.LOW).toFactory();
ruleset = rsf.createRuleSet("net/sourceforge/pmd/rulesets/ruleset-minimum-priority-exclusion.xml");
// only one rule, we have excluded one...
assertEquals("Number of Rules", 1, ruleset.getRules().size());
@ -592,10 +592,9 @@ public class RuleSetFactoryTest {
@Test
public void testSetPriority() throws RuleSetNotFoundException {
ResourceLoader rl = new ResourceLoader();
RuleSetFactory rsf = new RuleSetFactory(rl, RulePriority.MEDIUM_HIGH, false, true);
RuleSetFactory rsf = new RuleSetLoader().filterAbovePriority(RulePriority.MEDIUM_HIGH).warnDeprecated(false).toFactory();
assertEquals(0, rsf.createRuleSet(createRuleSetReferenceId(SINGLE_RULE)).size());
rsf = new RuleSetFactory(rl, RulePriority.MEDIUM_LOW, false, true);
rsf = new RuleSetLoader().filterAbovePriority(RulePriority.MEDIUM_LOW).warnDeprecated(false).toFactory();
assertEquals(1, rsf.createRuleSet(createRuleSetReferenceId(SINGLE_RULE)).size());
}
@ -774,7 +773,7 @@ public class RuleSetFactoryTest {
+ " <description>Ruleset which references a empty ruleset</description>\n" + "\n"
+ " <rule ref=\"rulesets/dummy/empty-ruleset.xml\" />\n"
+ "</ruleset>\n");
RuleSetFactory ruleSetFactory = new RuleSetFactory(new ResourceLoader(), RulePriority.LOW, true, true);
RuleSetFactory ruleSetFactory = new RuleSetLoader().loadResourcesWith(new ResourceLoader()).filterAbovePriority(RulePriority.LOW).warnDeprecated(true).enableCompatibility(true).toFactory();
RuleSet ruleset = ruleSetFactory.createRuleSet(ref);
assertEquals(0, ruleset.getRules().size());
@ -1279,7 +1278,7 @@ public class RuleSetFactoryTest {
}
private RuleSet loadRuleSetWithDeprecationWarnings(String ruleSetXml) throws RuleSetNotFoundException {
RuleSetFactory rsf = RulesetsFactoryUtils.createFactory(RulePriority.LOW, true, false);
RuleSetFactory rsf = new RuleSetLoader().warnDeprecated(true).enableCompatibility(false).toFactory();
return rsf.createRuleSet(createRuleSetReferenceId(ruleSetXml));
}

View File

@ -77,21 +77,21 @@ public class RuleSetTest {
@Test
public void testGetRuleByName() {
MockRule mock = new MockRule("name", "desc", "msg", "rulesetname");
RuleSet rs = RulesetsFactoryUtils.defaultFactory().createSingleRuleRuleSet(mock);
RuleSet rs = RuleSet.forSingleRule(mock);
assertEquals("unable to fetch rule by name", mock, rs.getRuleByName("name"));
}
@Test
public void testGetRuleByName2() {
MockRule mock = new MockRule("name", "desc", "msg", "rulesetname");
RuleSet rs = RulesetsFactoryUtils.defaultFactory().createSingleRuleRuleSet(mock);
RuleSet rs = RuleSet.forSingleRule(mock);
assertNull("the rule FooRule must not be found!", rs.getRuleByName("FooRule"));
}
@Test
public void testRuleList() {
MockRule rule = new MockRule("name", "desc", "msg", "rulesetname");
RuleSet ruleset = RulesetsFactoryUtils.defaultFactory().createSingleRuleRuleSet(rule);
RuleSet ruleset = RuleSet.forSingleRule(rule);
assertEquals("Size of RuleSet isn't one.", 1, ruleset.size());

View File

@ -81,7 +81,7 @@ public class RuleSetWriterTest {
ruleRef.setRuleSetReference(ruleSetReference);
ruleRef.setName("Foo"); // override the name
RuleSet ruleSet = ruleSetFactory.createSingleRuleRuleSet(ruleRef);
RuleSet ruleSet = RuleSet.forSingleRule(ruleRef);
writer.write(ruleSet);

Some files were not shown because too many files have changed in this diff Show More