Merge branch 'master' into pmd7-textfile-display-name

This commit is contained in:
Clément Fournier 2023-05-02 17:12:36 +02:00
commit ac86bb21dc
No known key found for this signature in database
GPG Key ID: 4D8D42402E4F47E2
59 changed files with 1482 additions and 1931 deletions

View File

@ -3,7 +3,7 @@ repository: pmd/pmd
pmd:
version: 7.0.0-SNAPSHOT
previous_version: 6.55.0
date: ??-????-2023
date: 27-May-2023
release_type: major
# release types: major, minor, bugfix

View File

@ -9,10 +9,7 @@ author: Tom Copeland, Andreas Dangel <andreas.dangel@adangel.org>
## Overview
The processing starts e.g. with the main class: `net.sourceforge.pmd.PMD`
{%include note.html content="This is the command line interface. There are many other means, who
PMD can be invoked. E.g. via ant, maven, gradle..." %}
The processing starts with the main class {% jdoc core::PmdAnalysis %}.
* Parse command line parameters (see net.sourceforge.pmd.cli.PMDParameters)
Also load the incremental analysis cache file

View File

@ -192,8 +192,7 @@ then the violation will be suppressed. Note that the query shouldn't be finding
the violation nodes to suppress, but rather, finding a non-empty sequence of nodes
when evaluated with the violation node as a context node.
The XPath version used by those queries is XPath 1.0, so it doesn't support various XPath 2.0
features. This will be updated with PMD 7.0.0.
The XPath version used by those queries is XPath 3.1 since PMD 7. Before then XPath 1.0 was used.
For example, to suppress reporting specifically "String" parameters which are unused:

View File

@ -30,186 +30,6 @@ Note: You'll need to select a specific version. This is done in the example via
This will transitively pull in the artifact `pmd-core` which contains the API.
## Command line interface
The easiest way is to call PMD with the same interface as from command line. The main class is
`net.sourceforge.pmd.PMD`:
``` java
import net.sourceforge.pmd.PMD;
public class Example {
public static void main(String[] args) {
String[] pmdArgs = {
"-d", "/home/workspace/src/main/java/code",
"-R", "rulesets/java/quickstart.xml",
"-f", "xml",
"-r", "/home/workspace/pmd-report.xml"
};
PMD.main(pmdArgs);
}
}
```
It uses the same options as described in [PMD CLI reference](pmd_userdocs_cli_reference.html).
## Programmatically, variant 1
This is very similar:
``` java
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.PMDConfiguration;
public class PmdExample {
public static void main(String[] args) {
PMDConfiguration configuration = new PMDConfiguration();
configuration.setInputPaths("/home/workspace/src/main/java/code");
configuration.addRuleSet("rulesets/java/quickstart.xml");
configuration.setReportFormat("xml");
configuration.setReportFile("/home/workspace/pmd-report.xml");
PMD.runPmd(configuration);
}
}
```
## Programmatically, variant 2
This gives you more control over which files are processed, but is also more complicated.
You can also provide your own custom renderers.
1. First we create a `PMDConfiguration` and configure it, first the rules:
```java
PMDConfiguration configuration = new PMDConfiguration();
configuration.setMinimumPriority(RulePriority.MEDIUM);
configuration.addRuleSet("rulesets/java/quickstart.xml");
```
2. Then we configure, which paths to analyze:
```java
configuration.setInputPaths("/home/workspace/src/main/java/code");
```
3. The we configure the default language version for Java. And in order to support type resolution,
PMD needs to have access to the compiled classes and dependencies as well. This is called
"auxclasspath" and is also configured here.
Note: you can specify multiple class paths separated by `:` on Unix-systems or `;` under Windows.
```java
configuration.setDefaultLanguageVersion(LanguageRegistry.findLanguageByTerseName("java").getVersion("11"));
configuration.prependAuxClasspath("/home/workspace/target/classes:/home/.m2/repository/my/dependency.jar");
```
4. Then we configure the reporting. Configuring the report file is optional. If not specified, the report
will be written to `stdout`.
```java
configuration.setReportFormat("xml");
configuration.setReportFile("/home/workspace/pmd-report.xml");
```
5. Now an optional step: If you want to use additional renderers as in the example, set them up before
calling PMD. You can use a built-in renderer, e.g. `XMLRenderer` or a custom renderer implementing
`Renderer`. Note, that you must manually initialize the renderer by setting a suitable `Writer`:
```java
Writer rendererOutput = new StringWriter();
Renderer renderer = createRenderer(rendererOutput);
// ...
private static Renderer createRenderer(Writer writer) {
XMLRenderer xml = new XMLRenderer("UTF-8");
xml.setWriter(writer);
return xml;
}
```
6. Finally we can start the PMD analysis. There is the possibility to fine-tune the configuration
by adding additional files to analyze or adding additional rulesets or renderers:
```java
try (PmdAnalysis pmd = PmdAnalysis.create(configuration)) {
// optional: add more rulesets
pmd.addRuleSet(pmd.newRuleSetLoader().loadFromResource("custom-ruleset.xml"));
// optional: add more files
pmd.files().addFile(Paths.get("src", "main", "more-java", "ExtraSource.java"));
// optional: add more renderers
pmd.addRenderer(renderer);
// or just call PMD
pmd.performAnalysis();
}
```
The renderer will be automatically flushed and closed at the end of the analysis.
7. Then you can check the rendered output.
``` java
System.out.println("Rendered Report:");
System.out.println(rendererOutput.toString());
```
Here is a complete example:
``` java
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.file.Paths;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.PmdAnalysis;
import net.sourceforge.pmd.RulePriority;
import net.sourceforge.pmd.lang.LanguageRegistry;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.renderers.XMLRenderer;
public class PmdExample2 {
public static void main(String[] args) throws IOException {
PMDConfiguration configuration = new PMDConfiguration();
configuration.setMinimumPriority(RulePriority.MEDIUM);
configuration.addRuleSet("rulesets/java/quickstart.xml");
configuration.setInputPaths("/home/workspace/src/main/java/code");
configuration.setDefaultLanguageVersion(LanguageRegistry.findLanguageByTerseName("java").getVersion("11"));
configuration.prependAuxClasspath("/home/workspace/target/classes");
configuration.setReportFormat("xml");
configuration.setReportFile("/home/workspace/pmd-report.xml");
Writer rendererOutput = new StringWriter();
Renderer renderer = createRenderer(rendererOutput);
try (PmdAnalysis pmd = PmdAnalysis.create(configuration)) {
// optional: add more rulesets
pmd.addRuleSet(pmd.newRuleSetLoader().loadFromResource("custom-ruleset.xml"));
// optional: add more files
pmd.files().addFile(Paths.get("src", "main", "more-java", "ExtraSource.java"));
// optional: add more renderers
pmd.addRenderer(renderer);
// or just call PMD
pmd.performAnalysis();
}
System.out.println("Rendered Report:");
System.out.println(rendererOutput.toString());
}
private static Renderer createRenderer(Writer writer) {
XMLRenderer xml = new XMLRenderer("UTF-8");
xml.setWriter(writer);
return xml;
}
}
```
## Running PMD programmatically
The programmatic API for PMD is centered around {% jdoc core::PmdAnalysis %}, please see the javadocs for usage information.

View File

@ -34,64 +34,10 @@ for all.</p>
{% tocmaker is_release_notes_processor %}
### Changes since 7.0.0-rc1
### Changes since 7.0.0-rc2
This section lists the most important changes from the last release candidate.
The remaining section describe the complete release notes for 7.0.0.
#### API Changes
* Moved the two classes {% jdoc core::cpd.impl.AntlrTokenizer %} and {% jdoc core::cpd.impl.JavaCCTokenizer %} from
`internal` package into package {% jdoc_package core::cpd.impl %}. These two classes are part of the API and
are base classes for CPD language implementations.
* `AntlrBaseRule` is gone in favor of {% jdoc core::lang.rule.AbstractVisitorRule %}.
* The classes {% jdoc kotlin::lang.kotlin.ast.KotlinInnerNode %} and {% jdoc swift::lang.swift.ast.SwiftInnerNode %}
are package-private now.
* The parameter order of {% jdoc core::lang.document.FileCollector#addSourceFile(String, String) %} has been swapped
in order to have the same meaning as in 6.55.0. That will make it easier if you upgrade from 6.55.0 to 7.0.0.
However, that means, that you need to change these method calls if you have migrated to 7.0.0-rc1 already.
#### Updated PMD Designer
This PMD release ships a new version of the pmd-designer.
For the changes, see [PMD Designer Changelog](https://github.com/pmd/pmd-designer/releases/tag/7.0.0-rc1).
#### Rule Changes
* {% rule "java/design/ImmutableField" %}: the property `ignoredAnnotations` has been removed. The property was
deprecated since PMD 6.52.0.
#### Fixed Issues
* cli
* [#4482](https://github.com/pmd/pmd/issues/4482): \[cli] pmd.bat can only be executed once
* [#4484](https://github.com/pmd/pmd/issues/4484): \[cli] ast-dump with no properties produce an NPE
* core
* [#2500](https://github.com/pmd/pmd/issues/2500): \[core] Clarify API for ANTLR based languages
* doc
* [#2501](https://github.com/pmd/pmd/issues/2501): \[doc] Verify ANTLR Documentation
* [#4438](https://github.com/pmd/pmd/issues/4438): \[doc] Documentation links in VS Code are outdated
* java-codestyle
* [#4273](https://github.com/pmd/pmd/issues/4273): \[java] CommentDefaultAccessModifier ignoredAnnotations should include "org.junit.jupiter.api.extension.RegisterExtension" by default
* [#4487](https://github.com/pmd/pmd/issues/4487): \[java] UnnecessaryConstructor: false-positive with @<!-- -->Inject and @<!-- -->Autowired
* java-design
* [#4254](https://github.com/pmd/pmd/issues/4254): \[java] ImmutableField - false positive with Lombok @<!-- -->Setter
* [#4477](https://github.com/pmd/pmd/issues/4477): \[java] SignatureDeclareThrowsException: false-positive with TestNG annotations
* [#4490](https://github.com/pmd/pmd/issues/4490): \[java] ImmutableField - false negative with Lombok @<!-- -->Getter
* java-errorprone
* [#4449](https://github.com/pmd/pmd/issues/4449): \[java] AvoidAccessibilityAlteration: Possible false positive in AvoidAccessibilityAlteration rule when using Lambda expression
* [#4493](https://github.com/pmd/pmd/issues/4493): \[java] MissingStaticMethodInNonInstantiatableClass: false-positive about @<!-- -->Inject
* [#4505](https://github.com/pmd/pmd/issues/4505): \[java] ImplicitSwitchFallThrough NPE in PMD 7.0.0-rc1
* java-multithreading
* [#4483](https://github.com/pmd/pmd/issues/4483): \[java] NonThreadSafeSingleton false positive with double-checked locking
* miscellaneous
* [#4462](https://github.com/pmd/pmd/issues/4462): Provide Software Bill of Materials (SBOM)
#### External contributions
* [#4444](https://github.com/pmd/pmd/pull/4444): \[java] CommentDefaultAccessModifier - ignore org.junit.jupiter.api.extension.RegisterExtension by default - [Nirvik Patel](https://github.com/nirvikpatel) (@nirvikpatel)
* [#4450](https://github.com/pmd/pmd/pull/4450): \[java] Fix #4449 AvoidAccessibilityAlteration: Correctly handle Lambda expressions in PrivilegedAction scenarios - [Seren](https://github.com/mohui1999) (@mohui1999)
* [#4452](https://github.com/pmd/pmd/pull/4452): \[doc] Update PMD_APEX_ROOT_DIRECTORY documentation reference - [nwcm](https://github.com/nwcm) (@nwcm)
* [#4474](https://github.com/pmd/pmd/pull/4474): \[java] ImmutableField: False positive with lombok (fixes #4254) - [Pim van der Loos](https://github.com/PimvanderLoos) (@PimvanderLoos)
* [#4488](https://github.com/pmd/pmd/pull/4488): \[java] Fix #4477: A false-positive about SignatureDeclareThrowsException - [AnnaDev](https://github.com/LynnBroe) (@LynnBroe)
* [#4494](https://github.com/pmd/pmd/pull/4494): \[java] Fix #4487: A false-positive about UnnecessaryConstructor and @<!-- -->Inject and @<!-- -->Autowired - [AnnaDev](https://github.com/LynnBroe) (@LynnBroe)
* [#4495](https://github.com/pmd/pmd/pull/4495): \[java] Fix #4493: false-positive about MissingStaticMethodInNonInstantiatableClass and @<!-- -->Inject - [AnnaDev](https://github.com/LynnBroe) (@LynnBroe)
* [#4520](https://github.com/pmd/pmd/pull/4520): \[doc] Fix typo: missing closing quotation mark after CPD-END - [João Dinis Ferreira](https://github.com/joaodinissf) (@joaodinissf)
The remaining section describes the complete release notes for 7.0.0.
### 🚀 Major Features and Enhancements
@ -214,33 +160,116 @@ Contributors: [Wener](https://github.com/wener-tiobe) (@wener-tiobe)
#### Changed Rules
**Java**
**General changes**
* {% rule "java/codestyle/UnnecessaryFullyQualifiedName" %}: the rule has two new properties,
* All statistical rules (like ExcessiveClassLength, ExcessiveParameterList) have been simplified and unified.
The properties `topscore` and `sigma` have been removed. The property `minimum` is still there, however the type is not
a decimal number anymore but has been changed to an integer. This affects rules in the languages Apex, Java, PLSQL
and Velocity Template Language (vm):
* Apex: {% rule apex/design/ExcessiveClassLength %}, {% rule apex/design/ExcessiveParameterList %},
{% rule apex/design/ExcessivePublicCount %}, {% rule apex/design/NcssConstructorCount %},
{% rule apex/design/NcssMethodCount %}, {% rule apex/design/NcssTypeCount %}
* Java: {% rule java/design/ExcessiveImports %}, {% rule java/design/ExcessiveParameterList %},
{% rule java/design/ExcessivePublicCount %}, {% rule java/design/SwitchDensity %}
* PLSQL: {% rule plsql/design/ExcessiveMethodLength %}, {% rule plsql/design/ExcessiveObjectLength %},
{% rule plsql/design/ExcessivePackageBodyLength %}, {% rule plsql/design/ExcessivePackageSpecificationLength %},
{% rule plsql/design/ExcessiveParameterList %}, {% rule plsql/design/ExcessiveTypeLength %},
{% rule plsql/design/NcssMethodCount %}, {% rule plsql/design/NcssObjectCount %},
{% rule plsql/design/NPathComplexity %}
* VM: {% rule vm/design/ExcessiveTemplateLength %}
* The general property `violationSuppressXPath` which is available for all rules to
[suppress warnings]({{ baseurl }}pmd_userdocs_suppressing_warnings.html) now uses XPath version 3.1 by default.
This version of the XPath language is mostly identical to XPath 2.0. In PMD 6, XPath 1.0 has been used.
If you upgrade from PMD 6, you need to verify your `violationSuppressXPath` properties.
**Apex General changes**
* The properties `cc_categories`, `cc_remediation_points_multiplier`, `cc_block_highlighting` have been removed
from all rules. These properties have been deprecated since PMD 6.13.0.
See [issue #1648](https://github.com/pmd/pmd/issues/1648) for more details.
**Java General changes**
* Violations reported on methods or classes previously reported the line range of the entire method
or class. With PMD 7.0.0, the reported location is now just the identifier of the method or class.
This affects various rules, e.g. {% rule java/design/CognitiveComplexity %}.
The report location is controlled by the overrides of the method {% jdoc core::lang.ast.Node#getReportLocation() %}
in different node types.
See [issue #4439](https://github.com/pmd/pmd/issues/4439) and [issue #730](https://github.com/pmd/pmd/issues/730)
for more details.
**Java Best Practices**
* {% rule java/bestpractices/ArrayIsStoredDirectly %}: Violations are now reported on the assignment and not
anymore on the formal parameter. The reported line numbers will probably move.
* {% rule java/bestpractices/AvoidReassigningLoopVariables %}: This rule might not report anymore all
reassignments of the control variable in for-loops when the property `forReassign` is set to `skip`.
See [issue #4500](https://github.com/pmd/pmd/issues/4500) for more details.
* {% rule java/bestpractices/LooseCoupling %}: The rule has a new property to allow some types to be coupled
to (`allowedTypes`).
* {% rule java/bestpractices/UnusedLocalVariable %}: This rule has some important false-negatives fixed
and finds many more cases now. For details see issues [#2130](https://github.com/pmd/pmd/issues/2130),
[#4516](https://github.com/pmd/pmd/issues/4516), and [#4517](https://github.com/pmd/pmd/issues/4517).
**Java Codestyle**
* {% rule java/codestyle/MethodNamingConventions %}: The property `checkNativeMethods` has been removed. The
property was deprecated since PMD 6.3.0. Use the property `nativePattern` to control whether native methods
should be considered or not.
* {% rule java/codestyle/ShortVariable %}: This rule now also reports short enum constant names.
* {% rule java/codestyle/UseDiamondOperator %}: The property `java7Compatibility` has been removed. The rule now
handles Java 7 properly without a property.
* {% rule java/codestyle/UnnecessaryFullyQualifiedName %}: The rule has two new properties,
to selectively disable reporting on static field and method qualifiers. The rule also has been improved
to be more precise.
* {% rule "java/codestyle/UselessParentheses" %}: the rule has two new properties which control how strict
* {% rule java/codestyle/UselessParentheses %}: The rule has two new properties which control how strict
the rule should be applied. With `ignoreClarifying` (default: true) parentheses that are strictly speaking
not necessary are allowed, if they separate expressions of different precedence.
The other property `ignoreBalancing` (default: true) is similar, in that it allows parentheses that help
reading and understanding the expressions.
* {% rule "java/bestpractices/LooseCoupling" %}: the rule has a new property to allow some types to be coupled
to (`allowedTypes`).
* {% rule "java/errorprone/EmptyCatchBlock" %}: `CloneNotSupportedException` and `InterruptedException` are not
special-cased anymore. Rename the exception parameter to `ignored` to ignore them.
* {% rule "java/errorprone/DontImportSun" %}: `sun.misc.Signal` is not special-cased anymore.
* {% rule "java/codestyle/UseDiamondOperator" %}: the property `java7Compatibility` is removed. The rule now
handles Java 7 properly without a property.
* {% rule "java/design/SingularField" %}: Properties `checkInnerClasses` and `disallowNotAssignment` are removed.
The rule is now more precise and will check these cases properly.
* {% rule "java/design/UseUtilityClass" %}: The property `ignoredAnnotations` has been removed.
* {% rule "java/design/LawOfDemeter" %}: the rule has a new property `trustRadius`. This defines the maximum degree
of trusted data. The default of 1 is the most restrictive.
* {% rule "java/documentation/CommentContent" %}: The properties `caseSensitive` and `disallowedTerms` are removed. The
new property `fobiddenRegex` can be used now to define the disallowed terms with a single regular
expression.
* {% rule "java/design/ImmutableField" %}: the property `ignoredAnnotations` has been removed. The property was
**Java Design**
* {% rule java/design/CyclomaticComplexity %}: The property `reportLevel` has been removed. The property was
deprecated since PMD 6.0.0. The report level can now be configured separated for classes and methods using
`classReportLevel` and `methodReportLevel` instead.
* {% rule java/design/ImmutableField %}: The property `ignoredAnnotations` has been removed. The property was
deprecated since PMD 6.52.0.
* {% rule java/design/LawOfDemeter %}: The rule has a new property `trustRadius`. This defines the maximum degree
of trusted data. The default of 1 is the most restrictive.
* {% rule java/design/NPathComplexity %}: The property `minimum` has been removed. It was deprecated since PMD 6.0.0.
Use the property `reportLevel` instead.
* {% rule java/design/SingularField %}: The properties `checkInnerClasses` and `disallowNotAssignment` have been removed.
The rule is now more precise and will check these cases properly.
* {% rule java/design/UseUtilityClass %}: The property `ignoredAnnotations` has been removed.
**Java Documentation**
* {% rule java/documentation/CommentContent %}: The properties `caseSensitive` and `disallowedTerms` are removed. The
new property `forbiddenRegex` can be used now to define the disallowed terms with a single regular
expression.
* {% rule java/documentation/CommentRequired %}:
* Overridden methods are now detected even without the `@Override`
annotation. This is relevant for the property `methodWithOverrideCommentRequirement`.
See also [pull request #3757](https://github.com/pmd/pmd/pull/3757).
* Elements in annotation types are now detected as well. This might lead to an increased number of violations
for missing public method comments.
* {% rule java/documentation/CommentSize %}: When determining the line-length of a comment, the leading comment
prefix markers (e.g. `*` or `//`) are ignored and don't add up to the line-length.
See also [pull request #4369](https://github.com/pmd/pmd/pull/4369).
**Java Error Prone**
* {% rule java/errorprone/AvoidDuplicateLiterals %}: The property `exceptionfile` has been removed. The property was
deprecated since PMD 6.10.0. Use the property `exceptionList` instead.
* {% rule java/errorprone/DontImportSun %}: `sun.misc.Signal` is not special-cased anymore.
* {% rule java/errorprone/EmptyCatchBlock %}: `CloneNotSupportedException` and `InterruptedException` are not
special-cased anymore. Rename the exception parameter to `ignored` to ignore them.
* {% rule java/errorprone/ImplicitSwitchFallThrough %}: Violations are now reported on the case statements
rather than on the switch statements. This is more accurate but might result in more violations now.
#### Removed Rules
@ -334,6 +363,7 @@ Language specific fixes:
* [#4427](https://github.com/pmd/pmd/issues/4427): \[apex] ApexBadCrypto test failing to detect inline code
* apex-design
* [#2667](https://github.com/pmd/pmd/issues/2667): \[apex] Integrate nawforce/ApexLink to build robust Unused rule
* [#4509](https://github.com/pmd/pmd/issues/4509): \[apex] ExcessivePublicCount doesn't consider inner classes correctly
* java
* [#520](https://github.com/pmd/pmd/issues/520): \[java] Allow `@SuppressWarnings` with constants instead of literals
* [#864](https://github.com/pmd/pmd/issues/864): \[java] Similar/duplicated implementations for determining FQCN
@ -370,7 +400,7 @@ Language specific fixes:
* [#1212](https://github.com/pmd/pmd/issues/1212): \[java] Don't raise JUnitTestContainsTooManyAsserts on JUnit 5's assertAll
* [#1422](https://github.com/pmd/pmd/issues/1422): \[java] JUnitTestsShouldIncludeAssert false positive with inherited @<!-- -->Rule field
* [#1455](https://github.com/pmd/pmd/issues/1455): \[java] JUnitTestsShouldIncludeAssert: False positives for assert methods named "check" and "verify"
* [#1563](https://github.com/pmd/pmd/issues/1563): \[java] False positive ForLoopCanBeForeach
* [#1563](https://github.com/pmd/pmd/issues/1563): \[java] ForLoopCanBeForeach false positive with method call using index variable
* [#1565](https://github.com/pmd/pmd/issues/1565): \[java] JUnitAssertionsShouldIncludeMessage false positive with AssertJ
* [#1747](https://github.com/pmd/pmd/issues/1747): \[java] PreserveStackTrace false-positive
* [#1969](https://github.com/pmd/pmd/issues/1969): \[java] MissingOverride false-positive triggered by package-private method overwritten in another package by extending class
@ -392,10 +422,13 @@ Language specific fixes:
* [#3672](https://github.com/pmd/pmd/pull/3672): \[java] LooseCoupling - fix false positive with generics
* [#3675](https://github.com/pmd/pmd/pull/3675): \[java] MissingOverride - fix false positive with mixing type vars
* [#3858](https://github.com/pmd/pmd/issues/3858): \[java] UseCollectionIsEmpty should infer local variable type from method invocation
* [#4516](https://github.com/pmd/pmd/issues/4516): \[java] UnusedLocalVariable: false-negative with try-with-resources
* [#4517](https://github.com/pmd/pmd/issues/4517): \[java] UnusedLocalVariable: false-negative with compound assignments
* [#4518](https://github.com/pmd/pmd/issues/4518): \[java] UnusedLocalVariable: false-positive with multiple for-loop indices
* java-codestyle
* [#1208](https://github.com/pmd/pmd/issues/1208): \[java] PrematureDeclaration rule false-positive on variable declared to measure time
* [#1429](https://github.com/pmd/pmd/issues/1429): \[java] PrematureDeclaration as result of method call (false positive)
* [#1480](https://github.com/pmd/pmd/issues/1480): \[java] IdenticalCatchBranches false positive
* [#1480](https://github.com/pmd/pmd/issues/1480): \[java] IdenticalCatchBranches false positive with return expressions
* [#1673](https://github.com/pmd/pmd/issues/1673): \[java] UselessParentheses false positive with conditional operator
* [#1790](https://github.com/pmd/pmd/issues/1790): \[java] UnnecessaryFullyQualifiedName false positive with enum constant
* [#1918](https://github.com/pmd/pmd/issues/1918): \[java] UselessParentheses false positive with boolean operators
@ -414,6 +447,8 @@ Language specific fixes:
* [#4273](https://github.com/pmd/pmd/issues/4273): \[java] CommentDefaultAccessModifier ignoredAnnotations should include "org.junit.jupiter.api.extension.RegisterExtension" by default
* [#4357](https://github.com/pmd/pmd/pull/4357): \[java] Fix IllegalStateException in UseDiamondOperator rule
* [#4487](https://github.com/pmd/pmd/issues/4487): \[java] UnnecessaryConstructor: false-positive with @<!-- -->Inject and @<!-- -->Autowired
* [#4511](https://github.com/pmd/pmd/issues/4511): \[java] LocalVariableCouldBeFinal shouldn't report unused variables
* [#4512](https://github.com/pmd/pmd/issues/4512): \[java] MethodArgumentCouldBeFinal shouldn't report unused parameters
* java-design
* [#1014](https://github.com/pmd/pmd/issues/1014): \[java] LawOfDemeter: False positive with lambda expression
* [#1605](https://github.com/pmd/pmd/issues/1605): \[java] LawOfDemeter: False positive for standard UTF-8 charset name
@ -456,6 +491,8 @@ Language specific fixes:
* [#4449](https://github.com/pmd/pmd/issues/4449): \[java] AvoidAccessibilityAlteration: Possible false positive in AvoidAccessibilityAlteration rule when using Lambda expression
* [#4493](https://github.com/pmd/pmd/issues/4493): \[java] MissingStaticMethodInNonInstantiatableClass: false-positive about @<!-- -->Inject
* [#4505](https://github.com/pmd/pmd/issues/4505): \[java] ImplicitSwitchFallThrough NPE in PMD 7.0.0-rc1
* [#4513](https://github.com/pmd/pmd/issues/4513): \[java] UselessOperationOnImmutable various false negatives with String
* [#4514](https://github.com/pmd/pmd/issues/4514): \[java] AvoidLiteralsInIfCondition false positive and negative for String literals when ignoreExpressions=true
* java-multithreading
* [#2537](https://github.com/pmd/pmd/issues/2537): \[java] DontCallThreadRun can't detect the case that call run() in `this.run()`
* [#2538](https://github.com/pmd/pmd/issues/2538): \[java] DontCallThreadRun can't detect the case that call run() in `foo.bar.run()`
@ -500,9 +537,8 @@ Language specific fixes:
* [#4520](https://github.com/pmd/pmd/pull/4520): \[doc] Fix typo: missing closing quotation mark after CPD-END - [João Dinis Ferreira](https://github.com/joaodinissf) (@joaodinissf)
### 📈 Stats
* 4416 commits
* 464 closed tickets & PRs
* Days since last release: 28
* 4557 commits
* 572 closed tickets & PRs
* Days since last release: 35
{% endtocmaker %}

File diff suppressed because it is too large Load Diff

View File

@ -488,6 +488,20 @@ We are shipping the following rules:
Contributors: [Jeroen Borgers](https://github.com/jborgers) (@jborgers),
[Peter Paul Bakker](https://github.com/stokpop) (@stokpop)
#### New: CPD support for TypeScript
Thanks to a contribution, CPD now supports the TypeScript language. It is shipped
with the rest of the JavaScript support in the module `pmd-javascript`.
Contributors: [Paul Guyot](https://github.com/pguyot) (@pguyot)
#### New: CPD support for Julia
Thanks to a contribution, CPD now supports the Julia language. It is shipped
in the new module `pmd-julia`.
Contributors: [Wener](https://github.com/wener-tiobe) (@wener-tiobe)
### Changed: JavaScript support
The JS specific parser options have been removed. The parser now always retains comments and uses version ES6.
@ -530,33 +544,116 @@ Related issue: [[core] Explicitly name all language versions (#4120)](https://gi
### Changed Rules
**Java**
**General changes**
* {% rule "java/codestyle/UnnecessaryFullyQualifiedName" %}: the rule has two new properties,
* All statistical rules (like ExcessiveClassLength, ExcessiveParameterList) have been simplified and unified.
The properties `topscore` and `sigma` have been removed. The property `minimum` is still there, however the type is not
a decimal number anymore but has been changed to an integer. This affects rules in the languages Apex, Java, PLSQL
and Velocity Template Language (vm):
* Apex: {% rule apex/design/ExcessiveClassLength %}, {% rule apex/design/ExcessiveParameterList %},
{% rule apex/design/ExcessivePublicCount %}, {% rule apex/design/NcssConstructorCount %},
{% rule apex/design/NcssMethodCount %}, {% rule apex/design/NcssTypeCount %}
* Java: {% rule java/design/ExcessiveImports %}, {% rule java/design/ExcessiveParameterList %},
{% rule java/design/ExcessivePublicCount %}, {% rule java/design/SwitchDensity %}
* PLSQL: {% rule plsql/design/ExcessiveMethodLength %}, {% rule plsql/design/ExcessiveObjectLength %},
{% rule plsql/design/ExcessivePackageBodyLength %}, {% rule plsql/design/ExcessivePackageSpecificationLength %},
{% rule plsql/design/ExcessiveParameterList %}, {% rule plsql/design/ExcessiveTypeLength %},
{% rule plsql/design/NcssMethodCount %}, {% rule plsql/design/NcssObjectCount %},
{% rule plsql/design/NPathComplexity %}
* VM: {% rule vm/design/ExcessiveTemplateLength %}
* The general property `violationSuppressXPath` which is available for all rules to
[suppress warnings](pmd_userdocs_suppressing_warnings.html) now uses XPath version 3.1 by default.
This version of the XPath language is mostly identical to XPath 2.0. In PMD 6, XPath 1.0 has been used.
If you upgrade from PMD 6, you need to verify your `violationSuppressXPath` properties.
**Apex General changes**
* The properties `cc_categories`, `cc_remediation_points_multiplier`, `cc_block_highlighting` have been removed
from all rules. These properties have been deprecated since PMD 6.13.0.
See [issue #1648](https://github.com/pmd/pmd/issues/1648) for more details.
**Java General changes**
* Violations reported on methods or classes previously reported the line range of the entire method
or class. With PMD 7.0.0, the reported location is now just the identifier of the method or class.
This affects various rules, e.g. {% rule java/design/CognitiveComplexity %}.
The report location is controlled by the overrides of the method {% jdoc core::lang.ast.Node#getReportLocation() %}
in different node types.
See [issue #4439](https://github.com/pmd/pmd/issues/4439) and [issue #730](https://github.com/pmd/pmd/issues/730)
for more details.
**Java Best Practices**
* {% rule java/bestpractices/ArrayIsStoredDirectly %}: Violations are now reported on the assignment and not
anymore on the formal parameter. The reported line numbers will probably move.
* {% rule java/bestpractices/AvoidReassigningLoopVariables %}: This rule might not report anymore all
reassignments of the control variable in for-loops when the property `forReassign` is set to `skip`.
See [issue #4500](https://github.com/pmd/pmd/issues/4500) for more details.
* {% rule java/bestpractices/LooseCoupling %}: The rule has a new property to allow some types to be coupled
to (`allowedTypes`).
* {% rule java/bestpractices/UnusedLocalVariable %}: This rule has some important false-negatives fixed
and finds many more cases now. For details see issues [#2130](https://github.com/pmd/pmd/issues/2130),
[#4516](https://github.com/pmd/pmd/issues/4516), and [#4517](https://github.com/pmd/pmd/issues/4517).
**Java Codestyle**
* {% rule java/codestyle/MethodNamingConventions %}: The property `checkNativeMethods` has been removed. The
property was deprecated since PMD 6.3.0. Use the property `nativePattern` to control whether native methods
should be considered or not.
* {% rule java/codestyle/ShortVariable %}: This rule now also reports short enum constant names.
* {% rule java/codestyle/UseDiamondOperator %}: The property `java7Compatibility` has been removed. The rule now
handles Java 7 properly without a property.
* {% rule java/codestyle/UnnecessaryFullyQualifiedName %}: The rule has two new properties,
to selectively disable reporting on static field and method qualifiers. The rule also has been improved
to be more precise.
* {% rule "java/codestyle/UselessParentheses" %}: the rule has two new properties which control how strict
* {% rule java/codestyle/UselessParentheses %}: The rule has two new properties which control how strict
the rule should be applied. With `ignoreClarifying` (default: true) parentheses that are strictly speaking
not necessary are allowed, if they separate expressions of different precedence.
The other property `ignoreBalancing` (default: true) is similar, in that it allows parentheses that help
reading and understanding the expressions.
* {% rule "java/bestpractices/LooseCoupling" %}: the rule has a new property to allow some types to be coupled
to (`allowedTypes`).
* {% rule "java/errorprone/EmptyCatchBlock" %}: `CloneNotSupportedException` and `InterruptedException` are not
special-cased anymore. Rename the exception parameter to `ignored` to ignore them.
* {% rule "java/errorprone/DontImportSun" %}: `sun.misc.Signal` is not special-cased anymore.
* {% rule "java/codestyle/UseDiamondOperator" %}: the property `java7Compatibility` is removed. The rule now
handles Java 7 properly without a property.
* {% rule "java/design/SingularField" %}: Properties `checkInnerClasses` and `disallowNotAssignment` are removed.
The rule is now more precise and will check these cases properly.
* {% rule "java/design/UseUtilityClass" %}: The property `ignoredAnnotations` has been removed.
* {% rule "java/design/LawOfDemeter" %}: the rule has a new property `trustRadius`. This defines the maximum degree
of trusted data. The default of 1 is the most restrictive.
* {% rule "java/documentation/CommentContent" %}: The properties `caseSensitive` and `disallowedTerms` are removed. The
new property `fobiddenRegex` can be used now to define the disallowed terms with a single regular
expression.
* {% rule "java/design/ImmutableField" %}: the property `ignoredAnnotations` has been removed. The property was
**Java Design**
* {% rule java/design/CyclomaticComplexity %}: The property `reportLevel` has been removed. The property was
deprecated since PMD 6.0.0. The report level can now be configured separated for classes and methods using
`classReportLevel` and `methodReportLevel` instead.
* {% rule java/design/ImmutableField %}: The property `ignoredAnnotations` has been removed. The property was
deprecated since PMD 6.52.0.
* {% rule java/design/LawOfDemeter %}: The rule has a new property `trustRadius`. This defines the maximum degree
of trusted data. The default of 1 is the most restrictive.
* {% rule java/design/NPathComplexity %}: The property `minimum` has been removed. It was deprecated since PMD 6.0.0.
Use the property `reportLevel` instead.
* {% rule java/design/SingularField %}: The properties `checkInnerClasses` and `disallowNotAssignment` have been removed.
The rule is now more precise and will check these cases properly.
* {% rule java/design/UseUtilityClass %}: The property `ignoredAnnotations` has been removed.
**Java Documentation**
* {% rule java/documentation/CommentContent %}: The properties `caseSensitive` and `disallowedTerms` are removed. The
new property `forbiddenRegex` can be used now to define the disallowed terms with a single regular
expression.
* {% rule java/documentation/CommentRequired %}:
* Overridden methods are now detected even without the `@Override`
annotation. This is relevant for the property `methodWithOverrideCommentRequirement`.
See also [pull request #3757](https://github.com/pmd/pmd/pull/3757).
* Elements in annotation types are now detected as well. This might lead to an increased number of violations
for missing public method comments.
* {% rule java/documentation/CommentSize %}: When determining the line-length of a comment, the leading comment
prefix markers (e.g. `*` or `//`) are ignored and don't add up to the line-length.
See also [pull request #4369](https://github.com/pmd/pmd/pull/4369).
**Java Error Prone**
* {% rule java/errorprone/AvoidDuplicateLiterals %}: The property `exceptionfile` has been removed. The property was
deprecated since PMD 6.10.0. Use the property `exceptionList` instead.
* {% rule java/errorprone/DontImportSun %}: `sun.misc.Signal` is not special-cased anymore.
* {% rule java/errorprone/EmptyCatchBlock %}: `CloneNotSupportedException` and `InterruptedException` are not
special-cased anymore. Rename the exception parameter to `ignored` to ignore them.
* {% rule java/errorprone/ImplicitSwitchFallThrough %}: Violations are now reported on the case statements
rather than on the switch statements. This is more accurate but might result in more violations now.
### Deprecated Rules

View File

@ -3,9 +3,7 @@
~ BSD-style license; for more info see http://pmd.sourceforge.net/license.html
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>pmd</artifactId>
<groupId>net.sourceforge.pmd</groupId>

View File

@ -115,7 +115,7 @@ public class SomeClass {
</test-code>
<test-code>
<description>class with inner classes</description>
<description>#4509 class with inner classes</description>
<rule-property name="minimum">1</rule-property>
<expected-problems>2</expected-problems>
<expected-linenumbers>1,5</expected-linenumbers>

View File

@ -38,7 +38,7 @@
<arguments>
<argument>-Dpicocli.autocomplete.systemExitOnError</argument>
<argument>-cp</argument>
<classpath/>
<classpath />
<argument>picocli.AutoComplete</argument>
<argument>--force</argument>
<argument>--completionScript</argument>

View File

@ -97,7 +97,6 @@ public class CpdCommand extends AbstractAnalysisPmdSubcommand {
*/
public CPDConfiguration toConfiguration() {
final CPDConfiguration configuration = new CPDConfiguration();
configuration.setDebug(debug);
configuration.setExcludes(excludes);
configuration.setFailOnViolation(failOnViolation);
configuration.setFileListPath(fileListPath == null ? null : fileListPath.toString());

View File

@ -282,7 +282,6 @@ public class PmdCommand extends AbstractAnalysisPmdSubcommand {
configuration.setIgnoreFilePath(ignoreListPath);
configuration.setInputUri(uri);
configuration.setReportFormat(format);
configuration.setDebug(debug);
configuration.setSourceEncoding(encoding.getEncoding().name());
configuration.setMinimumPriority(minimumPriority);
configuration.setReportFile(reportFile);

View File

@ -85,7 +85,6 @@ public class TreeExportCommand extends AbstractPmdSubcommand {
public TreeExportConfiguration toConfiguration() {
final TreeExportConfiguration configuration = new TreeExportConfiguration();
configuration.setDebug(debug);
configuration.setFile(file);
configuration.setFormat(format);
configuration.setLanguage(language);

View File

@ -49,10 +49,6 @@
<groupId>org.antlr</groupId>
<artifactId>antlr4-runtime</artifactId>
</dependency>
<dependency>
<groupId>com.beust</groupId>
<artifactId>jcommander</artifactId>
</dependency>
<dependency>
<groupId>net.sf.saxon</groupId>

View File

@ -14,7 +14,6 @@ import java.nio.charset.Charset;
public abstract class AbstractConfiguration {
private Charset sourceEncoding = Charset.forName(System.getProperty("file.encoding"));
private boolean debug;
/**
* Create a new abstract configuration.
@ -42,25 +41,4 @@ public abstract class AbstractConfiguration {
this.sourceEncoding = Charset.forName(sourceEncoding);
}
/**
* Return the debug indicator. If this value is <code>true</code> then PMD
* will log debug information.
*
* @return <code>true</code> if debug logging is enabled, <code>false</code>
* otherwise.
*/
public boolean isDebug() {
return debug;
}
/**
* Set the debug indicator.
*
* @param debug
* The debug indicator to set.
* @see #isDebug()
*/
public void setDebug(boolean debug) {
this.debug = debug;
}
}

View File

@ -1,251 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Map.Entry;
import java.util.Objects;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.event.Level;
import net.sourceforge.pmd.benchmark.TextTimingReportRenderer;
import net.sourceforge.pmd.benchmark.TimeTracker;
import net.sourceforge.pmd.benchmark.TimingReport;
import net.sourceforge.pmd.benchmark.TimingReportRenderer;
import net.sourceforge.pmd.cli.PMDCommandLineInterface;
import net.sourceforge.pmd.cli.PmdParametersParseResult;
import net.sourceforge.pmd.internal.LogMessages;
import net.sourceforge.pmd.internal.Slf4jSimpleConfiguration;
import net.sourceforge.pmd.reporting.ReportStats;
import net.sourceforge.pmd.util.log.MessageReporter;
import net.sourceforge.pmd.util.log.internal.SimpleMessageReporter;
/**
* Entry point for PMD's CLI. Use {@link #runPmd(PMDConfiguration)}
* or {@link #runPmd(String...)} to mimic a CLI run. This class is
* not a supported programmatic API anymore, use {@link PmdAnalysis}
* for fine control over the PMD integration and execution.
*
* <p><strong>Warning:</strong> This class is not intended to be instantiated or subclassed. It will
* be made final in PMD7.
*
* @deprecated This class is to be removed in PMD 7 in favor of a unified PmdCli entry point. {@link PmdAnalysis} should be used for non-CLI use-cases.
*/
@Deprecated
public final class PMD {
private static final String PMD_PACKAGE = "net.sourceforge.pmd";
// not final, in order to re-initialize logging
private static Logger log = LoggerFactory.getLogger(PMD_PACKAGE);
private PMD() {
}
/**
* Entry to invoke PMD as command line tool. Note that this will
* invoke {@link System#exit(int)}.
*
* @param args command line arguments
*/
public static void main(String[] args) {
StatusCode exitCode = runPmd(args);
PMDCommandLineInterface.setStatusCodeOrExit(exitCode.toInt());
}
/**
* Parses the command line arguments and executes PMD. Returns the
* status code without exiting the VM. Note that the arguments parsing
* may itself fail and produce a {@link StatusCode#ERROR}. This will
* print the error message to standard error.
*
* @param args command line arguments
*
* @return the status code. Note that {@link PMDConfiguration#isFailOnViolation()}
* (flag {@code --failOnViolation}) may turn an {@link StatusCode#OK} into a {@link
* StatusCode#VIOLATIONS_FOUND}.
*/
public static StatusCode runPmd(String... args) {
PmdParametersParseResult parseResult = PmdParametersParseResult.extractParameters(args);
// todo these warnings/errors should be output on a PmdRenderer
if (!parseResult.getDeprecatedOptionsUsed().isEmpty()) {
Entry<String, String> first = parseResult.getDeprecatedOptionsUsed().entrySet().iterator().next();
log.warn("Some deprecated options were used on the command-line, including {}", first.getKey());
log.warn("Consider replacing it with {}", first.getValue());
}
if (parseResult.isVersion()) {
System.out.println("PMD " + PMDVersion.VERSION);
return StatusCode.OK;
} else if (parseResult.isHelp()) {
PMDCommandLineInterface.printJcommanderUsageOnConsole();
System.out.println(PMDCommandLineInterface.buildUsageText());
return StatusCode.OK;
} else if (parseResult.isError()) {
System.err.println(parseResult.getError().getMessage());
System.err.println(LogMessages.runWithHelpFlagMessage());
return StatusCode.ERROR;
}
PMDConfiguration configuration = null;
try {
configuration = Objects.requireNonNull(
parseResult.toConfiguration()
);
} catch (IllegalArgumentException e) {
System.err.println("Cannot start analysis: " + e);
log.debug(ExceptionUtils.getStackTrace(e));
return StatusCode.ERROR;
}
Level curLogLevel = Slf4jSimpleConfiguration.getDefaultLogLevel();
boolean resetLogLevel = false;
try {
// only reconfigure logging, if debug flag was used on command line
// otherwise just use whatever is in conf/simplelogger.properties which happens automatically
if (configuration.isDebug()) {
Slf4jSimpleConfiguration.reconfigureDefaultLogLevel(Level.TRACE);
// need to reload the logger with the new configuration
log = LoggerFactory.getLogger(PMD_PACKAGE);
resetLogLevel = true;
}
MessageReporter pmdReporter = setupMessageReporter();
configuration.setReporter(pmdReporter);
return runPmd(configuration);
} finally {
if (resetLogLevel) {
// reset to the previous value
Slf4jSimpleConfiguration.reconfigureDefaultLogLevel(curLogLevel);
log = LoggerFactory.getLogger(PMD_PACKAGE);
}
}
}
/**
* Execute PMD from a configuration. Returns the status code without
* exiting the VM. This is the main entry point to run a full PMD run
* with a manually created configuration.
*
* @param configuration Configuration to run
*
* @return the status code. Note that {@link PMDConfiguration#isFailOnViolation()}
* (flag {@code --failOnViolation}) may turn an {@link StatusCode#OK} into a {@link
* StatusCode#VIOLATIONS_FOUND}.
*/
public static StatusCode runPmd(PMDConfiguration configuration) {
if (configuration.isBenchmark()) {
TimeTracker.startGlobalTracking();
}
MessageReporter pmdReporter = configuration.getReporter();
try {
PmdAnalysis pmd;
try {
pmd = PmdAnalysis.create(configuration);
} catch (Exception e) {
pmdReporter.errorEx("Could not initialize analysis", e);
return StatusCode.ERROR;
}
try {
log.debug("Current classpath:\n{}", System.getProperty("java.class.path"));
ReportStats stats = pmd.runAndReturnStats();
if (pmdReporter.numErrors() > 0) {
// processing errors are ignored
return StatusCode.ERROR;
} else if (stats.getNumViolations() > 0 && configuration.isFailOnViolation()) {
return StatusCode.VIOLATIONS_FOUND;
} else {
return StatusCode.OK;
}
} finally {
pmd.close();
}
} catch (Exception e) {
pmdReporter.errorEx("Exception while running PMD.", e);
PmdAnalysis.printErrorDetected(pmdReporter, 1);
return StatusCode.ERROR;
} finally {
finishBenchmarker(configuration);
}
}
private static @NonNull MessageReporter setupMessageReporter() {
// create a top-level reporter
// TODO CLI errors should also be reported through this
// TODO this should not use the logger as backend, otherwise without
// slf4j implementation binding, errors are entirely ignored.
MessageReporter pmdReporter = new SimpleMessageReporter(log);
// always install java.util.logging to slf4j bridge
Slf4jSimpleConfiguration.installJulBridge();
// logging, mostly for testing purposes
Level defaultLogLevel = Slf4jSimpleConfiguration.getDefaultLogLevel();
log.info("Log level is at {}", defaultLogLevel);
return pmdReporter;
}
private static void finishBenchmarker(PMDConfiguration configuration) {
if (configuration.isBenchmark()) {
final TimingReport timingReport = TimeTracker.stopGlobalTracking();
// TODO get specified report format from config
final TimingReportRenderer renderer = new TextTimingReportRenderer();
try {
// Don't close this writer, we don't want to close stderr
@SuppressWarnings("PMD.CloseResource")
final Writer writer = new OutputStreamWriter(System.err);
renderer.render(timingReport, writer);
} catch (final IOException e) {
System.err.println(e.getMessage());
}
}
}
/**
* Represents status codes that are used as exit codes during CLI runs.
*
* @see #runPmd(String[])
* @deprecated This class is to be removed in PMD 7 in favor of a unified PmdCli entry point.
*/
@Deprecated
public enum StatusCode {
/** No errors, no violations. This is exit code {@code 0}. */
OK(0),
/**
* Errors were detected, PMD may have not run to the end.
* This is exit code {@code 1}.
*/
ERROR(1),
/**
* No errors, but PMD found violations. This is exit code {@code 4}.
* This is only returned if {@link PMDConfiguration#isFailOnViolation()}
* is set (CLI flag {@code --failOnViolation}).
*/
VIOLATIONS_FOUND(4);
private final int code;
StatusCode(int code) {
this.code = code;
}
/** Returns the exit code as used in CLI. */
public int toInt() {
return this.code;
}
}
}

View File

@ -27,7 +27,6 @@ import net.sourceforge.pmd.annotation.DeprecatedUntil700;
import net.sourceforge.pmd.cache.AnalysisCache;
import net.sourceforge.pmd.cache.FileAnalysisCache;
import net.sourceforge.pmd.cache.NoopAnalysisCache;
import net.sourceforge.pmd.cli.PmdParametersParseResult;
import net.sourceforge.pmd.internal.util.ClasspathClassLoader;
import net.sourceforge.pmd.lang.Language;
import net.sourceforge.pmd.lang.LanguagePropertyBundle;
@ -41,45 +40,39 @@ import net.sourceforge.pmd.util.log.MessageReporter;
import net.sourceforge.pmd.util.log.internal.SimpleMessageReporter;
/**
* This class contains the details for the runtime configuration of a PMD run.
* You can either create one and set individual fields, or mimic a CLI run by
* using {@link PmdParametersParseResult#extractParameters(String...) extractParameters}.
* This class contains the details for the runtime configuration of a
* PMD run. Once configured, use {@link PmdAnalysis#create(PMDConfiguration)}
* in a try-with-resources to execute the analysis (see {@link PmdAnalysis}).
*
* <p>There are several aspects to the configuration of PMD.
* <h3>Rulesets</h3>
*
* <p>The aspects related to generic PMD behavior:</p>
* <ul>
* <li>Suppress marker is used in source files to suppress a RuleViolation,
* defaults to {@value DEFAULT_SUPPRESS_MARKER}. {@link #getSuppressMarker()}</li>
* <li>The number of threads to create when invoking on multiple files, defaults
* one thread per available processor. {@link #getThreads()}</li>
* <li>A ClassLoader to use when loading classes during Rule processing (e.g.
* during type resolution), defaults to ClassLoader of the Configuration class.
* {@link #getClassLoader()}</li>
* <li>A means to configure a ClassLoader using a prepended classpath String,
* instead of directly setting it programmatically.
* {@link #prependAuxClasspath(String)}</li>
* <li>A LanguageVersionDiscoverer instance, which defaults to using the default
* LanguageVersion of each Language. Means are provided to change the
* LanguageVersion for each Language.
* {@link #getLanguageVersionDiscoverer()}</li>
* <li>You can configure paths to the rulesets to use with {@link #addRuleSet(String)}.
* These can be file paths or classpath resources.</li>
* <li>Use {@link #setMinimumPriority(RulePriority)} to control the minimum priority a
* rule must have to be included. Defaults to the lowest priority, ie all rules are loaded.</li>
* <li>Use {@link #setRuleSetFactoryCompatibilityEnabled(boolean)} to disable the
* compatibility measures for removed and renamed rules in the rulesets that will
* be loaded.
* </ul>
*
* <p>The aspects related to Rules and Source files are:</p>
* <h3>Source files</h3>
*
* <ul>
* <li>RuleSets URIs: {@link #getRuleSetPaths()}</li>
* <li>A minimum priority threshold when loading Rules from RuleSets, defaults
* to {@link RulePriority#LOW}. {@link #getMinimumPriority()}</li>
* <li>The character encoding of source files, defaults to the system default as
* <li>The default encoding of source files is the system default as
* returned by <code>System.getProperty("file.encoding")</code>.
* {@link #getSourceEncoding()}</li>
* <li>A list of input paths to process for source files. This
* may include files, directories, archives (e.g. ZIP files), etc.
* {@link #getInputPathList()}</li>
* <li>A flag which controls, whether {@link RuleSetLoader#enableCompatibility(boolean)} filter
* should be used or not: #isRuleSetFactoryCompatibilityEnabled;
* You can set it with {@link #setSourceEncoding(String)}.</li>
* <li>The source files to analyze can be given in many ways. See
* {@link #addInputPath(Path)} {@link #setInputFilePath(Path)}, {@link #setInputUri(URI)}.
* <li>Files are assigned a language based on their name. The language
* version of languages can be given with
* {@link #setDefaultLanguageVersion(LanguageVersion)}.
* The default language assignment can be overridden with
* {@link #setForceLanguageVersion(LanguageVersion)}.</li>
* </ul>
*
* <h3>Rendering</h3>
*
* <ul>
* <li>The renderer format to use for Reports. {@link #getReportFormat()}</li>
* <li>The file to which the Report should render. {@link #getReportFile()}</li>
@ -91,14 +84,18 @@ import net.sourceforge.pmd.util.log.internal.SimpleMessageReporter;
* {@link #isShowSuppressedViolations()}</li>
* </ul>
*
* <p>The aspects related to special PMD behavior are:</p>
* <h3>Language configuration </h3>
* <ul>
* <li>An indicator of whether PMD should log debug information.
* {@link #isDebug()}</li>
* <li>An indicator of whether PMD should perform stress testing behaviors, such
* as randomizing the order of file processing. {@link #isStressTest()}</li>
* <li>An indicator of whether PMD should log benchmarking information.
* {@link #isBenchmark()}</li>
* <li>Use {@link #setSuppressMarker(String)} to change the comment marker for suppression comments. Defaults to {@value #DEFAULT_SUPPRESS_MARKER}.</li>
* <li>See {@link #setClassLoader(ClassLoader)} and {@link #prependAuxClasspath(String)} for
* information for how to configure classpath for Java analysis.</li>
* <li>You can set additional language properties with {@link #getLanguageProperties(Language)}</li>
* </ul>
*
* <h3>Miscellaneous</h3>
* <ul>
* <li>Use {@link #setThreads(int)} to control the parallelism of the analysis. Defaults
* one thread per available processor. {@link #getThreads()}</li>
* </ul>
*/
public class PMDConfiguration extends AbstractConfiguration {
@ -113,7 +110,7 @@ public class PMDConfiguration extends AbstractConfiguration {
private ClassLoader classLoader = getClass().getClassLoader();
private final LanguageVersionDiscoverer languageVersionDiscoverer;
private LanguageVersion forceLanguageVersion;
private MessageReporter reporter = new SimpleMessageReporter(LoggerFactory.getLogger(PMD.class));
private MessageReporter reporter = new SimpleMessageReporter(LoggerFactory.getLogger(PmdAnalysis.class));
// Rule and source file options
private List<String> ruleSets = new ArrayList<>();
@ -131,10 +128,6 @@ public class PMDConfiguration extends AbstractConfiguration {
private boolean showSuppressedViolations = false;
private boolean failOnViolation = true;
@Deprecated
private boolean stressTest;
@Deprecated
private boolean benchmark;
private AnalysisCache analysisCache = new NoopAnalysisCache();
private boolean ignoreIncrementalAnalysis;
private final LanguageRegistry langRegistry;
@ -253,6 +246,9 @@ public class PMDConfiguration extends AbstractConfiguration {
* <code>file://</code>) the file will be read with each line representing
* an entry on the classpath.</p>
*
* <p>You can specify multiple class paths separated by `:` on Unix-systems or `;` under Windows.
* See {@link File#pathSeparator}.
*
* @param classpath The prepended classpath.
*
* @throws IllegalArgumentException if the given classpath is invalid (e.g. does not exist)
@ -738,60 +734,6 @@ public class PMDConfiguration extends AbstractConfiguration {
this.reportProperties = reportProperties;
}
/**
* Return the stress test indicator. If this value is <code>true</code> then
* PMD will randomize the order of file processing to attempt to shake out
* bugs.
*
* @return <code>true</code> if stress test is enbaled, <code>false</code>
* otherwise.
*
* @deprecated For removal
*/
@Deprecated
public boolean isStressTest() {
return stressTest;
}
/**
* Set the stress test indicator.
*
* @param stressTest
* The stree test indicator to set.
* @see #isStressTest()
* @deprecated For removal.
*/
@Deprecated
public void setStressTest(boolean stressTest) {
this.stressTest = stressTest;
}
/**
* Return the benchmark indicator. If this value is <code>true</code> then
* PMD will log benchmark information.
*
* @return <code>true</code> if benchmark logging is enbaled,
* <code>false</code> otherwise.
* @deprecated This behavior is down to CLI, not part of the core analysis.
*/
@Deprecated
public boolean isBenchmark() {
return benchmark;
}
/**
* Set the benchmark indicator.
*
* @param benchmark
* The benchmark indicator to set.
* @see #isBenchmark()
* @deprecated This behavior is down to CLI, not part of the core analysis.
*/
@Deprecated
public void setBenchmark(boolean benchmark) {
this.benchmark = benchmark;
}
/**
* Whether PMD should exit with status 4 (the default behavior, true) if
* violations are found or just with 0 (to not break the build, e.g.).

View File

@ -44,6 +44,7 @@ import net.sourceforge.pmd.lang.document.FileCollector;
import net.sourceforge.pmd.lang.document.TextFile;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.reporting.ConfigurableFileNameRenderer;
import net.sourceforge.pmd.reporting.FileAnalysisListener;
import net.sourceforge.pmd.reporting.GlobalAnalysisListener;
import net.sourceforge.pmd.reporting.ListenerInitializer;
import net.sourceforge.pmd.reporting.ReportStats;
@ -53,11 +54,19 @@ import net.sourceforge.pmd.util.StringUtil;
import net.sourceforge.pmd.util.log.MessageReporter;
/**
* Main programmatic API of PMD. Create and configure a {@link PMDConfiguration},
* Main programmatic API of PMD. This is not a CLI entry point, see module
* {@code pmd-cli} for that.
*
* <h3>Usage overview</h3>
*
* Create and configure a {@link PMDConfiguration},
* then use {@link #create(PMDConfiguration)} to obtain an instance.
* You can perform additional configuration on the instance, eg adding
* You can perform additional configuration on the instance, e.g. adding
* files to process, or additional rulesets and renderers. Then, call
* {@link #performAnalysis()}. Example:
* {@link #performAnalysis()} or one of the related terminal methods.
*
* <h3>Simple example</h3>
*
* <pre>{@code
* PMDConfiguration config = new PMDConfiguration();
* config.setDefaultLanguageVersion(LanguageRegistry.findLanguageByTerseName("java").getVersion("11"));
@ -81,6 +90,42 @@ import net.sourceforge.pmd.util.log.MessageReporter;
* }
* }</pre>
*
* <h3>Rendering reports</h3>
*
* If you just want to render a report to a file like with the CLI, you
* should use a {@link Renderer}. You can add a custom one with {@link PmdAnalysis#addRenderer(Renderer)}.
* You can add one of the builtin renderers from its ID using {@link PMDConfiguration#setReportFormat(String)}.
*
* <h3>Reports and events</h3>
*
* <p>If you want strongly typed access to violations and other analysis events,
* you can implement and register a {@link GlobalAnalysisListener} with {@link #addListener(GlobalAnalysisListener)}.
* The listener needs to provide a new {@link FileAnalysisListener} for each file,
* which will receive events from the analysis. The listener's lifecycle
* happens only once the analysis is started ({@link #performAnalysis()}).
*
* <p>If you want access to all events once the analysis ends instead of processing
* events as they go, you can obtain a {@link Report} instance from {@link #performAnalysisAndCollectReport()},
* or use {@link Report.GlobalReportBuilderListener} manually. Keep in
* mind collecting a report is less memory-efficient than using a listener.
*
* <p>If you want to process events in batches, one per file, you can
* use {@link Report.ReportBuilderListener}. to implement {@link GlobalAnalysisListener#startFileAnalysis(TextFile)}.
*
* <p>Listeners can be used alongside renderers.
*
* <h3>Specifying the Java classpath</h3>
*
* Java rules work better if you specify the path to the compiled classes
* of the analysed sources. See {@link PMDConfiguration#prependAuxClasspath(String)}.
*
* <h3>Customizing message output</h3>
*
* <p>The analysis reports messages like meta warnings and errors through a
* {@link MessageReporter} instance. To override how those messages are output,
* you can set it in {@link PMDConfiguration#setReporter(MessageReporter)}.
* By default, it forwards messages to SLF4J.
*
*/
public final class PmdAnalysis implements AutoCloseable {

View File

@ -1,228 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cli;
import java.util.Properties;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.PMD.StatusCode;
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;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.renderers.RendererFactory;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
/**
* @author Romain Pelisse &lt;belaran@gmail.com&gt;
* @deprecated Internal API. Use {@link PMD#runPmd(String...)} or {@link PMD#main(String[])},
* or {@link PmdParametersParseResult} if you just want to produce a configuration.
*/
@Deprecated
@InternalApi
public final class PMDCommandLineInterface {
@Deprecated
public static final String PROG_NAME = "pmd";
/**
* @deprecated This is used for testing, but support for it will be removed in PMD 7.
* Use {@link PMD#runPmd(String...)} or an overload to avoid exiting the VM. In PMD 7,
* {@link PMD#main(String[])} will call {@link System#exit(int)} always.
*/
@Deprecated
public static final String NO_EXIT_AFTER_RUN = "net.sourceforge.pmd.cli.noExit";
/**
* @deprecated This is used for testing, but support for it will be removed in PMD 7.
* Use {@link PMD#runPmd(String...)} or an overload to avoid exiting the VM. In PMD 7,
* {@link PMD#main(String[])} will call {@link System#exit(int)} always.
*/
@Deprecated
public static final String STATUS_CODE_PROPERTY = "net.sourceforge.pmd.cli.status";
/**
* @deprecated Use {@link StatusCode#OK}
*/
@Deprecated
public static final int NO_ERRORS_STATUS = 0;
/**
* @deprecated Use {@link StatusCode#ERROR}
*/
@Deprecated
public static final int ERROR_STATUS = 1;
/**
* @deprecated Use {@link StatusCode#VIOLATIONS_FOUND}
*/
@Deprecated
public static final int VIOLATIONS_FOUND = 4;
private PMDCommandLineInterface() { }
/**
* Note: this may terminate the VM.
*
* @deprecated Use {@link PmdParametersParseResult#extractParameters(String...)}
*/
@Deprecated
public static PMDParameters extractParameters(PMDParameters arguments, String[] args, String progName) {
JCommander jcommander = new JCommander(arguments);
jcommander.setProgramName(progName);
try {
jcommander.parse(args);
if (arguments.isHelp()) {
jcommander.usage();
System.out.println(buildUsageText());
setStatusCodeOrExit(NO_ERRORS_STATUS);
}
} catch (ParameterException e) {
jcommander.usage();
System.out.println(buildUsageText());
System.err.println(e.getMessage());
setStatusCodeOrExit(ERROR_STATUS);
}
return arguments;
}
public static String buildUsageText() {
return "\n"
+ "Mandatory arguments:\n"
+ "1) A java source code filename or directory\n"
+ "2) A report format \n"
+ "3) A ruleset filename or a comma-delimited string of ruleset filenames\n"
+ "\n"
+ "For example: \n"
+ getWindowsLaunchCmd() + " -d c:\\my\\source\\code -f html -R java-unusedcode\n\n"
+ supportedVersions() + "\n"
+ "Available report formats and their configuration properties are:" + "\n" + getReports()
+ "\n" + getExamples() + "\n" + "\n" + "\n";
}
@Deprecated
public static String buildUsageText(JCommander jcommander) {
return buildUsageText();
}
private static String getExamples() {
return getWindowsExample() + getUnixExample();
}
private static String getWindowsLaunchCmd() {
final String WINDOWS_PROMPT = "C:\\>";
final String launchCmd = "pmd-bin-" + PMDVersion.VERSION + "\\bin\\pmd.bat";
return WINDOWS_PROMPT + launchCmd;
}
private static String getWindowsExample() {
final String launchCmd = getWindowsLaunchCmd();
final String WINDOWS_PATH_TO_CODE = "c:\\my\\source\\code ";
return "For example on windows: " + "\n"
+ launchCmd + " --dir " + WINDOWS_PATH_TO_CODE
+ "--format text -R rulesets/java/quickstart.xml --use-version java-1.5 --debug" + "\n"
+ launchCmd + " -dir " + WINDOWS_PATH_TO_CODE
+ "-f xml --rulesets rulesets/java/quickstart.xml,category/java/codestyle.xml --encoding UTF-8" + "\n"
+ launchCmd + " --d " + WINDOWS_PATH_TO_CODE
+ "--rulesets rulesets/java/quickstart.xml --aux-classpath lib\\commons-collections.jar;lib\\derby.jar"
+ "\n"
+ launchCmd + " -d " + WINDOWS_PATH_TO_CODE
+ "-f html -R rulesets/java/quickstart.xml --aux-classpath file:///C:/my/classpathfile" + "\n" + "\n";
}
private static String getUnixExample() {
final String launchCmd = "$ pmd-bin-" + PMDVersion.VERSION + "/bin/run.sh pmd";
return "For example on *nix: " + "\n"
+ launchCmd
+ " --dir /home/workspace/src/main/java/code -f html --rulesets rulesets/java/quickstart.xml,category/java/codestyle.xml"
+ "\n"
+ launchCmd
+ " -d ./src/main/java/code -R rulesets/java/quickstart.xml -f xslt --property xsltFilename=my-own.xsl"
+ "\n"
+ launchCmd
+ " -d ./src/main/java/code -R rulesets/java/quickstart.xml -f xslt --property xsltFilename=html-report-v2.xslt"
+ "\n"
+ " - html-report-v2.xslt is at https://github.com/pmd/pmd/tree/master/pmd-core/etc/xslt/html-report-v2.xslt"
+ launchCmd
+ " -d ./src/main/java/code -f html -R rulesets/java/quickstart.xml --aux-classpath commons-collections.jar:derby.jar"
+ "\n";
}
private static String supportedVersions() {
return "Languages and version supported:" + "\n"
+ LanguageRegistry.PMD.commaSeparatedList(Language::getId)
+ "\n";
}
/**
* For testing purpose only...
*
* @param args
*
* @deprecated Use {@link PMD#runPmd(String...)}
*/
@Deprecated
public static void main(String[] args) {
System.out.println(PMDCommandLineInterface.buildUsageText());
}
public static String jarName() {
return "pmd-" + PMDVersion.VERSION + ".jar";
}
private static String getReports() {
StringBuilder buf = new StringBuilder();
for (String reportName : RendererFactory.supportedRenderers()) {
Renderer renderer = RendererFactory.createRenderer(reportName, new Properties());
buf.append(" ").append(reportName).append(": ");
if (!reportName.equals(renderer.getName())) {
buf.append(" Deprecated alias for '").append(renderer.getName()).append("\n");
continue;
}
buf.append(renderer.getDescription()).append("\n");
for (PropertyDescriptor<?> property : renderer.getPropertyDescriptors()) {
buf.append(" ").append(property.name()).append(" - ");
buf.append(property.description());
Object deflt = property.defaultValue();
if (deflt != null) {
buf.append(" default: ").append(deflt);
}
buf.append("\n");
}
}
return buf.toString();
}
public static void setStatusCodeOrExit(int status) {
if (isExitAfterRunSet()) {
System.exit(status);
} else {
setStatusCode(status);
}
}
private static boolean isExitAfterRunSet() {
String noExit = System.getenv(NO_EXIT_AFTER_RUN);
if (noExit == null) {
noExit = System.getProperty(NO_EXIT_AFTER_RUN);
}
return noExit == null;
}
private static void setStatusCode(int statusCode) {
System.setProperty(STATUS_CODE_PROPERTY, Integer.toString(statusCode));
}
public static void printJcommanderUsageOnConsole() {
new JCommander(new PMDParameters()).usage();
}
}

View File

@ -1,184 +0,0 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cli;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import org.checkerframework.checker.nullness.qual.Nullable;
import net.sourceforge.pmd.PMDConfiguration;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterException;
/**
* Result of parsing a bunch of CLI arguments. Parsing may fail with an
* exception, or succeed and produce a {@link PMDConfiguration}. If the
* {@code --help} argument is mentioned, no configuration is produced.
*/
public final class PmdParametersParseResult {
private final PMDParameters result;
private final ParameterException error;
private final Map<String, String> deprecatedOptionsUsed;
PmdParametersParseResult(PMDParameters result,
Map<String, String> deprecatedOptionsUsed) {
this.result = Objects.requireNonNull(result);
this.deprecatedOptionsUsed = deprecatedOptionsUsed;
this.error = null;
}
PmdParametersParseResult(ParameterException error, Map<String, String> deprecatedOptionsUsed) {
this.result = null;
this.error = Objects.requireNonNull(error);
this.deprecatedOptionsUsed = deprecatedOptionsUsed;
}
/** Returns true if parsing failed. */
public boolean isError() {
return result == null;
}
/**
* Returns whether parsing just requested the {@code --help} text.
* In this case no configuration is produced.
*/
public boolean isHelp() {
return !isError() && result.isHelp();
}
/**
* Returns whether parsing just requested the {@code --version} text.
* In this case no configuration is produced.
*/
public boolean isVersion() {
return !isError() && result.isVersion();
}
/**
* Returns the error if parsing failed. Parsing may fail if required
* parameters are not provided, or if some parameters don't pass validation.
* Otherwise returns null.
*/
public ParameterException getError() {
return error;
}
/**
* Returns a map of deprecated CLI options used by the command that
* created this instance. Each key is a deprecated option that was used,
* and the value is a suggested replacement (a piece of English text).
*/
public Map<String, String> getDeprecatedOptionsUsed() {
return deprecatedOptionsUsed;
}
/**
* Returns the resulting configuration if parsing succeeded and neither {@link #isHelp()} nor {@link #isVersion()} is requested.
* Otherwise returns null.
*/
public @Nullable PMDConfiguration toConfiguration() {
return isValidParameterSet() ? result.toConfiguration() : null;
}
private boolean isValidParameterSet() {
return result != null && !isHelp() && !isVersion();
}
/**
* Parse an array of CLI parameters and returns a result (which may be failed).
*
* @param args Array of parameters
*
* @return A parse result
*
* @throws NullPointerException If the parameter array is null
*/
public static PmdParametersParseResult extractParameters(String... args) {
Objects.requireNonNull(args, "Null parameter array");
PMDParameters result = new PMDParameters();
JCommander jcommander = new JCommander(result);
jcommander.setProgramName("pmd");
try {
parseAndValidate(jcommander, result, args);
return new PmdParametersParseResult(result, filterDeprecatedOptions(args));
} catch (ParameterException e) {
return new PmdParametersParseResult(e, filterDeprecatedOptions(args));
}
}
private static void parseAndValidate(JCommander jcommander, PMDParameters result, String[] args) {
jcommander.parse(args);
if (result.isHelp() || result.isVersion()) {
return;
}
// jcommander has no special support for global parameter validation like this
// For consistency we report this with a ParameterException
if (result.getInputPaths().isEmpty()
&& null == result.getUri()
&& null == result.getFileListPath()) {
throw new ParameterException(
"Please provide a parameter for source root directory (--dir or -d), database URI (--uri or -u), or file list path (--file-list).");
}
}
private static Map<String, String> filterDeprecatedOptions(String... args) {
Map<String, String> argSet = new LinkedHashMap<>(SUGGESTED_REPLACEMENT);
argSet.keySet().retainAll(new HashSet<>(Arrays.asList(args)));
return Collections.unmodifiableMap(argSet);
}
/** Map of deprecated option to suggested replacement. */
private static final Map<String, String> SUGGESTED_REPLACEMENT;
static {
Map<String, String> m = new LinkedHashMap<>();
m.put("-rulesets", "--rulesets (or -R)");
m.put("-uri", "--uri");
m.put("-dir", "--dir (or -d)");
m.put("-filelist", "--file-list");
m.put("-ignorelist", "--ignore-list");
m.put("-format", "--format (or -f)");
m.put("-debug", "--debug");
m.put("-verbose", "--verbose");
m.put("-help", "--help");
m.put("-encoding", "--encoding");
m.put("-threads", "--threads");
m.put("-benchmark", "--benchmark");
m.put("-stress", "--stress");
m.put("-shortnames", PMDParameters.RELATIVIZE_PATHS_WITH);
m.put("--short-names", PMDParameters.RELATIVIZE_PATHS_WITH);
m.put("-showsuppressed", "--show-suppressed");
m.put("-suppressmarker", "--suppress-marker");
m.put("-minimumpriority", "--minimum-priority");
m.put("-property", "--property");
m.put("-reportfile", "--report-file");
m.put("-force-language", "--force-language");
m.put("-auxclasspath", "--aux-classpath");
m.put("-failOnViolation", "--fail-on-violation");
m.put("--failOnViolation", "--fail-on-violation");
m.put("-norulesetcompatibility", "--no-ruleset-compatibility");
m.put("-cache", "--cache");
m.put("-no-cache", "--no-cache");
m.put("-v", "--use-version"); // In PMD 7, -v will enable verbose mode
m.put("-V", "--verbose"); // In PMD 7, -V will show the tool version
m.put("-min", "--minimum-priority");
m.put("-version", "--use-version");
m.put("-language", "--use-version");
m.put("-l", "--use-version");
SUGGESTED_REPLACEMENT = Collections.unmodifiableMap(m);
}
}

View File

@ -85,8 +85,6 @@ public class CPDConfiguration extends AbstractConfiguration {
private boolean failOnViolation = true;
private boolean debug = false;
public SourceCode sourceCodeFor(File file) {
return new SourceCode(new SourceCode.FileCodeLoader(file, getSourceEncoding().name()));
}
@ -396,13 +394,4 @@ public class CPDConfiguration extends AbstractConfiguration {
this.failOnViolation = failOnViolation;
}
@Override
public boolean isDebug() {
return debug;
}
@Override
public void setDebug(boolean debug) {
this.debug = debug;
}
}

View File

@ -9,9 +9,6 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.cli.PMDParameters;
public final class ShortFilenameUtil {
private ShortFilenameUtil() {
@ -27,8 +24,6 @@ public final class ShortFilenameUtil {
* @param inputFileName
* @return
*
* @see PMDConfiguration#isReportShortNames()
* @see PMDParameters#isShortnames()
*/
public static String determineFileName(List<String> inputPathPrefixes, String inputFileName) {
for (final String prefix : inputPathPrefixes) {

View File

@ -97,6 +97,17 @@ public interface Language extends Comparable<Language> {
*/
List<LanguageVersion> getVersions();
/**
* Returns the latest language version. May not be the
* {@linkplain #getDefaultVersion() default}.
*
* @return The latest language version
*/
default LanguageVersion getLatestVersion() {
List<LanguageVersion> versions = getVersions();
return versions.get(versions.size() - 1);
}
/**
* Returns a complete set of supported version names for this language
* including all aliases.

View File

@ -6,7 +6,10 @@ package net.sourceforge.pmd.renderers;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Objects;
import net.sourceforge.pmd.AbstractConfiguration;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.annotation.Experimental;
import net.sourceforge.pmd.internal.util.IOUtil;
import net.sourceforge.pmd.lang.document.FileId;
@ -66,16 +69,20 @@ public abstract class AbstractRenderer extends AbstractPropertySource implements
@Override
public void setFileNameRenderer(FileNameRenderer fileNameRenderer) {
this.fileNameRenderer = fileNameRenderer;
this.fileNameRenderer = Objects.requireNonNull(fileNameRenderer);
}
/**
* Determines the filename that should be used in the report depending on the
* option "shortnames". If the option is enabled, then the filename in the report
* is without the directory prefix of the directories, that have been analyzed.
* If the option "shortnames" is not enabled, then the fileId is returned as-is.
* Determines the filename that should be used in the report for the
* given ID. This uses the {@link FileNameRenderer} of this renderer.
* In the PMD CLI, the file name renderer respects the {@link PMDConfiguration#getRelativizeRoots()}
* relativize roots to output relative paths.
*
* <p>A renderer does not have to use this method to output paths.
* Some report formats require a specific format for paths, eg URIs.
* They can implement this ad-hoc.
*/
protected String determineFileName(FileId fileId) {
protected final String determineFileName(FileId fileId) {
return fileNameRenderer.getDisplayName(fileId);
}

View File

@ -110,13 +110,20 @@ public interface Renderer extends PropertySource {
*/
Writer getWriter();
/**
* Set the {@link FileNameRenderer} used to render file paths to the report.
* Note that this renderer does not have to use the parameter to output paths.
* Some report formats require a specific format for paths (eg a URI), and are
* allowed to circumvent the provided strategy.
*
* @param fileNameRenderer a non-null file name renderer
*/
void setFileNameRenderer(FileNameRenderer fileNameRenderer);
/**
* Set the Writer for the Renderer.
*
* @param writer
* The Writer.
* @param writer The Writer.
*/
void setWriter(Writer writer);

View File

@ -8,6 +8,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.Report.ProcessingError;
import net.sourceforge.pmd.Report.SuppressedViolation;
import net.sourceforge.pmd.RuleViolation;
@ -17,10 +18,13 @@ import net.sourceforge.pmd.util.AssertionUtil;
/**
* A handler for events occuring during analysis of a single file. Instances
* are only used on a single thread for their entire lifetime, so don't
* need to be synchronized to access state they own.
* need to be synchronized to access state they own. File listeners are
* spawned by a {@link GlobalAnalysisListener}.
*
* <p>Listeners are assumed to be ready to receive events as soon as they
* are constructed.
*
* @see Report.ReportBuilderListener
*/
public interface FileAnalysisListener extends AutoCloseable {

View File

@ -216,30 +216,6 @@ class PmdConfigurationTest {
assertEquals(0, configuration.getReportProperties().size(), "Replaced report properties size");
}
@Test
void testDebug() {
PMDConfiguration configuration = new PMDConfiguration();
assertEquals(false, configuration.isDebug(), "Default debug");
configuration.setDebug(true);
assertEquals(true, configuration.isDebug(), "Changed debug");
}
@Test
void testStressTest() {
PMDConfiguration configuration = new PMDConfiguration();
assertEquals(false, configuration.isStressTest(), "Default stress test");
configuration.setStressTest(true);
assertEquals(true, configuration.isStressTest(), "Changed stress test");
}
@Test
void testBenchmark() {
PMDConfiguration configuration = new PMDConfiguration();
assertEquals(false, configuration.isBenchmark(), "Default benchmark");
configuration.setBenchmark(true);
assertEquals(true, configuration.isBenchmark(), "Changed benchmark");
}
@Test
void testAnalysisCache(@TempDir Path folder) throws IOException {
final PMDConfiguration configuration = new PMDConfiguration();

View File

@ -1,110 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cli;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.cache.NoopAnalysisCache;
import net.sourceforge.pmd.lang.LanguageRegistry;
import com.github.stefanbirkner.systemlambda.SystemLambda;
/**
* Unit test for {@link PMDCommandLineInterface}
*/
class PMDCommandLineInterfaceTest {
@BeforeEach
void clearSystemProperties() {
System.clearProperty(PMDCommandLineInterface.NO_EXIT_AFTER_RUN);
System.clearProperty(PMDCommandLineInterface.STATUS_CODE_PROPERTY);
}
@Test
void testProperties() {
PMDParameters params = new PMDParameters();
String[] args = { "-d", "source_folder", "-f", "yahtml", "-P", "outputDir=output_folder", "-R", "java-empty", };
PMDCommandLineInterface.extractParameters(params, args, "PMD");
assertEquals("output_folder", params.getProperties().getProperty("outputDir"));
}
@Test
void testMultipleProperties() {
PMDParameters params = new PMDParameters();
String[] args = { "-d", "source_folder", "-f", "ideaj", "-P", "sourcePath=/home/user/source/", "-P",
"fileName=Foo.java", "-P", "classAndMethodName=Foo.method", "-R", "java-empty", };
PMDCommandLineInterface.extractParameters(params, args, "PMD");
assertEquals("/home/user/source/", params.getProperties().getProperty("sourcePath"));
assertEquals("Foo.java", params.getProperties().getProperty("fileName"));
assertEquals("Foo.method", params.getProperties().getProperty("classAndMethodName"));
}
@Test
void testNoCacheSwitch() {
PMDParameters params = new PMDParameters();
String[] args = {"-d", "source_folder", "-f", "ideaj", "-R", "java-empty", "-cache", "/home/user/.pmd/cache", "-no-cache", };
PMDCommandLineInterface.extractParameters(params, args, "PMD");
assertTrue(params.isIgnoreIncrementalAnalysis());
PMDConfiguration config = params.toConfiguration(LanguageRegistry.PMD);
assertTrue(config.isIgnoreIncrementalAnalysis());
assertTrue(config.getAnalysisCache() instanceof NoopAnalysisCache);
}
@Test
void testNoCacheSwitchLongOption() {
PMDParameters params = new PMDParameters();
String[] args = {"-d", "source_folder", "-f", "ideaj", "-R", "java-empty", "--cache", "/home/user/.pmd/cache", "--no-cache", };
PMDCommandLineInterface.extractParameters(params, args, "PMD");
assertTrue(params.isIgnoreIncrementalAnalysis());
PMDConfiguration config = params.toConfiguration();
assertTrue(config.isIgnoreIncrementalAnalysis());
assertTrue(config.getAnalysisCache() instanceof NoopAnalysisCache);
}
@Test
void testSetStatusCodeOrExitDoExit() throws Exception {
int code = SystemLambda.catchSystemExit(() -> PMDCommandLineInterface.setStatusCodeOrExit(0));
assertEquals(0, code);
}
@Test
void testSetStatusCodeOrExitSetStatus() {
System.setProperty(PMDCommandLineInterface.NO_EXIT_AFTER_RUN, "1");
PMDCommandLineInterface.setStatusCodeOrExit(0);
assertEquals(System.getProperty(PMDCommandLineInterface.STATUS_CODE_PROPERTY), "0");
}
@Test
void testBuildUsageText() {
// no exception..
assertNotNull(PMDCommandLineInterface.buildUsageText());
}
@Test
void testOnlyFileListOption() {
PMDParameters params = new PMDParameters();
String[] args = {"--file-list", "pmd.filelist", "-f", "text", "-R", "rulesets/java/quickstart.xml", "--no-cache", };
PMDCommandLineInterface.extractParameters(params, args, "PMD");
PMDConfiguration config = params.toConfiguration();
assertEquals("pmd.filelist", config.getInputFile().toString());
assertThat(config.getInputPathList(), empty()); // no additional input paths
}
}

View File

@ -1,76 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.cli;
import static net.sourceforge.pmd.util.CollectionUtil.listOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.nio.file.Path;
import org.junit.jupiter.api.Test;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.util.CollectionUtil;
class PMDParametersTest {
@Test
void testMultipleDirsAndRuleSets() {
PmdParametersParseResult result = PmdParametersParseResult.extractParameters(
"-d", "a", "b", "-R", "x.xml", "y.xml"
);
assertMultipleDirsAndRulesets(result);
}
@Test
void testMultipleDirsAndRuleSetsWithCommas() {
PmdParametersParseResult result = PmdParametersParseResult.extractParameters(
"-d", "a,b", "-R", "x.xml,y.xml"
);
assertMultipleDirsAndRulesets(result);
}
@Test
void testMultipleDirsAndRuleSetsWithRepeatedOption() {
PmdParametersParseResult result = PmdParametersParseResult.extractParameters(
"-d", "a", "-d", "b", "-R", "x.xml", "-R", "y.xml"
);
assertMultipleDirsAndRulesets(result);
}
@Test
void testNoPositionalParametersAllowed() {
assertError(
// vvvv
"-R", "x.xml", "-d", "a", "--", "-d", "b"
);
}
private void assertMultipleDirsAndRulesets(PmdParametersParseResult result) {
assertFalse(result.isError());
PMDConfiguration config = result.toConfiguration();
assertEquals(CollectionUtil.map(config.getInputPathList(), Path::toString), listOf("a", "b"));
assertEquals(config.getRuleSetPaths(), listOf("x.xml", "y.xml"));
}
@Test
void testEmptyDirOption() {
assertError("-d", "-R", "y.xml");
}
@Test
void testEmptyRulesetOption() {
assertError("-R", "-d", "something");
}
private void assertError(String... params) {
PmdParametersParseResult result = PmdParametersParseResult.extractParameters(params);
assertTrue(result.isError());
}
}

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