forked from phoedos/pmd
Merge branch 'master' into pmd/7.0.x
This commit is contained in:
commit
384d32ddd0
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -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
|
||||
|
14
.github/ISSUE_TEMPLATE/question.md
vendored
14
.github/ISSUE_TEMPLATE/question.md
vendored
@ -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:**
|
||||
|
@ -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)
|
||||
|
@ -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 %}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
225
pmd-core/src/main/java/net/sourceforge/pmd/RuleSetLoader.java
Normal file
225
pmd-core/src/main/java/net/sourceforge/pmd/RuleSetLoader.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 <belaran@gmail.com>
|
||||
*
|
||||
* @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";
|
||||
|
@ -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.",
|
||||
|
@ -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 <belaran@gmail.com>
|
||||
*
|
||||
* @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
|
||||
|
@ -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 <belaran@gmail.com>
|
||||
*
|
||||
* @deprecated Is internal API
|
||||
*/
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public final class MonoThreadProcessor extends AbstractPMDProcessor {
|
||||
|
||||
private final List<Report> reports = new ArrayList<>();
|
||||
|
@ -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 <belaran@gmail.com>
|
||||
* @deprecated Is internal API
|
||||
*/
|
||||
@Deprecated
|
||||
@InternalApi
|
||||
public class MultiThreadProcessor extends AbstractPMDProcessor {
|
||||
private final ExecutorService executor;
|
||||
private final CompletionService<Report> completionService;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user