diff --git a/docs/_config.yml b/docs/_config.yml index 4dc5eee07d..540e3ad8ae 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -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 diff --git a/docs/pages/pmd/devdocs/how_pmd_works.md b/docs/pages/pmd/devdocs/how_pmd_works.md index 1ac3f99929..f91b76757d 100644 --- a/docs/pages/pmd/devdocs/how_pmd_works.md +++ b/docs/pages/pmd/devdocs/how_pmd_works.md @@ -9,10 +9,7 @@ author: Tom Copeland, Andreas Dangel ## 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 diff --git a/docs/pages/pmd/userdocs/suppressing_warnings.md b/docs/pages/pmd/userdocs/suppressing_warnings.md index 68bf5e4379..da433e6469 100644 --- a/docs/pages/pmd/userdocs/suppressing_warnings.md +++ b/docs/pages/pmd/userdocs/suppressing_warnings.md @@ -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: diff --git a/docs/pages/pmd/userdocs/tools/java-api.md b/docs/pages/pmd/userdocs/tools/java-api.md index 36ebb017ea..5347e7b56a 100644 --- a/docs/pages/pmd/userdocs/tools/java-api.md +++ b/docs/pages/pmd/userdocs/tools/java-api.md @@ -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. diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index a3c12dd7d9..6ff8f01214 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -34,64 +34,10 @@ for all.

{% 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 %} - diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index acece18793..f773376557 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -7,6 +7,631 @@ Previous versions of PMD can be downloaded here: https://github.com/pmd/pmd/rele +## 29-April-2023 - 7.0.0-rc2 + +We're excited to bring you the next major version of PMD! + +Since this is a big release, we provide here only a concise version of the release notes. We prepared a separate +page with the full [Detailed Release Notes for PMD 7.0.0](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_release_notes_pmd7.html). + +
+ℹ️ Release Candidates +

PMD 7.0.0 is finally almost ready. In order to gather feedback, we are going to ship a couple of release candidates. +These are officially available on GitHub and Maven Central and can be used as usual (e.g. as a dependency). +We encourage you to try out the new features, but keep in mind that we may introduce API breaking changes between +the release candidates. It should be stable enough if you don't use custom rules.

+ +

We have still some tasks planned for the next release candidates. +You can see the progress in PMD 7 Tracking Issue #3898.

+ +

If you find any problem or difficulty while updating from PMD 6, please provide feedback via our +issue tracker. That way we can improve the experience +for all.

+
+ +### Table Of Contents + +* [Changes since 7.0.0-rc1](#changes-since-7.0.0-rc1) + * [API Changes](#api-changes) + * [Updated PMD Designer](#updated-pmd-designer) + * [Language Related Changes](#language-related-changes) + * [Rule Changes](#rule-changes) + * [Fixed Issues](#fixed-issues) + * [External contributions](#external-contributions) +* [🚀 Major Features and Enhancements](#🚀-major-features-and-enhancements) + * [New official logo](#new-official-logo) + * [Revamped Java module](#revamped-java-module) + * [Revamped Command Line Interface](#revamped-command-line-interface) + * [Full Antlr support](#full-antlr-support) + * [Updated PMD Designer](#updated-pmd-designer) +* [🎉 Language Related Changes](#🎉-language-related-changes) + * [New: Swift support](#new:-swift-support) + * [New: Kotlin support (experimental)](#new:-kotlin-support-(experimental)) + * [New: CPD support for TypeScript](#new:-cpd-support-for-typescript) + * [New: CPD support for Julia](#new:-cpd-support-for-julia) + * [Changed: JavaScript support](#changed:-javascript-support) + * [Changed: Language versions](#changed:-language-versions) +* [🌟 New and changed rules](#🌟-new-and-changed-rules) + * [New Rules](#new-rules) + * [Changed Rules](#changed-rules) + * [Removed Rules](#removed-rules) +* [🚨 API](#🚨-api) +* [💥 Compatibility and migration notes](#💥-compatibility-and-migration-notes) +* [🐛 Fixed Issues](#🐛-fixed-issues) +* [✨ External Contributions](#✨-external-contributions) +* [📈 Stats](#📈-stats) + +### Changes since 7.0.0-rc1 + +This section lists the most important changes from the last release candidate. +The remaining section describes the complete release notes for 7.0.0. + +#### API Changes +* Moved the two classes AntlrTokenizer and JavaCCTokenizer from + `internal` package into package net.sourceforge.pmd.cpd.impl. These two classes are part of the API and + are base classes for CPD language implementations. +* `AntlrBaseRule` is gone in favor of AbstractVisitorRule. +* The classes KotlinInnerNode and SwiftInnerNode + are package-private now. +* The parameter order of addSourceFile 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). + +#### Language Related Changes +* New: CPD support for TypeScript +* New: CPD support for Julia + +#### Rule Changes +* [`ImmutableField`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#immutablefield): the property `ignoredAnnotations` has been removed. The property was + deprecated since PMD 6.52.0. +* [`SwitchDensity`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#switchdensity): the type of the property `minimum` has been changed from decimal to integer + for consistency with other statistical rules. + +#### 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 +* [#4402](https://github.com/pmd/pmd/pull/4402): \[javascript] CPD: add support for Typescript using antlr4 grammar - [Paul Guyot](https://github.com/pguyot) (@pguyot) +* [#4403](https://github.com/pmd/pmd/pull/4403): \[julia] CPD: Add support for Julia code duplication - [Wener](https://github.com/wener-tiobe) (@wener-tiobe) +* [#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) + +### 🚀 Major Features and Enhancements + +#### New official logo + +The new official logo of PMD: + +![New PMD Logo](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/images/logo/pmd-logo-300px.png) + +#### Revamped Java module + +* Java grammar substantially refactored - more correct regarding the Java Language Specification (JLS) +* Built-in rules have been upgraded for the changed AST +* Rewritten type resolution framework and symbol table correctly implements the JLS +* AST exposes more semantic information (method calls, field accesses) + +For more information, see the [Detailed Release Notes for PMD 7](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_release_notes_pmd7.html). + +Contributors: [Clément Fournier](https://github.com/oowekyala) (@oowekyala), +[Andreas Dangel](https://github.com/adangel) (@adangel), +[Juan Martín Sotuyo Dodero](https://github.com/jsotuyod) (@jsotuyod) + +#### Revamped Command Line Interface + +* unified and consistent Command Line Interface for both Linux/Unix and Windows across our different utilities +* single script `pmd` (`pmd.bat` for Windows) to launch the different utilities: + * `pmd check` to run PMD rules and analyze a project + * `pmd cpd` to run CPD (copy paste detector) + * `pmd designer` to run the PMD Rule Designer +* progress bar support for `pmd check` +* shell completion + +![Demo](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/images/userdocs/pmd-demo.gif) + +For more information, see the [Detailed Release Notes for PMD 7](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_release_notes_pmd7.html). + +Contributors: [Juan Martín Sotuyo Dodero](https://github.com/jsotuyod) (@jsotuyod) + +#### Full Antlr support + +* [Antlr](https://www.antlr.org/) based grammars can now be used to build full-fledged PMD rules. +* Previously, Antlr grammar could only be used for CPD +* New supported languages: Swift and Kotlin + +For more information, see the [Detailed Release Notes for PMD 7](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_release_notes_pmd7.html). + +Contributors: [Lucas Soncini](https://github.com/lsoncini) (@lsoncini), +[Matías Fraga](https://github.com/matifraga) (@matifraga), +[Tomás De Lucca](https://github.com/tomidelucca) (@tomidelucca) + +#### 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). + +### 🎉 Language Related Changes + +Note that this is just a concise listing of the highlight. +For more information on the languages, see the [Detailed Release Notes for PMD 7](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_release_notes_pmd7.html). + +#### New: Swift support + +* use PMD to analyze Swift code with PMD rules +* initially 4 built-in rules + +Contributors: [Lucas Soncini](https://github.com/lsoncini) (@lsoncini), +[Matías Fraga](https://github.com/matifraga) (@matifraga), +[Tomás De Lucca](https://github.com/tomidelucca) (@tomidelucca) + +#### New: Kotlin support (experimental) + +* use PMD to analyze Kotlin code with PMD rules +* Support for Kotlin 1.8 grammar +* initially 2 built-in rules + +#### 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 + +* latest version supports ES6 and also some new constructs (see [Rhino](https://github.com/mozilla/rhino)]) +* comments are retained + +#### Changed: Language versions + +* more predefined language versions for each supported language +* can be used to limit rule execution for specific versions only with `minimumLanguageVersion` and + `maximumLanguageVersion` attributes. + +### 🌟 New and changed rules + +#### New Rules + +**Apex** +* [`UnusedMethod`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_apex_design.html#unusedmethod) finds unused methods in your code. + +**Java** +* [`UnnecessaryBoxing`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_codestyle.html#unnecessaryboxing) reports boxing and unboxing conversions that may be made implicit. + +**Kotlin** +* [`FunctionNameTooShort`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_kotlin_bestpractices.html#functionnametooshort) +* [`OverrideBothEqualsAndHashcode`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_kotlin_errorprone.html#overridebothequalsandhashcode) + +**Swift** +* [`ProhibitedInterfaceBuilder`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_swift_bestpractices.html#prohibitedinterfacebuilder) +* [`UnavailableFunction`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_swift_bestpractices.html#unavailablefunction) +* [`ForceCast`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_swift_errorprone.html#forcecast) +* [`ForceTry`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_swift_errorprone.html#forcetry) + +#### Changed Rules + +**General changes** + +* 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: [`ExcessiveClassLength`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_apex_design.html#excessiveclasslength), [`ExcessiveParameterList`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_apex_design.html#excessiveparameterlist), + [`ExcessivePublicCount`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_apex_design.html#excessivepubliccount), [`NcssConstructorCount`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_apex_design.html#ncssconstructorcount), + [`NcssMethodCount`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_apex_design.html#ncssmethodcount), [`NcssTypeCount`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_apex_design.html#ncsstypecount) + * Java: [`ExcessiveImports`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#excessiveimports), [`ExcessiveParameterList`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#excessiveparameterlist), + [`ExcessivePublicCount`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#excessivepubliccount), [`SwitchDensity`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#switchdensity) + * PLSQL: [`ExcessiveMethodLength`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_plsql_design.html#excessivemethodlength), [`ExcessiveObjectLength`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_plsql_design.html#excessiveobjectlength), + [`ExcessivePackageBodyLength`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_plsql_design.html#excessivepackagebodylength), [`ExcessivePackageSpecificationLength`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_plsql_design.html#excessivepackagespecificationlength), + [`ExcessiveParameterList`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_plsql_design.html#excessiveparameterlist), [`ExcessiveTypeLength`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_plsql_design.html#excessivetypelength), + [`NcssMethodCount`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_plsql_design.html#ncssmethodcount), [`NcssObjectCount`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_plsql_design.html#ncssobjectcount), + [`NPathComplexity`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_plsql_design.html#npathcomplexity) + * VM: [`ExcessiveTemplateLength`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_vm_design.html#excessivetemplatelength) + +* The general property `violationSuppressXPath` which is available for all rules to + [suppress warnings](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/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. [`CognitiveComplexity`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#cognitivecomplexity). + + The report location is controlled by the overrides of the method 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** + +* [`ArrayIsStoredDirectly`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_bestpractices.html#arrayisstoreddirectly): Violations are now reported on the assignment and not + anymore on the formal parameter. The reported line numbers will probably move. +* [`AvoidReassigningLoopVariables`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_bestpractices.html#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. +* [`LooseCoupling`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_bestpractices.html#loosecoupling): The rule has a new property to allow some types to be coupled + to (`allowedTypes`). +* [`UnusedLocalVariable`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_bestpractices.html#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** + +* [`MethodNamingConventions`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_codestyle.html#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. +* [`ShortVariable`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_codestyle.html#shortvariable): This rule now also reports short enum constant names. +* [`UseDiamondOperator`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_codestyle.html#usediamondoperator): The property `java7Compatibility` has been removed. The rule now + handles Java 7 properly without a property. +* [`UnnecessaryFullyQualifiedName`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_codestyle.html#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. +* [`UselessParentheses`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_codestyle.html#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. + +**Java Design** + +* [`CyclomaticComplexity`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#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. +* [`ImmutableField`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#immutablefield): The property `ignoredAnnotations` has been removed. The property was + deprecated since PMD 6.52.0. +* [`LawOfDemeter`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#lawofdemeter): The rule has a new property `trustRadius`. This defines the maximum degree + of trusted data. The default of 1 is the most restrictive. +* [`NPathComplexity`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#npathcomplexity): The property `minimum` has been removed. It was deprecated since PMD 6.0.0. + Use the property `reportLevel` instead. +* [`SingularField`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#singularfield): The properties `checkInnerClasses` and `disallowNotAssignment` have been removed. + The rule is now more precise and will check these cases properly. +* [`UseUtilityClass`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_design.html#useutilityclass): The property `ignoredAnnotations` has been removed. + +**Java Documentation** + +* [`CommentContent`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_documentation.html#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. +* [`CommentRequired`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_documentation.html#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. +* [`CommentSize`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_documentation.html#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** + +* [`AvoidDuplicateLiterals`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_errorprone.html#avoidduplicateliterals): The property `exceptionfile` has been removed. The property was + deprecated since PMD 6.10.0. Use the property `exceptionList` instead. +* [`DontImportSun`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_errorprone.html#dontimportsun): `sun.misc.Signal` is not special-cased anymore. +* [`EmptyCatchBlock`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_errorprone.html#emptycatchblock): `CloneNotSupportedException` and `InterruptedException` are not + special-cased anymore. Rename the exception parameter to `ignored` to ignore them. +* [`ImplicitSwitchFallThrough`](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_rules_java_errorprone.html#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 + +Many rules, that were previously deprecated have been finally removed. +See [Detailed Release Notes for PMD 7](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_release_notes_pmd7.html) for the complete list. + +### 🚨 API + +The API of PMD has been growing over the years and needed some cleanup. The goal is, to +have a clear separation between a well-defined API and the implementation, which is internal. +This should help us in future development. + +Also, there are some improvement and changes in different areas. For the detailed description +of the changes listed here, see [Detailed Release Notes for PMD 7](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_release_notes_pmd7.html). + +* Miscellaneous smaller changes and cleanups +* XPath 3.1 support for XPath-based rules +* Node stream API for AST traversal +* Metrics framework +* Testing framework +* Language Lifecycle and Language Properties + +### 💥 Compatibility and migration notes +See [Detailed Release Notes for PMD 7](https://docs.pmd-code.org/pmd-doc-7.0.0-rc2/pmd_release_notes_pmd7.html). + +### 🐛 Fixed Issues + +* miscellaneous + * [#881](https://github.com/pmd/pmd/issues/881): \[all] Breaking API changes for 7.0.0 + * [#896](https://github.com/pmd/pmd/issues/896): \[all] Use slf4j + * [#1431](https://github.com/pmd/pmd/pull/1431): \[ui] Remove old GUI applications (designerold, bgastviewer) + * [#1451](https://github.com/pmd/pmd/issues/1451): \[core] RulesetFactoryCompatibility stores the whole ruleset file in memory as a string + * [#2496](https://github.com/pmd/pmd/issues/2496): Update PMD 7 Logo on landing page + * [#2497](https://github.com/pmd/pmd/issues/2497): PMD 7 Logo page + * [#2498](https://github.com/pmd/pmd/issues/2498): Update PMD 7 Logo in documentation + * [#3797](https://github.com/pmd/pmd/issues/3797): \[all] Use JUnit5 + * [#4462](https://github.com/pmd/pmd/issues/4462): Provide Software Bill of Materials (SBOM) +* ant + * [#4080](https://github.com/pmd/pmd/issues/4080): \[ant] Split off Ant integration into a new submodule +* core + * [#880](https://github.com/pmd/pmd/issues/880): \[core] Make visitors generic + * [#1622](https://github.com/pmd/pmd/pull/1622): \[core] NodeStream API + * [#1687](https://github.com/pmd/pmd/issues/1687): \[core] Deprecate and Remove XPath 1.0 support + * [#1785](https://github.com/pmd/pmd/issues/1785): \[core] Allow abstract node types to be valid rulechain visits + * [#1825](https://github.com/pmd/pmd/pull/1825): \[core] Support NoAttribute for XPath + * [#2038](https://github.com/pmd/pmd/issues/2038): \[core] Remove DCD + * [#2218](https://github.com/pmd/pmd/issues/2218): \[core] `isFindBoundary` should not be an attribute + * [#2234](https://github.com/pmd/pmd/issues/2234): \[core] Consolidate PMD CLI into a single command + * [#2239](https://github.com/pmd/pmd/issues/2239): \[core] Merging Javacc build scripts + * [#2500](https://github.com/pmd/pmd/issues/2500): \[core] Clarify API for ANTLR based languages + * [#2518](https://github.com/pmd/pmd/issues/2518): \[core] Language properties + * [#2602](https://github.com/pmd/pmd/issues/2602): \[core] Remove ParserOptions + * [#2614](https://github.com/pmd/pmd/pull/2614): \[core] Upgrade Saxon, add XPath 3.1, remove Jaxen + * [#2696](https://github.com/pmd/pmd/pull/2696): \[core] Remove DFA + * [#2821](https://github.com/pmd/pmd/issues/2821): \[core] Rule processing error filenames are missing paths + * [#2873](https://github.com/pmd/pmd/issues/2873): \[core] Utility classes in pmd 7 + * [#2885](https://github.com/pmd/pmd/issues/2885): \[core] Error recovery mode + * [#3203](https://github.com/pmd/pmd/issues/3203): \[core] Replace RuleViolationFactory implementations with ViolationDecorator + * [#3692](https://github.com/pmd/pmd/pull/3692): \[core] Analysis listeners + * [#3782](https://github.com/pmd/pmd/issues/3782): \[core] Language lifecycle + * [#3815](https://github.com/pmd/pmd/issues/3815): \[core] Update Saxon HE to 10.7 + * [#3893](https://github.com/pmd/pmd/pull/3893): \[core] Text documents + * [#3902](https://github.com/pmd/pmd/issues/3902): \[core] Violation decorators + * [#3918](https://github.com/pmd/pmd/issues/3918): \[core] Make LanguageRegistry non static + * [#3922](https://github.com/pmd/pmd/pull/3922): \[core] Better error reporting for the ruleset parser + * [#4035](https://github.com/pmd/pmd/issues/4035): \[core] ConcurrentModificationException in DefaultRuleViolationFactory + * [#4120](https://github.com/pmd/pmd/issues/4120): \[core] Explicitly name all language versions + * [#4353](https://github.com/pmd/pmd/pull/4353): \[core] Micro optimizations for Node API + * [#4365](https://github.com/pmd/pmd/pull/4365): \[core] Improve benchmarking + * [#4420](https://github.com/pmd/pmd/pull/4420): \[core] Remove PMD.EOL +* cli + * [#2234](https://github.com/pmd/pmd/issues/2234): \[core] Consolidate PMD CLI into a single command + * [#3828](https://github.com/pmd/pmd/issues/3828): \[core] Progress reporting + * [#4079](https://github.com/pmd/pmd/issues/4079): \[cli] Split off CLI implementation into a pmd-cli submodule + * [#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 +* 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 +* testing + * [#2435](https://github.com/pmd/pmd/issues/2435): \[test] Remove duplicated Dummy language module + * [#4234](https://github.com/pmd/pmd/issues/4234): \[test] Tests that change the logging level do not work + +Language specific fixes: + +* apex + * [#1937](https://github.com/pmd/pmd/issues/1937): \[apex] Apex should only have a single RootNode + * [#1648](https://github.com/pmd/pmd/issues/1648): \[apex,vf] Remove CodeClimate dependency + * [#1750](https://github.com/pmd/pmd/pull/1750): \[apex] Remove apex statistical rules + * [#2836](https://github.com/pmd/pmd/pull/2836): \[apex] Remove Apex ProjectMirror + * [#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 + * [#905](https://github.com/pmd/pmd/issues/905): \[java] Add new node for anonymous class declaration + * [#910](https://github.com/pmd/pmd/issues/910): \[java] AST inconsistency between primitive and reference type arrays + * [#997](https://github.com/pmd/pmd/issues/997): \[java] Java8 parsing corner case with annotated array types + * [#998](https://github.com/pmd/pmd/issues/998): \[java] AST inconsistencies around FormalParameter + * [#1019](https://github.com/pmd/pmd/issues/1019): \[java] Breaking Java Grammar changes for PMD 7.0.0 + * [#1124](https://github.com/pmd/pmd/issues/1124): \[java] ImmutableList implementation in the qname codebase + * [#1128](https://github.com/pmd/pmd/issues/1128): \[java] Improve ASTLocalVariableDeclaration + * [#1150](https://github.com/pmd/pmd/issues/1150): \[java] ClassOrInterfaceType AST improvements + * [#1207](https://github.com/pmd/pmd/issues/1207): \[java] Resolve explicit types using FQCNs, without hitting the classloader + * [#1367](https://github.com/pmd/pmd/issues/1367): \[java] Parsing error on annotated inner class + * [#1661](https://github.com/pmd/pmd/issues/1661): \[java] About operator nodes + * [#2366](https://github.com/pmd/pmd/pull/2366): \[java] Remove qualified names + * [#2819](https://github.com/pmd/pmd/issues/2819): \[java] GLB bugs in pmd 7 + * [#3642](https://github.com/pmd/pmd/issues/3642): \[java] Parse error on rare extra dimensions on method return type on annotation methods + * [#3763](https://github.com/pmd/pmd/issues/3763): \[java] Ambiguous reference error in valid code + * [#3749](https://github.com/pmd/pmd/issues/3749): \[java] Improve `isOverridden` in ASTMethodDeclaration + * [#3750](https://github.com/pmd/pmd/issues/3750): \[java] Make symbol table support instanceof pattern bindings + * [#3752](https://github.com/pmd/pmd/issues/3752): \[java] Expose annotations in symbol API + * [#4237](https://github.com/pmd/pmd/pull/4237): \[java] Cleanup handling of Java comments + * [#4317](https://github.com/pmd/pmd/issues/4317): \[java] Some AST nodes should not be TypeNodes + * [#4359](https://github.com/pmd/pmd/issues/4359): \[java] Type resolution fails with NPE when the scope is not a type declaration + * [#4367](https://github.com/pmd/pmd/issues/4367): \[java] Move testrule TypeResTest into internal +* java-bestpractices + * [#342](https://github.com/pmd/pmd/issues/342): \[java] AccessorMethodGeneration: Name clash with another public field not properly handled + * [#755](https://github.com/pmd/pmd/issues/755): \[java] AccessorClassGeneration false positive for private constructors + * [#770](https://github.com/pmd/pmd/issues/770): \[java] UnusedPrivateMethod yields false positive for counter-variant arguments + * [#807](https://github.com/pmd/pmd/issues/807): \[java] AccessorMethodGeneration false positive with overloads + * [#833](https://github.com/pmd/pmd/issues/833): \[java] ForLoopCanBeForeach should consider iterating on this + * [#1189](https://github.com/pmd/pmd/issues/1189): \[java] UnusedPrivateMethod false positive from inner class via external class + * [#1205](https://github.com/pmd/pmd/issues/1205): \[java] Improve ConstantsInInterface message to mention alternatives + * [#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] 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 + * [#1998](https://github.com/pmd/pmd/issues/1998): \[java] AccessorClassGeneration false-negative: subclass calls private constructor + * [#2130](https://github.com/pmd/pmd/issues/2130): \[java] UnusedLocalVariable: false-negative with array + * [#2147](https://github.com/pmd/pmd/issues/2147): \[java] JUnitTestsShouldIncludeAssert - false positives with lambdas and static methods + * [#2464](https://github.com/pmd/pmd/issues/2464): \[java] LooseCoupling must ignore class literals: ArrayList.class + * [#2542](https://github.com/pmd/pmd/issues/2542): \[java] UseCollectionIsEmpty can not detect the case `foo.bar().size()` + * [#2650](https://github.com/pmd/pmd/issues/2650): \[java] UseTryWithResources false positive when AutoCloseable helper used + * [#2796](https://github.com/pmd/pmd/issues/2796): \[java] UnusedAssignment false positive with call chains + * [#2797](https://github.com/pmd/pmd/issues/2797): \[java] MissingOverride long-standing issues + * [#2806](https://github.com/pmd/pmd/issues/2806): \[java] SwitchStmtsShouldHaveDefault false-positive with Java 14 switch non-fallthrough branches + * [#2822](https://github.com/pmd/pmd/issues/2822): \[java] LooseCoupling rule: Extend to cover user defined implementations and interfaces + * [#2843](https://github.com/pmd/pmd/pull/2843): \[java] Fix UnusedAssignment FP with field accesses + * [#2882](https://github.com/pmd/pmd/issues/2882): \[java] UseTryWithResources - false negative for explicit close + * [#2883](https://github.com/pmd/pmd/issues/2883): \[java] JUnitAssertionsShouldIncludeMessage false positive with method call + * [#2890](https://github.com/pmd/pmd/issues/2890): \[java] UnusedPrivateMethod false positive with generics + * [#2946](https://github.com/pmd/pmd/issues/2946): \[java] SwitchStmtsShouldHaveDefault false positive on enum inside enums + * [#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 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 + * [#2134](https://github.com/pmd/pmd/issues/2134): \[java] PreserveStackTrace not handling `Throwable.addSuppressed(...)` + * [#2299](https://github.com/pmd/pmd/issues/2299): \[java] UnnecessaryFullyQualifiedName false positive with similar package name + * [#2391](https://github.com/pmd/pmd/issues/2391): \[java] UseDiamondOperator FP when expected type and constructed type have a different parameterization + * [#2528](https://github.com/pmd/pmd/issues/2528): \[java] MethodNamingConventions - JUnit 5 method naming not support ParameterizedTest + * [#2739](https://github.com/pmd/pmd/issues/2739): \[java] UselessParentheses false positive for string concatenation + * [#2748](https://github.com/pmd/pmd/issues/2748): \[java] UnnecessaryCast false positive with unchecked cast + * [#2973](https://github.com/pmd/pmd/issues/2973): \[java] New rule: UnnecessaryBoxing + * [#3195](https://github.com/pmd/pmd/pull/3195): \[java] Improve rule UnnecessaryReturn to detect more cases + * [#3218](https://github.com/pmd/pmd/pull/3218): \[java] Generalize UnnecessaryCast to flag all unnecessary casts + * [#3221](https://github.com/pmd/pmd/issues/3221): \[java] PrematureDeclaration false positive for unused variables + * [#3238](https://github.com/pmd/pmd/issues/3238): \[java] Improve ExprContext, fix FNs of UnnecessaryCast + * [#3500](https://github.com/pmd/pmd/pull/3500): \[java] UnnecessaryBoxing - check for Integer.valueOf(String) calls + * [#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 + * [#2160](https://github.com/pmd/pmd/issues/2160): \[java] Issues with Law of Demeter + * [#2175](https://github.com/pmd/pmd/issues/2175): \[java] LawOfDemeter: False positive for chained methods with generic method call + * [#2179](https://github.com/pmd/pmd/issues/2179): \[java] LawOfDemeter: False positive with static property access - should treat class-level property as global object, not dot-accessed property + * [#2180](https://github.com/pmd/pmd/issues/2180): \[java] LawOfDemeter: False positive with Thread and ThreadLocalRandom + * [#2182](https://github.com/pmd/pmd/issues/2182): \[java] LawOfDemeter: False positive with package-private access + * [#2188](https://github.com/pmd/pmd/issues/2188): \[java] LawOfDemeter: False positive with fields assigned to local vars + * [#2536](https://github.com/pmd/pmd/issues/2536): \[java] ClassWithOnlyPrivateConstructorsShouldBeFinal can't detect inner class + * [#3668](https://github.com/pmd/pmd/pull/3668): \[java] ClassWithOnlyPrivateConstructorsShouldBeFinal - fix FP with inner private classes + * [#3754](https://github.com/pmd/pmd/issues/3754): \[java] SingularField false positive with read in while condition + * [#3786](https://github.com/pmd/pmd/issues/3786): \[java] SimplifyBooleanReturns should consider operator precedence + * [#4238](https://github.com/pmd/pmd/pull/4238): \[java] Make LawOfDemeter not use the rulechain + * [#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-documentation + * [#4369](https://github.com/pmd/pmd/pull/4369): \[java] Improve CommentSize + * [#4416](https://github.com/pmd/pmd/pull/4416): \[java] Fix reported line number in CommentContentRule +* java-errorprone + * [#659](https://github.com/pmd/pmd/issues/659): \[java] MissingBreakInSwitch - last default case does not contain a break + * [#1005](https://github.com/pmd/pmd/issues/1005): \[java] CloneMethodMustImplementCloneable triggers for interfaces + * [#1669](https://github.com/pmd/pmd/issues/1669): \[java] NullAssignment - FP with ternay and null as constructor argument + * [#1899](https://github.com/pmd/pmd/issues/1899): \[java] Recognize @SuppressWanings("fallthrough") for MissingBreakInSwitch + * [#2320](https://github.com/pmd/pmd/issues/2320): \[java] NullAssignment - FP with ternary and null as method argument + * [#2532](https://github.com/pmd/pmd/issues/2532): \[java] AvoidDecimalLiteralsInBigDecimalConstructor can not detect the case `new BigDecimal(Expression)` + * [#2579](https://github.com/pmd/pmd/issues/2579): \[java] MissingBreakInSwitch detects the lack of break in the last case + * [#2880](https://github.com/pmd/pmd/issues/2880): \[java] CompareObjectsWithEquals - false negative with type res + * [#2893](https://github.com/pmd/pmd/issues/2893): \[java] Remove special cases from rule EmptyCatchBlock + * [#2894](https://github.com/pmd/pmd/issues/2894): \[java] Improve MissingBreakInSwitch + * [#3071](https://github.com/pmd/pmd/issues/3071): \[java] BrokenNullCheck FP with PMD 6.30.0 + * [#3087](https://github.com/pmd/pmd/issues/3087): \[java] UnnecessaryBooleanAssertion overlaps with SimplifiableTestAssertion + * [#3100](https://github.com/pmd/pmd/issues/3100): \[java] UseCorrectExceptionLogging FP in 6.31.0 + * [#3173](https://github.com/pmd/pmd/issues/3173): \[java] UseProperClassLoader false positive + * [#3351](https://github.com/pmd/pmd/issues/3351): \[java] ConstructorCallsOverridableMethod ignores abstract methods + * [#3400](https://github.com/pmd/pmd/issues/3400): \[java] AvoidUsingOctalValues FN with underscores + * [#3843](https://github.com/pmd/pmd/issues/3843): \[java] UseEqualsToCompareStrings should consider return type + * [#4356](https://github.com/pmd/pmd/pull/4356): \[java] Fix NPE in CloseResourceRule + * [#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()` + * [#2577](https://github.com/pmd/pmd/issues/2577): \[java] UseNotifyAllInsteadOfNotify falsely detect a special case with argument: `foo.notify(bar)` + * [#4483](https://github.com/pmd/pmd/issues/4483): \[java] NonThreadSafeSingleton false positive with double-checked locking +* java-performance + * [#1224](https://github.com/pmd/pmd/issues/1224): \[java] InefficientEmptyStringCheck false negative in anonymous class + * [#2587](https://github.com/pmd/pmd/issues/2587): \[java] AvoidArrayLoops could also check for list copy through iterated List.add() + * [#2712](https://github.com/pmd/pmd/issues/2712): \[java] SimplifyStartsWith false-positive with AssertJ + * [#3486](https://github.com/pmd/pmd/pull/3486): \[java] InsufficientStringBufferDeclaration: Fix NPE + * [#3848](https://github.com/pmd/pmd/issues/3848): \[java] StringInstantiation: false negative when using method result +* kotlin + * [#419](https://github.com/pmd/pmd/issues/419): \[kotlin] Add support for Kotlin + * [#4389](https://github.com/pmd/pmd/pull/4389): \[kotlin] Update grammar to version 1.8 +* swift + * [#1877](https://github.com/pmd/pmd/pull/1877): \[swift] Feature/swift rules + * [#1882](https://github.com/pmd/pmd/pull/1882): \[swift] UnavailableFunction Swift rule +* xml + * [#1800](https://github.com/pmd/pmd/pull/1800): \[xml] Unimplement org.w3c.dom.Node from the XmlNodeWrapper + +### ✨ External Contributions + +* [#1658](https://github.com/pmd/pmd/pull/1658): \[core] Node support for Antlr-based languages - [Matías Fraga](https://github.com/matifraga) (@matifraga) +* [#1698](https://github.com/pmd/pmd/pull/1698): \[core] [swift] Antlr Base Parser adapter and Swift Implementation - [Lucas Soncini](https://github.com/lsoncini) (@lsoncini) +* [#1774](https://github.com/pmd/pmd/pull/1774): \[core] Antlr visitor rules - [Lucas Soncini](https://github.com/lsoncini) (@lsoncini) +* [#1877](https://github.com/pmd/pmd/pull/1877): \[swift] Feature/swift rules - [Matías Fraga](https://github.com/matifraga) (@matifraga) +* [#1881](https://github.com/pmd/pmd/pull/1881): \[doc] Add ANTLR documentation - [Matías Fraga](https://github.com/matifraga) (@matifraga) +* [#1882](https://github.com/pmd/pmd/pull/1882): \[swift] UnavailableFunction Swift rule - [Tomás de Lucca](https://github.com/tomidelucca) (@tomidelucca) +* [#2830](https://github.com/pmd/pmd/pull/2830): \[apex] Apexlink POC - [Kevin Jones](https://github.com/nawforce) (@nawforce) +* [#3866](https://github.com/pmd/pmd/pull/3866): \[core] Add CLI Progress Bar - [@JerritEic](https://github.com/JerritEic) (@JerritEic) +* [#4402](https://github.com/pmd/pmd/pull/4402): \[javascript] CPD: add support for Typescript using antlr4 grammar - [Paul Guyot](https://github.com/pguyot) (@pguyot) +* [#4403](https://github.com/pmd/pmd/pull/4403): \[julia] CPD: Add support for Julia code duplication - [Wener](https://github.com/wener-tiobe) (@wener-tiobe) +* [#4412](https://github.com/pmd/pmd/pull/4412): \[doc] Added new error msg to ConstantsInInterface - [David Ljunggren](https://github.com/dague1) (@dague1) +* [#4428](https://github.com/pmd/pmd/pull/4428): \[apex] ApexBadCrypto bug fix for #4427 - inline detection of hard coded values - [Steven Stearns](https://github.com/sfdcsteve) (@sfdcsteve) +* [#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) + +### 📈 Stats +* 4557 commits +* 572 closed tickets & PRs +* Days since last release: 35 + + + ## 25-March-2023 - 7.0.0-rc1 We're excited to bring you the next major version of PMD! diff --git a/docs/pages/release_notes_pmd7.md b/docs/pages/release_notes_pmd7.md index 08f285d210..5579225cd2 100644 --- a/docs/pages/release_notes_pmd7.md +++ b/docs/pages/release_notes_pmd7.md @@ -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 diff --git a/pmd-ant/pom.xml b/pmd-ant/pom.xml index 7001eeddfc..26e41e525d 100644 --- a/pmd-ant/pom.xml +++ b/pmd-ant/pom.xml @@ -3,9 +3,7 @@ ~ BSD-style license; for more info see http://pmd.sourceforge.net/license.html --> - + pmd net.sourceforge.pmd diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml index b424122e23..e529fac558 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/ExcessivePublicCount.xml @@ -115,7 +115,7 @@ public class SomeClass { - class with inner classes + #4509 class with inner classes 1 2 1,5 diff --git a/pmd-cli/pom.xml b/pmd-cli/pom.xml index a144afdd06..2df635e272 100644 --- a/pmd-cli/pom.xml +++ b/pmd-cli/pom.xml @@ -38,7 +38,7 @@ -Dpicocli.autocomplete.systemExitOnError -cp - + picocli.AutoComplete --force --completionScript diff --git a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/CpdCommand.java b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/CpdCommand.java index da3fdacdc0..547b7633a5 100644 --- a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/CpdCommand.java +++ b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/CpdCommand.java @@ -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()); diff --git a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/PmdCommand.java b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/PmdCommand.java index 41472cff12..ac9f295265 100644 --- a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/PmdCommand.java +++ b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/PmdCommand.java @@ -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); diff --git a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/TreeExportCommand.java b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/TreeExportCommand.java index 452d1410fd..f9733ec230 100644 --- a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/TreeExportCommand.java +++ b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/TreeExportCommand.java @@ -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); diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index 621b770cde..2f57145455 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -49,10 +49,6 @@ org.antlr antlr4-runtime - - com.beust - jcommander - net.sf.saxon diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/AbstractConfiguration.java b/pmd-core/src/main/java/net/sourceforge/pmd/AbstractConfiguration.java index 671cf74da1..8fd6ea6dbb 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/AbstractConfiguration.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/AbstractConfiguration.java @@ -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 true then PMD - * will log debug information. - * - * @return true if debug logging is enabled, false - * 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; - } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java b/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java deleted file mode 100644 index 46d7ff111c..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMD.java +++ /dev/null @@ -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. - * - *

Warning: 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 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; - } - - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java index c471ca76ae..b6449b5129 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PMDConfiguration.java @@ -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}). * - *

There are several aspects to the configuration of PMD. + *

Rulesets

* - *

The aspects related to generic PMD behavior:

*
    - *
  • Suppress marker is used in source files to suppress a RuleViolation, - * defaults to {@value DEFAULT_SUPPRESS_MARKER}. {@link #getSuppressMarker()}
  • - *
  • The number of threads to create when invoking on multiple files, defaults - * one thread per available processor. {@link #getThreads()}
  • - *
  • A ClassLoader to use when loading classes during Rule processing (e.g. - * during type resolution), defaults to ClassLoader of the Configuration class. - * {@link #getClassLoader()}
  • - *
  • A means to configure a ClassLoader using a prepended classpath String, - * instead of directly setting it programmatically. - * {@link #prependAuxClasspath(String)}
  • - *
  • 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()}
  • + *
  • You can configure paths to the rulesets to use with {@link #addRuleSet(String)}. + * These can be file paths or classpath resources.
  • + *
  • Use {@link #setMinimumPriority(RulePriority)} to control the minimum priority a + * rule must have to be included. Defaults to the lowest priority, ie all rules are loaded.
  • + *
  • Use {@link #setRuleSetFactoryCompatibilityEnabled(boolean)} to disable the + * compatibility measures for removed and renamed rules in the rulesets that will + * be loaded. *
* - *

The aspects related to Rules and Source files are:

+ *

Source files

+ * *
    - *
  • RuleSets URIs: {@link #getRuleSetPaths()}
  • - *
  • A minimum priority threshold when loading Rules from RuleSets, defaults - * to {@link RulePriority#LOW}. {@link #getMinimumPriority()}
  • - *
  • The character encoding of source files, defaults to the system default as + *
  • The default encoding of source files is the system default as * returned by System.getProperty("file.encoding"). - * {@link #getSourceEncoding()}
  • - *
  • A list of input paths to process for source files. This - * may include files, directories, archives (e.g. ZIP files), etc. - * {@link #getInputPathList()}
  • - *
  • A flag which controls, whether {@link RuleSetLoader#enableCompatibility(boolean)} filter - * should be used or not: #isRuleSetFactoryCompatibilityEnabled; + * You can set it with {@link #setSourceEncoding(String)}.
  • + *
  • The source files to analyze can be given in many ways. See + * {@link #addInputPath(Path)} {@link #setInputFilePath(Path)}, {@link #setInputUri(URI)}. + *
  • Files are assigned a language based on their name. The language + * version of languages can be given with + * {@link #setDefaultLanguageVersion(LanguageVersion)}. + * The default language assignment can be overridden with + * {@link #setForceLanguageVersion(LanguageVersion)}.
  • *
* + *

Rendering

+ * *
    *
  • The renderer format to use for Reports. {@link #getReportFormat()}
  • *
  • The file to which the Report should render. {@link #getReportFile()}
  • @@ -91,14 +84,18 @@ import net.sourceforge.pmd.util.log.internal.SimpleMessageReporter; * {@link #isShowSuppressedViolations()} *
* - *

The aspects related to special PMD behavior are:

+ *

Language configuration

*
    - *
  • An indicator of whether PMD should log debug information. - * {@link #isDebug()}
  • - *
  • An indicator of whether PMD should perform stress testing behaviors, such - * as randomizing the order of file processing. {@link #isStressTest()}
  • - *
  • An indicator of whether PMD should log benchmarking information. - * {@link #isBenchmark()}
  • + *
  • Use {@link #setSuppressMarker(String)} to change the comment marker for suppression comments. Defaults to {@value #DEFAULT_SUPPRESS_MARKER}.
  • + *
  • See {@link #setClassLoader(ClassLoader)} and {@link #prependAuxClasspath(String)} for + * information for how to configure classpath for Java analysis.
  • + *
  • You can set additional language properties with {@link #getLanguageProperties(Language)}
  • + *
+ * + *

Miscellaneous

+ *
    + *
  • Use {@link #setThreads(int)} to control the parallelism of the analysis. Defaults + * one thread per available processor. {@link #getThreads()}
  • *
*/ public class PMDConfiguration extends AbstractConfiguration { @@ -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 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 { * file://) the file will be read with each line representing * an entry on the classpath.

* + *

You can specify multiple class paths separated by `:` on Unix-systems or `;` under Windows. + * See {@link File#pathSeparator}. + * * @param classpath The prepended classpath. * * @throws IllegalArgumentException if the given classpath is invalid (e.g. does not exist) @@ -738,60 +734,6 @@ public class PMDConfiguration extends AbstractConfiguration { this.reportProperties = reportProperties; } - /** - * Return the stress test indicator. If this value is true then - * PMD will randomize the order of file processing to attempt to shake out - * bugs. - * - * @return true if stress test is enbaled, false - * 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 true then - * PMD will log benchmark information. - * - * @return true if benchmark logging is enbaled, - * false 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.). diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java index 1bf5e9a584..638d6b97de 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/PmdAnalysis.java @@ -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. + * + *

Usage overview

+ * + * 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. + * + *

Simple example

+ * *
{@code
  *   PMDConfiguration config = new PMDConfiguration();
  *   config.setDefaultLanguageVersion(LanguageRegistry.findLanguageByTerseName("java").getVersion("11"));
@@ -81,6 +90,42 @@ import net.sourceforge.pmd.util.log.MessageReporter;
  *   }
  * }
* + *

Rendering reports

+ * + * 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)}. + * + *

Reports and events

+ * + *

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()}). + * + *

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. + * + *

If you want to process events in batches, one per file, you can + * use {@link Report.ReportBuilderListener}. to implement {@link GlobalAnalysisListener#startFileAnalysis(TextFile)}. + * + *

Listeners can be used alongside renderers. + * + *

Specifying the Java classpath

+ * + * Java rules work better if you specify the path to the compiled classes + * of the analysed sources. See {@link PMDConfiguration#prependAuxClasspath(String)}. + * + *

Customizing message output

+ * + *

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 { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDCommandLineInterface.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDCommandLineInterface.java deleted file mode 100644 index 02f80e9cc7..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDCommandLineInterface.java +++ /dev/null @@ -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 <belaran@gmail.com> - * @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(); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java deleted file mode 100644 index 2c96b29c8b..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java +++ /dev/null @@ -1,459 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.cli; - -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Properties; -import java.util.stream.Collectors; - -import org.apache.commons.lang3.StringUtils; -import org.checkerframework.checker.nullness.qual.NonNull; -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; - -import com.beust.jcommander.IStringConverter; -import com.beust.jcommander.IValueValidator; -import com.beust.jcommander.Parameter; -import com.beust.jcommander.ParameterException; -import com.beust.jcommander.validators.PositiveInteger; - -/** - * @deprecated Internal API. Use {@link PMD#runPmd(String[])} or {@link PMD#main(String[])} - */ -@Deprecated -@InternalApi -public class PMDParameters { - - static final String RELATIVIZE_PATHS_WITH = "--relativize-paths-with"; - @Parameter(names = { "--rulesets", "-rulesets", "-R" }, - description = "Path to a ruleset xml file. " - + "The path may reference a resource on the classpath of the application, be a local file system path, or a URL. " - + "The option can be repeated, and multiple arguments can be provided to a single occurrence of the option.", - required = true, - variableArity = true) - private List rulesets; - - @Parameter(names = { "--uri", "-uri", "-u" }, - description = "Database URI for sources. " - + "One of --dir, --file-list or --uri must be provided. " - ) - private String uri; - - @Parameter(names = { "--dir", "-dir", "-d" }, - description = "Path to a source file, or directory containing source files to analyze. " - // About the following line: - // In PMD 6, this is only the case for files found in directories. If you - // specify a file directly, and it is unknown, then the Java parser is used. - + "Note that a file is only effectively added if it matches a language known by PMD. " - + "Zip and Jar files are also supported, if they are specified directly " - + "(archive files found while exploring a directory are not recursively expanded). " - + "This option can be repeated, and multiple arguments can be provided to a single occurrence of the option. " - + "One of --dir, --file-list or --uri must be provided. ", - variableArity = true) - private List inputPaths = new ArrayList<>(); - - @Parameter(names = { "--file-list", "-filelist" }, - description = - "Path to a file containing a list of files to analyze, one path per line. " - + "One of --dir, --file-list or --uri must be provided. " - ) - private String fileListPath; - - @Parameter(names = { "--ignore-list", "-ignorelist" }, - description = "Path to a file containing a list of files to exclude from the analysis, one path per line. " - + "This option can be combined with --dir and --file-list. " - ) - private String ignoreListPath; - - @Parameter(names = { "--format", "-format", "-f" }, description = "Report format type.") - private String format = "text"; // Enhance to support other usage - - @Parameter(names = { "--debug", "--verbose", "-debug", "-verbose", "-D", "-V" }, description = "Debug mode.") - private boolean debug = false; - - @Parameter(names = { "--help", "-help", "-h", "-H" }, description = "Display help on usage.", help = true) - private boolean help = false; - - @Parameter(names = { "--encoding", "-encoding", "-e" }, - description = "Specifies the character set encoding of the source code files PMD is reading (i.e., UTF-8).") - private String encoding = "UTF-8"; - - @Parameter(names = { "--threads", "-threads", "-t" }, description = "Sets the number of threads used by PMD.", - validateWith = PositiveInteger.class) - private int threads = 1; // see also default in PMDTask (Ant) - - @Parameter(names = { "--benchmark", "-benchmark", "-b" }, - description = "Benchmark mode - output a benchmark report upon completion; default to System.err.") - private boolean benchmark = false; - - @Parameter(names = { "--stress", "-stress", "-S" }, description = "Performs a stress test.") - private boolean stress = false; - - @Parameter(names = { "--show-suppressed", "-showsuppressed" }, description = "Report should show suppressed rule violations.") - private boolean showsuppressed = false; - - @Parameter(names = { "--suppress-marker", "-suppressmarker" }, - description = "Specifies the string that marks a line which PMD should ignore; default is NOPMD.") - private String suppressmarker = "NOPMD"; - - @Parameter(names = { "--minimum-priority", "-minimumpriority", "-min" }, - description = "Rule priority threshold; rules with lower priority than configured here won't be used. " - + "Valid values are integers between 1 and 5 (inclusive), with 5 being the lowest priority.", - validateValueWith = RulePriorityValidator.class) - private int minimumPriority = RulePriority.LOW.getPriority(); - - @Parameter(names = { "--property", "-property", "-P" }, description = "{name}={value}: Define a property for the report format.", - converter = PropertyConverter.class) - private List properties = new ArrayList<>(); - - @Parameter(names = { "--report-file", "-reportfile", "-r" }, - description = "Path to a file to which report output is written. " - + "The file is created if it does not exist. " - + "If this option is not specified, the report is rendered to standard output.") - private String reportfile = null; - - @Parameter(names = { RELATIVIZE_PATHS_WITH, "-z" }, - variableArity = true, - description = "Path relative to which directories are rendered in the report. " - + "This option allows shortening directories in the report; " - + "without it, paths are rendered as mentioned in the source directory (option \"--dir\"). " - + "The option can be repeated, in which case the shortest relative path will be used. " - + "If the root path is mentioned (e.g. \"/\" or \"C:\\\"), then the paths will be rendered as absolute.", - validateValueWith = PathToRelativizeRootValidator.class, - converter = StringToPathConverter.class) - private List relativizePathRoot = new ArrayList<>(); - - @Parameter(names = { "-version", "-v" }, description = "Specify version of a language PMD should use.") - private String version = null; - - @Parameter(names = "--version", description = "Display current version of PMD and exit without performing any analysis.", help = true) - private boolean currentVersion = false; - - @Parameter(names = { "-language", "-l" }, description = "Specify a language PMD should use.") - private String language = null; - - @Parameter(names = { "--force-language", "-force-language" }, - description = "Force a language to be used for all input files, irrespective of file names. " - + "When using this option, the automatic language selection by extension is disabled, and PMD " - + "tries to parse all input files with the given language's parser. " - + "Parsing errors are ignored." - ) - private String forceLanguage = null; - - @Parameter(names = { "--aux-classpath", "-auxclasspath" }, - description = "Specifies the classpath for libraries used by the source code. " - + "This is used to resolve types in Java source files. The platform specific path delimiter " - + "(\":\" on Linux, \";\" on Windows) is used to separate the entries. " - + "Alternatively, a single 'file:' URL to a text file containing path elements on consecutive lines " - + "can be specified.") - private String auxclasspath; - - @Parameter(names = { "--fail-on-violation", "--failOnViolation", "-failOnViolation"}, arity = 1, - description = "By default PMD exits with status 4 if violations are found. Disable this option with '-failOnViolation false' to exit with 0 instead and just write the report.") - private boolean failOnViolation = true; - - @Parameter(names = { "--no-ruleset-compatibility", "-norulesetcompatibility" }, - description = "Disable the ruleset compatibility filter. The filter is active by default and tries automatically 'fix' old ruleset files with old rule names") - private boolean noRuleSetCompatibility = false; - - @Parameter(names = { "--cache", "-cache" }, arity = 1, - description = "Specify the location of the cache file for incremental analysis. " - + "This should be the full path to the file, including the desired file name (not just the parent directory). " - + "If the file doesn't exist, it will be created on the first run. The file will be overwritten on each run " - + "with the most up-to-date rule violations.") - private String cacheLocation = null; - - @Parameter(names = { "--no-cache", "-no-cache" }, description = "Explicitly disable incremental analysis. The '-cache' option is ignored if this switch is present in the command line.") - private boolean noCache = false; - - @Parameter(names = "--use-version", description = "The language version PMD should use when parsing source code in the language-version format, ie: 'java-1.8'") - private List languageVersions = new ArrayList<>(); - - // this has to be a public static class, so that JCommander can use it! - public static class PropertyConverter implements IStringConverter { - - private static final char SEPARATOR = '='; - - @Override - public Properties convert(String value) { - int indexOfSeparator = value.indexOf(SEPARATOR); - if (indexOfSeparator < 0) { - throw new ParameterException( - "Property name must be separated with an = sign from it value: name=value."); - } - String propertyName = value.substring(0, indexOfSeparator); - String propertyValue = value.substring(indexOfSeparator + 1); - Properties properties = new Properties(); - properties.put(propertyName, propertyValue); - return properties; - } - } - - - // this has to be a public static class, so that JCommander can use it! - public static class RulePriorityValidator implements IValueValidator { - - @Override - public void validate(String name, Integer value) throws ParameterException { - if (value < 1 || value > 5) { - throw new ParameterException("Priority values can only be integer value, between 1 and 5," + value + " is not valid"); - } - } - } - - public static class PathToRelativizeRootValidator implements IValueValidator> { - @Override - public void validate(String name, List value) throws ParameterException { - for (Path p : value) { - if (Files.isRegularFile(p)) { - throw new ParameterException("Expected a directory path for option " + name + ", found a file: " + p); - } - } - } - } - - public static class StringToPathConverter implements IStringConverter { - @Override - public Path convert(String value) { - return Paths.get(value); - } - } - - /** - * Converts these parameters into a configuration. - * - * @return A new PMDConfiguration corresponding to these parameters - * - * @throws IllegalArgumentException if the parameters are inconsistent or incomplete - */ - public PMDConfiguration toConfiguration() { - return toConfiguration(LanguageRegistry.PMD); - } - - /** - * Converts these parameters into a configuration. The given language - * registry is used to resolve references to languages in the parameters. - * - * @return A new PMDConfiguration corresponding to these parameters - * - * @throws IllegalArgumentException if the parameters are inconsistent or incomplete - */ - public @NonNull PMDConfiguration toConfiguration(LanguageRegistry registry) { - if (null == this.getSourceDir() && null == this.getUri() && null == this.getFileListPath()) { - throw new IllegalArgumentException( - "Please provide a parameter for source root directory (-dir or -d), database URI (-uri or -u), or file list path (-filelist)."); - } - PMDConfiguration configuration = new PMDConfiguration(); - configuration.setInputPaths(this.getInputPaths().stream().collect(Collectors.joining(","))); - configuration.setInputFilePath(this.getFileListPath()); - configuration.setIgnoreFilePath(this.getIgnoreListPath()); - configuration.setInputUri(this.getUri()); - configuration.setReportFormat(this.getFormat()); - configuration.setBenchmark(this.isBenchmark()); - configuration.setDebug(this.isDebug()); - configuration.addRelativizeRoots(this.relativizePathRoot); - configuration.setMinimumPriority(this.getMinimumPriority()); - configuration.setReportFile(this.getReportfile()); - configuration.setReportProperties(this.getProperties()); - configuration.setRuleSets(Arrays.asList(this.getRulesets().split(","))); - configuration.setRuleSetFactoryCompatibilityEnabled(!this.noRuleSetCompatibility); - configuration.setShowSuppressedViolations(this.isShowsuppressed()); - configuration.setSourceEncoding(this.getEncoding()); - configuration.setStressTest(this.isStress()); - configuration.setSuppressMarker(this.getSuppressmarker()); - configuration.setThreads(this.getThreads()); - configuration.setFailOnViolation(this.isFailOnViolation()); - configuration.setAnalysisCacheLocation(this.cacheLocation); - configuration.setIgnoreIncrementalAnalysis(this.isIgnoreIncrementalAnalysis()); - - LanguageVersion forceLangVersion = getForceLangVersion(registry); - if (forceLangVersion != null) { - configuration.setForceLanguageVersion(forceLangVersion); - } - - LanguageVersion languageVersion = getLangVersion(registry); - if (languageVersion != null) { - configuration.getLanguageVersionDiscoverer().setDefaultLanguageVersion(languageVersion); - } - - for (String langVerStr : this.getLanguageVersions()) { - int dashPos = langVerStr.indexOf('-'); - if (dashPos == -1) { - throw new IllegalArgumentException("Invalid language version: " + langVerStr); - } - String langStr = langVerStr.substring(0, dashPos); - String verStr = langVerStr.substring(dashPos + 1); - Language lang = LanguageRegistry.findLanguageByTerseName(langStr); - LanguageVersion langVer = null; - if (lang != null) { - langVer = lang.getVersion(verStr); - } - if (lang == null || langVer == null) { - throw new IllegalArgumentException("Invalid language version: " + langVerStr); - } - configuration.getLanguageVersionDiscoverer().setDefaultLanguageVersion(langVer); - } - - try { - configuration.prependAuxClasspath(this.getAuxclasspath()); - } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("Invalid auxiliary classpath: " + e.getMessage(), e); - } - return configuration; - } - - - public boolean isIgnoreIncrementalAnalysis() { - return noCache; - } - - - public boolean isDebug() { - return debug; - } - - public boolean isHelp() { - return help; - } - - public boolean isVersion() { - return currentVersion; - } - - public String getEncoding() { - return encoding; - } - - public Integer getThreads() { - return threads; - } - - public boolean isBenchmark() { - return benchmark; - } - - public boolean isStress() { - return stress; - } - - public boolean isShowsuppressed() { - return showsuppressed; - } - - public String getSuppressmarker() { - return suppressmarker; - } - - public RulePriority getMinimumPriority() { - return RulePriority.valueOf(minimumPriority); - } - - public Properties getProperties() { - Properties result = new Properties(); - for (Properties p : properties) { - result.putAll(p); - } - return result; - } - - public String getReportfile() { - return reportfile; - } - - private @Nullable LanguageVersion getLangVersion(LanguageRegistry registry) { - if (language != null) { - Language lang = registry.getLanguageById(language); - if (lang != null) { - return version != null ? lang.getVersion(version) - : lang.getDefaultVersion(); - } - } - return null; - } - - public @Nullable String getLanguage() { - return language; - } - - private @Nullable LanguageVersion getForceLangVersion(LanguageRegistry registry) { - Language lang = forceLanguage != null ? registry.getLanguageById(forceLanguage) : null; - return lang != null ? lang.getDefaultVersion() : null; - } - - public List getLanguageVersions() { - return languageVersions; - } - - public String getForceLanguage() { - return forceLanguage != null ? forceLanguage : ""; - } - - public String getAuxclasspath() { - return auxclasspath; - } - - @Deprecated - public String getRulesets() { - return StringUtils.join(rulesets, ","); - } - - public List getRulesetRefs() { - return rulesets; - } - - public List getInputPaths() { - return inputPaths; - } - - @Deprecated - public String getSourceDir() { - return StringUtils.join(inputPaths, ","); - } - - public String getFileListPath() { - return fileListPath; - } - - public String getIgnoreListPath() { - return ignoreListPath; - } - - public String getFormat() { - return format; - } - - public boolean isFailOnViolation() { - return failOnViolation; - } - - - /** - * @return the uri alternative to source directory. - */ - public String getUri() { - return uri; - } - - /** - * @param uri - * the uri specifying the source directory. - */ - public void setUri(String uri) { - this.uri = uri; - } - -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PmdParametersParseResult.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PmdParametersParseResult.java deleted file mode 100644 index a6ec665dba..0000000000 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PmdParametersParseResult.java +++ /dev/null @@ -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 deprecatedOptionsUsed; - - PmdParametersParseResult(PMDParameters result, - Map deprecatedOptionsUsed) { - this.result = Objects.requireNonNull(result); - this.deprecatedOptionsUsed = deprecatedOptionsUsed; - this.error = null; - } - - PmdParametersParseResult(ParameterException error, Map 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 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 filterDeprecatedOptions(String... args) { - Map 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 SUGGESTED_REPLACEMENT; - - - static { - Map 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); - } -} diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDConfiguration.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDConfiguration.java index efe6550261..6332ec8348 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDConfiguration.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDConfiguration.java @@ -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; - } } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/ShortFilenameUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/ShortFilenameUtil.java index cc081da613..fa10c36459 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/ShortFilenameUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/internal/util/ShortFilenameUtil.java @@ -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 inputPathPrefixes, String inputFileName) { for (final String prefix : inputPathPrefixes) { diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/Language.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/Language.java index 4d10b41e4d..66c5513bbd 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/Language.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/Language.java @@ -97,6 +97,17 @@ public interface Language extends Comparable { */ List getVersions(); + /** + * Returns the latest language version. May not be the + * {@linkplain #getDefaultVersion() default}. + * + * @return The latest language version + */ + default LanguageVersion getLatestVersion() { + List versions = getVersions(); + return versions.get(versions.size() - 1); + } + /** * Returns a complete set of supported version names for this language * including all aliases. diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractRenderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractRenderer.java index 58f5628135..b36f03ad28 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractRenderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/AbstractRenderer.java @@ -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. + * + *

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); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/Renderer.java b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/Renderer.java index ff84c4eff5..443eef1b1d 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/renderers/Renderer.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/renderers/Renderer.java @@ -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); diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/reporting/FileAnalysisListener.java b/pmd-core/src/main/java/net/sourceforge/pmd/reporting/FileAnalysisListener.java index f882ac7632..7ecc79018e 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/reporting/FileAnalysisListener.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/reporting/FileAnalysisListener.java @@ -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}. * *

Listeners are assumed to be ready to receive events as soon as they * are constructed. + * + * @see Report.ReportBuilderListener */ public interface FileAnalysisListener extends AutoCloseable { diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/PmdConfigurationTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/PmdConfigurationTest.java index 7fdc4933f6..210bef744c 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/PmdConfigurationTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/PmdConfigurationTest.java @@ -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(); diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDCommandLineInterfaceTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDCommandLineInterfaceTest.java deleted file mode 100644 index 4b3e03f256..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDCommandLineInterfaceTest.java +++ /dev/null @@ -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 - } -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDParametersTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDParametersTest.java deleted file mode 100644 index 67fdbaef77..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cli/PMDParametersTest.java +++ /dev/null @@ -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()); - } - -} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/LanguageParameterTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/LanguageParameterTest.java deleted file mode 100644 index 1033dc9242..0000000000 --- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/LanguageParameterTest.java +++ /dev/null @@ -1,27 +0,0 @@ -/** - * BSD-style license; for more info see http://pmd.sourceforge.net/license.html - */ - -package net.sourceforge.pmd.lang; - -import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; - -import net.sourceforge.pmd.cli.PMDCommandLineInterface; -import net.sourceforge.pmd.cli.PMDParameters; - -class LanguageParameterTest { - - /** Test that language parameters from the CLI are correctly passed through to the PMDConfiguration. Although this is a - * CLI test, it resides here to take advantage of {@link net.sourceforge.pmd.lang.DummyLanguageModule} - */ - @Test - void testLanguageFromCliToConfiguration() { - PMDParameters params = new PMDParameters(); - String[] args = { "-d", "source_folder", "-f", "ideaj", "-P", "sourcePath=/home/user/source/", "-R", "java-empty", "-force-language", "dummy"}; - PMDCommandLineInterface.extractParameters(params, args, "PMD"); - - assertEquals(DummyLanguageModule.getInstance().getDefaultVersion().getName(), params.toConfiguration().getForceLanguageVersion().getName()); - } -} diff --git a/pmd-cpp/pom.xml b/pmd-cpp/pom.xml index beb01403db..4f64a2da65 100644 --- a/pmd-cpp/pom.xml +++ b/pmd-cpp/pom.xml @@ -34,7 +34,7 @@ - + diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityRule.java index 21f8d2bcb1..40ea664a05 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityRule.java @@ -12,8 +12,8 @@ import net.sourceforge.pmd.lang.java.ast.ASTSwitchExpression; import net.sourceforge.pmd.lang.java.ast.ASTSwitchLike; import net.sourceforge.pmd.lang.java.ast.ASTSwitchStatement; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule; +import net.sourceforge.pmd.lang.rule.internal.CommonPropertyDescriptors; import net.sourceforge.pmd.properties.PropertyDescriptor; -import net.sourceforge.pmd.properties.PropertyFactory; /** * Switch Density - This is the number of statements over the number of @@ -28,13 +28,12 @@ import net.sourceforge.pmd.properties.PropertyFactory; */ public class SwitchDensityRule extends AbstractJavaRulechainRule { - private static final PropertyDescriptor REPORT_LEVEL = - // can't use CommonPropertyDescriptors because we need a double property - PropertyFactory.doubleProperty("minimum") - .desc("Threshold above which a node is reported") - .require(positive()) - .defaultValue(10d) - .build(); + private static final PropertyDescriptor REPORT_LEVEL = + CommonPropertyDescriptors.reportLevelProperty() + .desc("Threshold above which a switch statement or expression is reported") + .require(positive()) + .defaultValue(10) + .build(); public SwitchDensityRule() { super(ASTSwitchStatement.class, ASTSwitchExpression.class); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java index 66741473a1..e76992afdd 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPass.java @@ -633,18 +633,16 @@ public final class DataflowPass { @Override public SpanInfo visit(ASTForeachStatement node, SpanInfo data) { ASTStatement body = node.getBody(); - // the iterable expression - JavaNode init = node.getChild(1); - ASTVariableDeclaratorId foreachVar = ((ASTLocalVariableDeclaration) node.getChild(0)).iterator().next(); - return handleLoop(node, data, init, null, null, body, true, foreachVar); + ASTExpression init = node.getIterableExpr(); + return handleLoop(node, data, init, null, null, body, true, node.getVarId()); } @Override public SpanInfo visit(ASTForStatement node, SpanInfo data) { ASTStatement body = node.getBody(); - ASTForInit init = node.getFirstChildOfType(ASTForInit.class); + ASTForInit init = node.firstChild(ASTForInit.class); ASTExpression cond = node.getCondition(); - ASTForUpdate update = node.getFirstChildOfType(ASTForUpdate.class); + ASTForUpdate update = node.firstChild(ASTForUpdate.class); return handleLoop(node, data, init, cond, update, body, true, null); } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/InvalidTypeSignatureException.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/InvalidTypeSignatureException.java new file mode 100644 index 0000000000..7201d103b6 --- /dev/null +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/InvalidTypeSignatureException.java @@ -0,0 +1,12 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.symbols.internal.asm; + +class InvalidTypeSignatureException extends IllegalArgumentException { + + InvalidTypeSignatureException(String s) { + super(s); + } +} diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/SignatureParser.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/SignatureParser.java index d012cc303d..927236f715 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/SignatureParser.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/SignatureParser.java @@ -62,10 +62,8 @@ class SignatureParser { public void parseMethodType(LazyMethodType type, String genericSig) { TypeScanner b = typeParamsWrapper(type, genericSig); - parseFully(b, TypeSigParser::methodType); - type.setExceptionTypes(b.popList()); - type.setReturnType(b.pop()); - type.setParameterTypes(b.popList()); + int eof = TypeSigParser.methodType(type, b.start, b); + b.expectEoI(eof); } /** diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/SignatureScanner.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/SignatureScanner.java index 752e6b08d9..f0e6a72c6c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/SignatureScanner.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/SignatureScanner.java @@ -15,7 +15,7 @@ class SignatureScanner { protected final String chars; protected final int start; - protected final int end; + protected final int end; // exclusive SignatureScanner(String descriptor) { @@ -38,7 +38,7 @@ class SignatureScanner { public char charAt(int off) { - return off == end ? 0 : chars.charAt(off); + return off < end ? chars.charAt(off) : 0; } public void dumpChars(int start, int end, StringBuilder builder) { @@ -82,7 +82,7 @@ class SignatureScanner { String sb = "Expected " + expectedWhat + ":\n" + indent + bufferToString() + "\n" + indent + StringUtils.repeat(' ', pos - start) + '^' + "\n"; - return new IllegalArgumentException(sb); + return new InvalidTypeSignatureException(sb); } public void expectEoI(int e) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/TypeSigParser.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/TypeSigParser.java index d19a977b11..288bd1074e 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/TypeSigParser.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/internal/asm/TypeSigParser.java @@ -6,15 +6,14 @@ package net.sourceforge.pmd.lang.java.symbols.internal.asm; import static java.util.Collections.emptyList; -import java.util.ArrayDeque; import java.util.ArrayList; -import java.util.Deque; import java.util.List; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import net.sourceforge.pmd.lang.java.symbols.JClassSymbol; +import net.sourceforge.pmd.lang.java.symbols.internal.asm.GenericSigBase.LazyMethodType; import net.sourceforge.pmd.lang.java.types.JClassType; import net.sourceforge.pmd.lang.java.types.JTypeMirror; import net.sourceforge.pmd.lang.java.types.LexicalScope; @@ -32,6 +31,7 @@ final class TypeSigParser { static int classHeader(final int start, TypeScanner b) { int cur = classType(start, b); // superclass + JTypeMirror superClass = b.pop(); if (b.charAt(cur) == 'L') { List superItfs = new ArrayList<>(1); @@ -43,13 +43,17 @@ final class TypeSigParser { } else { b.pushList(emptyList()); } + b.push(superClass); return cur; } - static int methodType(final int start, TypeScanner b) { + static int methodType(LazyMethodType type, final int start, TypeScanner b) { int cur = parameterTypes(start, b); + type.setParameterTypes(b.popList()); cur = typeSignature(cur, b, true); // return type + type.setReturnType(b.pop()); cur = throwsSignaturesOpt(cur, b); + type.setExceptionTypes(b.popList()); return cur; } @@ -263,6 +267,7 @@ final class TypeSigParser { case '/': case '<': case '>': + case 0: return false; default: return true; @@ -276,9 +281,9 @@ final class TypeSigParser { abstract static class TypeScanner extends SignatureScanner { - // those stacks usually are 0..1 - private final Deque typeStack = new ArrayDeque<>(0); - private final Deque> listStack = new ArrayDeque<>(0); + // 1-element "stacks", push must be followed by pop + private @Nullable JTypeMirror type; + private @Nullable List list; private final TypeSystem ts; private final LexicalScope lexicalScope; @@ -296,19 +301,29 @@ final class TypeSigParser { } void pushList(List l) { - listStack.push(l); + assert this.list == null; + assert l != null; + this.list = l; } void push(JTypeMirror mirror) { - typeStack.push(mirror); + assert this.type == null; + assert mirror != null; + this.type = mirror; } JTypeMirror pop() { - return typeStack.pop(); + assert this.type != null; + JTypeMirror t = this.type; + this.type = null; + return t; } List popList() { - return listStack.pop(); + assert this.list != null; + List l = this.list; + this.list = null; + return l; } /** diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 08bf3bdad7..6eff22774f 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -1392,7 +1392,7 @@ public class ShortMethod { class="net.sourceforge.pmd.lang.rule.XPathRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#shortvariable"> -Fields, local variables, or parameter names that are very short are not helpful to the reader. +Fields, local variables, enum constant names or parameter names that are very short are not helpful to the reader. 3 diff --git a/pmd-java/src/main/resources/category/java/errorprone.xml b/pmd-java/src/main/resources/category/java/errorprone.xml index ac2a1558e0..73b9dfc494 100644 --- a/pmd-java/src/main/resources/category/java/errorprone.xml +++ b/pmd-java/src/main/resources/category/java/errorprone.xml @@ -566,6 +566,7 @@ public void checkRequests() { // with rule property "ignoreExpressions" set to "false" if (i == pos + 5) {} // violation: magic number 5 within an (additive) expression if (i == pos + SUFFIX_LENGTH) {} // preferred approach + if (i == 5 && "none".equals(aString)) {} // 2 violations: magic number 5 and literal "none" } ]]> diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/coverage/PMDCoverageTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/coverage/PMDCoverageTest.java index f573e94f61..39e09f0ea0 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/coverage/PMDCoverageTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/coverage/PMDCoverageTest.java @@ -4,54 +4,46 @@ package net.sourceforge.pmd.coverage; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.emptyString; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import static org.junit.jupiter.api.Assertions.fail; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Arrays; -import java.util.List; +import java.nio.file.Paths; +import java.util.function.Consumer; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringUtils; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; -import net.sourceforge.pmd.PMD; +import net.sourceforge.pmd.PMDConfiguration; +import net.sourceforge.pmd.PmdAnalysis; import net.sourceforge.pmd.internal.util.IOUtil; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.java.JavaLanguageModule; import com.github.stefanbirkner.systemlambda.SystemLambda; -// TODO enable test -@Disabled("Test is failing and was excluded on PMD 7 branch") class PMDCoverageTest { @TempDir private Path tempFolder; - @Test - void testPmdOptions() { - runPmd("-d src/main/java/net/sourceforge/pmd/lang/java/rule/design -f text -R rulesets/internal/all-java.xml -stress -benchmark"); - } - - @Test void runAllJavaPmdOnSourceTree() { - runPmd("-d src/main/java -f text -R rulesets/internal/all-java.xml"); + runPmd("src/main/java", conf -> {}); } @Test void runAllJavaPmdOnTestResourcesWithLatestJavaVersion() { - List versions = JavaLanguageModule.getInstance().getVersions(); - LanguageVersion latest = versions.get(versions.size() - 1); + LanguageVersion latest = JavaLanguageModule.getInstance().getLatestVersion(); - runPmd("-d src/test/resources -f text -R rulesets/internal/all-java.xml -language java -version " + latest.getVersion()); + runPmd("src/test/resources", conf -> conf.setDefaultLanguageVersion(latest)); } /** @@ -59,38 +51,37 @@ class PMDCoverageTest { * * @param commandLine */ - private void runPmd(String commandLine) { + private void runPmd(String inputPath, Consumer configure) { StringBuilder report = new StringBuilder("missing report"); try { Path f = Files.createTempFile(tempFolder, PMDCoverageTest.class.getSimpleName(), null); - String[] args = ArrayUtils.addAll( - commandLine.split("\\s"), - "-reportfile", - f.toAbsolutePath().toString(), - "-threads", - String.valueOf(Runtime.getRuntime().availableProcessors()) - ); - System.err.println("Running PMD with: " + Arrays.toString(args)); String output = SystemLambda.tapSystemOut(() -> { String errorOutput = SystemLambda.tapSystemErr(() -> { - PMD.runPmd(args); + PMDConfiguration conf = new PMDConfiguration(); + conf.addInputPath(Paths.get(inputPath)); + conf.setReportFile(f); + conf.addRuleSet("rulesets/internal/all-java.xml"); + conf.setThreads(Runtime.getRuntime().availableProcessors()); + configure.accept(conf); + + try (PmdAnalysis pmd = PmdAnalysis.create(conf)) { + pmd.performAnalysis(); + } report.setLength(0); report.append(IOUtil.readFileToString(f.toFile(), StandardCharsets.UTF_8)); }); - assertEquals(0, StringUtils.countMatches(errorOutput, "Exception applying rule"), "No exceptions expected"); - assertFalse(errorOutput.contains("Ruleset not found"), "Wrong configuration? Ruleset not found"); - assertEquals(0, StringUtils.countMatches(errorOutput, "Use of deprecated attribute"), "No usage of deprecated XPath attributes expected"); + assertThat(errorOutput, not(containsString("Exception applying rule"))); + assertThat(errorOutput, not(containsString("Ruleset not found"))); + assertThat(errorOutput, not(containsString("Use of deprecated attribute"))); }); - assertEquals(0, output.length(), "Nothing should be output to stdout"); - - assertEquals(0, StringUtils.countMatches(report, "Error while processing"), "No processing errors expected"); - + assertThat(output, is(emptyString())); + assertThat(output, not(containsString("Error while processing"))); // we might have explicit examples of parsing errors, so these are maybe false positives - assertEquals(0, StringUtils.countMatches(report, "Error while parsing"), "No parsing error expected"); + assertThat(output, not(containsString("Error while parsing"))); } catch (IOException ioe) { fail("Problem creating temporary file: " + ioe.getLocalizedMessage()); } catch (AssertionError ae) { diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPassTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPassTest.java new file mode 100644 index 0000000000..131e1de98e --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/internal/DataflowPassTest.java @@ -0,0 +1,35 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.internal; + +import static org.hamcrest.MatcherAssert.assertThat; + +import org.hamcrest.Matchers; +import org.junit.jupiter.api.Test; + +import net.sourceforge.pmd.lang.java.BaseParserTest; +import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.rule.internal.DataflowPass.DataflowResult; + +/** + * @author Clément Fournier + */ +class DataflowPassTest extends BaseParserTest { + + + @Test + void testSimple() { + + ASTCompilationUnit ast = java.parseResource( + "/net/sourceforge/pmd/lang/java/ast/jdkversiontests/java20p/RecordPatternsInEnhancedFor.java", + "20-preview" + ); + + DataflowResult dataflow = DataflowPass.getDataflowResult(ast); + assertThat(dataflow.getUnusedAssignments(), Matchers.hasSize(2)); + + } + +} diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/symbols/internal/asm/SigParserTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/symbols/internal/asm/SigParserTest.kt index 2e115f60e9..4d16fdc868 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/symbols/internal/asm/SigParserTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/symbols/internal/asm/SigParserTest.kt @@ -4,10 +4,19 @@ package net.sourceforge.pmd.lang.java.symbols.internal.asm +import io.kotest.assertions.throwables.shouldThrow import io.kotest.assertions.withClue import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.Matcher +import io.kotest.matchers.collections.shouldHaveSize +import io.kotest.matchers.should import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import javasymbols.testdata.impls.SomeInnerClasses +import net.sourceforge.pmd.lang.ast.test.IntelliMarker +import net.sourceforge.pmd.lang.ast.test.shouldBe import net.sourceforge.pmd.lang.java.symbols.JTypeParameterSymbol +import net.sourceforge.pmd.lang.java.symbols.internal.asm.GenericSigBase.LazyMethodType import net.sourceforge.pmd.lang.java.symbols.internal.asm.TypeParamsParser.BaseTypeParamsBuilder import net.sourceforge.pmd.lang.java.types.* import org.mockito.Mockito.`when` @@ -27,25 +36,56 @@ fun TypeSystem.mockTypeVar(name: String): JTypeVar { return t } -fun TypeSystem.mockLexicalScope(vararg names: String): LexicalScope = +fun mockLexicalScope(vararg names: String): LexicalScope = + with(testTypeSystem) { LexicalScope.EMPTY.andThen(names.map { mockTypeVar(name = it) }) + } operator fun LexicalScope.get(name: String): SubstVar = apply(name)!! -fun TypeSystem.shouldParseType(scope: LexicalScope, sig: String, t: TypeDslOf.() -> JTypeMirror) { - val parsed = asmLoader.sigParser.parseFieldType(scope, sig) +fun LexicalScope.shouldParseType(sig: String, test: TypeDslOf.() -> JTypeMirror) { + val ts = testTypeSystem + val parsed = ts.asmLoader.sigParser.parseFieldType(this, sig) - parsed shouldBe TypeDslOf(this).t() + parsed shouldBe TypeDslOf(ts).test() +} +private fun LexicalScope.shouldThrowWhenParsingType(sig: String, matcher: (InvalidTypeSignatureException)->Unit={}) { + val ex = shouldThrow { + val ts = testTypeSystem + ts.asmLoader.sigParser.parseFieldType(this, sig) + } + matcher(ex) } -class SigParserTest : FunSpec({ +private fun LexicalScope.shouldParseMethod( + descriptor: String, + genericSig: String? = descriptor, + exceptions: Array? = null, + skipFirstParam: Boolean = false, + test: TypeDslOf.(LazyMethodType) -> Unit +) { + val ts = testTypeSystem + val mockStub = mock(ExecutableStub::class.java) + `when`(mockStub.sigParser()).thenReturn(ts.asmLoader.sigParser) + `when`(mockStub.enclosingTypeParameterOwner).thenReturn(null) + `when`(mockStub.typeSystem).thenReturn(ts) + + val mt = LazyMethodType(mockStub, descriptor, genericSig, exceptions, skipFirstParam) + withClue("Parsing descriptor") { + mt.ensureParsed() + } + + TypeDslOf(ts).test(mt) +} + +class SigParserTest : IntelliMarker, FunSpec({ test("Test type sig parsing with type vars") { - with(testTypeSystem) { - val scope = mockLexicalScope("T", "V") + val scope = mockLexicalScope("T", "V") + with(scope) { - shouldParseType(scope, "Ljava/util/Map;>;") { + shouldParseType("Ljava/util/Map;>;") { java.util.Map::class[scope["T"], java.util.List::class[scope["V"]]] } } @@ -53,12 +93,112 @@ class SigParserTest : FunSpec({ test("Test wildcards") { - with(testTypeSystem) { - val scope = mockLexicalScope("T", "V") + val scope = mockLexicalScope("T", "V") + scope.shouldParseType("Ljava/util/Map;>;") { + java.util.Map::class[scope["T"], java.util.List::class[scope["V"]]] + } + scope.shouldParseType("Ljava/util/Map<-Ljava/lang/Number;+[Ljava/lang/Object;>;") { + java.util.Map::class[ + `?` `super` java.lang.Number::class, + `?` extends ts.OBJECT.toArray()] + } + } - shouldParseType(scope, "Ljava/util/Map;>;") { - java.util.Map::class[scope["T"], java.util.List::class[scope["V"]]] + test("Test method sig") { + + with(LexicalScope.EMPTY) { + + shouldParseMethod(descriptor = "(I)Z") { + it::getTypeParams shouldBe emptyList() + it::getExceptionTypes shouldBe emptyList() + it::getReturnType shouldBe boolean + it::getParameterTypes shouldBe listOf(int) } + + shouldParseMethod(descriptor = "()V") { + it::getTypeParams shouldBe emptyList() + it::getExceptionTypes shouldBe emptyList() + it::getReturnType shouldBe void + it::getParameterTypes shouldBe emptyList() + } + + } + } + + test("Test generic method") { + + with(LexicalScope.EMPTY) { + shouldParseMethod(descriptor = "([TT;)TT;") { + it.typeParams.shouldHaveSize(1) + val (t) = it.typeParams + t::getUpperBound shouldBe ts.OBJECT + it::getExceptionTypes shouldBe emptyList() + it::getReturnType shouldBe t + it::getParameterTypes shouldBe listOf(t.toArray()) + } + } + } + + test("Test multiple type bounds") { + + with(LexicalScope.EMPTY) { + shouldParseMethod(descriptor = "()V") { + it.typeParams.shouldHaveSize(1) + val (t) = it.typeParams + t::getUpperBound shouldBe ts.glb(java.lang.Number::class.raw, java.lang.CharSequence::class.raw) + } + } + } + + test("Test inner type") { + + with(LexicalScope.EMPTY) { + shouldParseType("Ljavasymbols/testdata/impls/SomeInnerClasses.Inner;") { + SomeInnerClasses::class[ts.STRING] + .selectInner(SomeInnerClasses.Inner::class.raw.symbol, listOf(ts.STRING)) + } + } + } + + test("Test throws clause") { + + with(LexicalScope.EMPTY) { + shouldParseMethod(descriptor = "()V^TT;^Ljava/lang/Error;") { + it.typeParams.shouldHaveSize(1) + val (t) = it.typeParams + it::getExceptionTypes shouldBe listOf( + t, java.lang.Error::class.raw + ) + t::getUpperBound shouldBe java.lang.Exception::class.raw + it::getReturnType shouldBe void + it::getParameterTypes shouldBe emptyList() + } + } + } + + test("Test primitives") { + + with(LexicalScope.EMPTY) { + shouldParseType("Z") { boolean } + shouldParseType("C") { char } + shouldParseType("F") { float } + shouldParseType("B") { byte } + shouldParseType("S") { short } + shouldParseType("I") { int } + shouldParseType("J") { long } + shouldParseType("D") { double } + } + } + + test("Test array types") { + + with(LexicalScope.EMPTY) { + + shouldParseType("[Z") { boolean.toArray() } + shouldParseType("[I") { int.toArray() } + shouldParseType("[[[I") { int.toArray(3) } + shouldParseType("[[Ljava/lang/Object;") { ts.OBJECT.toArray(2) } + shouldParseType("[[Ljava/util/List<*>;") { java.util.List::class[`?`].toArray(2) } } } @@ -97,6 +237,17 @@ class SigParserTest : FunSpec({ } } + + test("Test invalid sigs") { + + with(LexicalScope.EMPTY) { + shouldThrowWhenParsingType("Ljava/lang/Object") { + it.message!!.shouldContain("Expected semicolon") + } + } + } + + }) internal class MockTypeParamsScanner(sig: String) : BaseTypeParamsBuilder(sig) { diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TestUtilitiesForTypes.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TestUtilitiesForTypes.kt index ba844f2c2e..90482a9828 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TestUtilitiesForTypes.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TestUtilitiesForTypes.kt @@ -38,6 +38,7 @@ val testTypeSystem: TypeSystem get() = JavaParsingHelper.TEST_TYPE_SYSTEM val TypeSystem.asmLoader: AsmSymbolResolver get() = this.resolver as AsmSymbolResolver fun TypeSystem.lub(vararg us: JTypeMirror): JTypeMirror = lub(us.toList()) +fun TypeSystem.glb(vararg us: JTypeMirror): JTypeMirror = glb(us.toList()) val TypeSystem.STRING get() = declaration(getClassSymbol(String::class.java)) as JClassType diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningLoopVariables.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningLoopVariables.xml index 8180b410be..db04045647 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningLoopVariables.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningLoopVariables.xml @@ -675,10 +675,10 @@ public class Foo { - violation: various conditional reassignments of 'for' loop variable, skip allowed + #4500 violation: various conditional reassignments of 'for' loop variable, skip allowed skip - 4 - 13,14,15,16 + 10 + 13,14,15,16,17,18,19,20,21,22 - a compound assignment operator does not a usage make - 1 + a compound assignment operator does not a usage make #4517 + 3 + 3,9,12 + + Avoid unused local variables such as 'x'. + Avoid unused local variables such as 'c'. + Avoid unused local variables such as 'c'. + @@ -440,12 +469,12 @@ public class UsedLocalVar { - Actually unused try-with-resources #3656 + Actually unused try-with-resources #3656 and #4516 1 5 + + + [java] UnusedLocalVariable: false-positive with multiple for-loop indices #4518 + 4 + 3,3,6,15 + + Avoid unused local variables such as 'a'. + Avoid unused local variables such as 'b'. + Avoid unused local variables such as 'b'. + Avoid unused local variables such as 'j'. + + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/LocalVariableCouldBeFinal.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/LocalVariableCouldBeFinal.xml index aa5e26767a..69686f20af 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/LocalVariableCouldBeFinal.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/LocalVariableCouldBeFinal.xml @@ -7,11 +7,12 @@ May be final 1 + 3 @@ -30,7 +31,7 @@ public class Foo { - Unused, no violation + #4511 Unused, no violation 0 - - Blank local var + Initialized local vars 2 + 3,4 + + + + + #3122 Blank uninitialized local var + 3 + 3,4,5 - TEST1 + One non-final parameter 1 - TEST2 + Two non-final parameters 2 - TEST3 + Two non-final parameters with assignments to local vars 2 - TEST4 + Two parameters, one final, one non-final (1) 1 - TEST5 + Two parameters, one final, one non-final (2) 1 - TEST6 + Already two final parameters 0 + + + #4512 [java] MethodArgumentCouldBeFinal shouldn't report unused parameters + 0 + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentRequired.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentRequired.xml index 9e28b92f13..b8328ba236 100755 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentRequired.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentRequired.xml @@ -532,4 +532,33 @@ public class CommentRequirement {} public class CommentRequirement {} ]]> + + + Method overridden without @Override (#3123) + Required + 1 + 4 + + + + + Methods inside annotations (#3123) + 2 + 3,4 + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentSize.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentSize.xml index 632ecb1bf1..057b91d81e 100755 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentSize.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/documentation/xml/CommentSize.xml @@ -29,7 +29,7 @@ public class Foo { ]]> - Line too long + #4369 Line too long 5 1 5 @@ -37,7 +37,7 @@ public class Foo { // -/* 4 +/* 12345 * 5 way too long */ public class Foo { diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/AvoidLiteralsInIfCondition.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/AvoidLiteralsInIfCondition.xml index a03efce856..418dccf581 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/AvoidLiteralsInIfCondition.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/AvoidLiteralsInIfCondition.xml @@ -144,4 +144,36 @@ public class AvoidLiteralsInIfConditionWithExpressions { } ]]> + + + + + [java] AvoidLiteralsInIfCondition false positive and negative for String literals when ignoreExpressions=true #4514 + true + -1,0 + 2 + 4,5 + + + + + [java] AvoidLiteralsInIfCondition false positive and negative for String literals when ignoreExpressions=false #4514 + false + -1,0 + 5 + 4,5,8,9,9 + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ImplicitSwitchFallThrough.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ImplicitSwitchFallThrough.xml index 16afc0e794..ce77c57423 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ImplicitSwitchFallThrough.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ImplicitSwitchFallThrough.xml @@ -7,6 +7,7 @@ one case, which is not empty 1 + 6 + + + [java] UselessOperationOnImmutable various false negatives with String #4513 + 3 + 3,6,9 + + diff --git a/pmd-javascript/pom.xml b/pmd-javascript/pom.xml index e5cdefc231..1fb4bb9ea9 100644 --- a/pmd-javascript/pom.xml +++ b/pmd-javascript/pom.xml @@ -47,7 +47,7 @@ - + diff --git a/pmd-languages-deps/pom.xml b/pmd-languages-deps/pom.xml index 296b354747..9c2aa09980 100644 --- a/pmd-languages-deps/pom.xml +++ b/pmd-languages-deps/pom.xml @@ -1,7 +1,5 @@ - + 4.0.0 net.sourceforge.pmd diff --git a/pmd-matlab/pom.xml b/pmd-matlab/pom.xml index de32016435..cadb6012cd 100644 --- a/pmd-matlab/pom.xml +++ b/pmd-matlab/pom.xml @@ -34,7 +34,7 @@ - + diff --git a/pmd-objectivec/pom.xml b/pmd-objectivec/pom.xml index 559ca8320f..c2a592ae8d 100644 --- a/pmd-objectivec/pom.xml +++ b/pmd-objectivec/pom.xml @@ -34,7 +34,7 @@ - + diff --git a/pmd-python/pom.xml b/pmd-python/pom.xml index 9d8068a8fe..86be90a79d 100644 --- a/pmd-python/pom.xml +++ b/pmd-python/pom.xml @@ -34,7 +34,7 @@ - + diff --git a/pom.xml b/pom.xml index 5e4d08f020..db7af7b9ca 100644 --- a/pom.xml +++ b/pom.xml @@ -81,7 +81,7 @@ - 2023-03-25T11:47:31Z + 2023-04-29T21:39:33Z 8 @@ -670,11 +670,6 @@ ant ${ant.version} - - com.beust - jcommander - 1.48 - info.picocli picocli