diff --git a/.ci/build.sh b/.ci/build.sh
index 9268888029..7bd31fb01c 100755
--- a/.ci/build.sh
+++ b/.ci/build.sh
@@ -87,15 +87,15 @@ function build() {
if pmd_ci_maven_isSnapshotBuild; then
if [ "${PMD_CI_MAVEN_PROJECT_VERSION}" != "7.0.0-SNAPSHOT" ]; then
pmd_ci_log_group_start "Executing PMD dogfood test with ${PMD_CI_MAVEN_PROJECT_VERSION}"
- ./mvnw versions:set -DnewVersion=${PMD_CI_MAVEN_PROJECT_VERSION}-dogfood -DgenerateBackupPoms=false
+ ./mvnw versions:set -DnewVersion="${PMD_CI_MAVEN_PROJECT_VERSION}-dogfood" -DgenerateBackupPoms=false
+ sed -i 's/[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}.*<\/version>\( *\)/'"${PMD_CI_MAVEN_PROJECT_VERSION}"'<\/version>\1/' pom.xml
./mvnw verify --show-version --errors --batch-mode --no-transfer-progress "${PMD_MAVEN_EXTRA_OPTS[@]}" \
-DskipTests \
-Dmaven.javadoc.skip=true \
-Dmaven.source.skip=true \
- -Dcheckstyle.skip=true \
- -Ppmd-dogfood \
- -Dpmd.dogfood.version=${PMD_CI_MAVEN_PROJECT_VERSION}
- ./mvnw versions:set -DnewVersion=${PMD_CI_MAVEN_PROJECT_VERSION} -DgenerateBackupPoms=false
+ -Dcheckstyle.skip=true
+ ./mvnw versions:set -DnewVersion="${PMD_CI_MAVEN_PROJECT_VERSION}" -DgenerateBackupPoms=false
+ git checkout -- pom.xml
pmd_ci_log_group_end
else
# current maven-pmd-plugin is not compatible with PMD 7 yet.
diff --git a/.ci/files/all-java.xml b/.ci/files/all-java.xml
index bd0946ee66..e3b25d645e 100644
--- a/.ci/files/all-java.xml
+++ b/.ci/files/all-java.xml
@@ -54,10 +54,6 @@
-
-
-
-
@@ -77,7 +73,6 @@
-
@@ -130,7 +125,7 @@
-
+
@@ -153,17 +148,16 @@
-
-
+
-
+
-
+
-
+
@@ -210,7 +204,6 @@
-
@@ -228,31 +221,31 @@
-
-
-
-
+
+
+
+
-
+
-
+
-
+
-
+
@@ -268,7 +261,7 @@
-
+
@@ -294,25 +287,17 @@
-
-
-
-
-
-
-
-
diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties
index ffdc10e59f..abd303b673 100644
--- a/.mvn/wrapper/maven-wrapper.properties
+++ b/.mvn/wrapper/maven-wrapper.properties
@@ -1,2 +1,2 @@
-distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.1/apache-maven-3.8.1-bin.zip
+distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
diff --git a/docs/_config.yml b/docs/_config.yml
index 8faa80876b..ca829f79b7 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -2,7 +2,7 @@ repository: pmd/pmd
pmd:
version: 7.0.0-SNAPSHOT
- previous_version: 6.37.0
+ previous_version: 6.38.0
date: ??-?????-2021
release_type: major
diff --git a/docs/_data/sidebars/pmd_sidebar.yml b/docs/_data/sidebars/pmd_sidebar.yml
index c743d80699..c4d8aad28c 100644
--- a/docs/_data/sidebars/pmd_sidebar.yml
+++ b/docs/_data/sidebars/pmd_sidebar.yml
@@ -397,8 +397,14 @@ entries:
- title: Major contributions
output: web, pdf
subfolderitems:
- - title: Adding a new language
- url: /pmd_devdocs_major_adding_new_language.html
+ - title: Rule Guidelines
+ url: /pmd_devdocs_major_rule_guidelines.html
+ output: web, pdf
+ - title: Adding a new language (JavaCC)
+ url: /pmd_devdocs_major_adding_new_language_javacc.html
+ output: web, pdf
+ - title: Adding a new language (Antlr)
+ url: /pmd_devdocs_major_adding_new_language_antlr.html
output: web, pdf
- title: Adding a new CPD language
url: /pmd_devdocs_major_adding_new_cpd_language.html
diff --git a/docs/_data/xpath_funs.yml b/docs/_data/xpath_funs.yml
index b2a7beb5f5..830217ae71 100644
--- a/docs/_data/xpath_funs.yml
+++ b/docs/_data/xpath_funs.yml
@@ -10,6 +10,22 @@ aliases:
- &needs_typenode "The context node must be a {% jdoc jast::TypeNode %}"
langs:
+ - name: "Any language"
+ ns: "pmd"
+ funs:
+ - name: fileName
+ returnType: "xs:string"
+ shortDescription: "Returns the current filename"
+ description: "Returns the current simple filename without path but including the extension.
+ This can be used to write rules that check filename naming conventions.
+
+ This function is available since PMD 6.38.0.
"
+ notes: "The function can be called on any node."
+ examples:
+ - code: "//b[pmd:fileName() = 'Foo.xml']"
+ outcome: "Matches any `<b>` tags in files called `Foo.xml`."
+
+
- name: "Java"
ns: "pmd-java"
funs:
diff --git a/docs/pages/7_0_0_release_notes.md b/docs/pages/7_0_0_release_notes.md
index 2b4c261c86..d01bca241a 100644
--- a/docs/pages/7_0_0_release_notes.md
+++ b/docs/pages/7_0_0_release_notes.md
@@ -100,34 +100,53 @@ conversions that may be made implicit.
* {% 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.
#### Deprecated Rules
-* {% rule "java/performance/UnnecessaryWrapperObjectCreation" %} has been deprecated.
- It is replaced by the more general rule {% rule java/codestyle/UnnecessaryBoxing %}.
#### Removed Rules
The following previously deprecated rules have been finally removed:
-* AbstractNaming (java-codestyle)
-* AvoidFinalLocalVariable (java-codestyle)
-* AvoidPrefixingMethodParameters (java-codestyle)
-* DataflowAnomalyAnalysis (java-errorprone)
-* ForLoopsMustUseBraces (java-codestyle)
-* IfElseStmtsMustUseBraces (java-codestyle)
-* IfStmtsMustUseBraces (java-codestyle)
+* AbstractNaming (java-codestyle) -> use {% rule "java/codestyle/ClassNamingConventions" %}
+* AvoidFinalLocalVariable (java-codestyle) -> not replaced
+* AvoidPrefixingMethodParameters (java-codestyle) -> use {% rule "java/codestyle/FormalParameterNamingConventions" %}
+* AvoidUsingShortType (java-performance) -> not replaced
+* BadComparison (java-errorprone) -> use {% rule "java/errorprone/ComparisonWithNaN" %}
+* BooleanInstantiation (java-performance) -> use {% rule "java/codestyle/UnnecessaryBoxing" %} and {% rule "java/bestpractices/PrimitiveWrapperInstantiation" %}
+* ByteInstantiation (java-performance) -> use {% rule "java/codestyle/UnnecessaryBoxing" %} and {% rule "java/bestpractices/PrimitiveWrapperInstantiation" %}
+* CloneThrowsCloneNotSupportedException (java-errorprone) -> not replaced
+* DataflowAnomalyAnalysis (java-errorprone) -> not replaced
+* DefaultPackage (java-codestyle) -> use {% rule "java/codestyle/CommentDefaultAccessModifier" %}
+* DoNotCallSystemExit (java-errorprone) -> use {% rule "java/errorprone/DoNotTerminateVM" %}
+* ForLoopsMustUseBraces (java-codestyle) -> use {% rule "java/codestyle/ControlStatementBraces" %}
+* IfElseStmtsMustUseBraces (java-codestyle) -> use {% rule "java/codestyle/ControlStatementBraces" %}
+* IfStmtsMustUseBraces (java-codestyle) -> use {% rule "java/codestyle/ControlStatementBraces" %}
+* IntegerInstantiation (java-performance) -> use {% rule "java/codestyle/UnnecessaryBoxing" %} and {% rule "java/bestpractices/PrimitiveWrapperInstantiation" %}
+* InvalidSlf4jMessageFormat (java-errorprone) -> use {% rule "java/errorprone/InvalidLogMessageFormat" %}
* LoggerIsNotStaticFinal (java-errorprone)
-* MIsLeadingVariableName (java-codestyle)
-* ModifiedCyclomaticComplexity (java-design)
-* PositionLiteralsFirstInCaseInsensitiveComparisons (java-bestpractices)
-* PositionLiteralsFirstInComparisons (java-bestpractices)
-* StdCyclomaticComplexity (java-design)
+* LongInstantiation (java-performance) -> use {% rule "java/codestyle/UnnecessaryBoxing" %} and {% rule "java/bestpractices/PrimitiveWrapperInstantiation" %}
+* MIsLeadingVariableName (java-codestyle) -> use {% rule "java/codestyle/FieldNamingConventions" %}
+* MissingBreakInSwitch (java-errorprone) -> use {% rule "java/errorprone/ImplicitSwitchFallThrough" %}
+* ModifiedCyclomaticComplexity (java-design) -> use {% rule "java/design/CyclomaticComplexity" %}
+* PositionLiteralsFirstInCaseInsensitiveComparisons (java-bestpractices) -> use {% rule "java/bestpractices/LiteralsFirstInComparisons" %}
+* PositionLiteralsFirstInComparisons (java-bestpractices) -> use {% rule "java/bestpractices/LiteralsFirstInComparisons" %}
+* ReturnEmptyArrayRatherThanNull (java-errorprone) -> use {% rule "java/errorprone/ReturnEmptyCollectionRatherThanNull" %}
+* ShortInstantiation (java-performance) -> use {% rule "java/codestyle/UnnecessaryBoxing" %} and {% rule "java/bestpractices/PrimitiveWrapperInstantiation" %}
+* SimplifyBooleanAssertion (java-design) -> use {% rule "java/bestpractices/SimplifiableTestAssertion" %}
+* SimplifyStartsWith (java-performance) -> not replaced
+* StdCyclomaticComplexity (java-design) -> use {% rule "java/design/CyclomaticComplexity" %}
* SuspiciousConstantFieldName (java-codestyle)
+* UnnecessaryWrapperObjectCreation (java-performance) -> use the new rule {% rule "java/codestyle/UnnecessaryBoxing" %}
* UnsynchronizedStaticDateFormatter (java-multithreading)
+* UseAssertEqualsInsteadOfAssertTrue (java-bestpractices) -> use {% rule "java/bestpractices/SimplifiableTestAssertion" %}
+* UseAssertNullInsteadOfAssertEquals (java-bestpractices) -> use {% rule "java/bestpractices/SimplifiableTestAssertion" %}
+* UseAssertSameInsteadOfAssertEquals (java-bestpractices) -> use {% rule "java/bestpractices/SimplifiableTestAssertion" %}
+* UseAssertTrueInsteadOfAssertEquals (java-bestpractices) -> use {% rule "java/bestpractices/SimplifiableTestAssertion" %}
* VariableNamingConventions (apex-codestyle)
-* VariableNamingConventions (java-codestyle)
-* WhileLoopsMustUseBraces (java-codestyle)
+* VariableNamingConventions (java-codestyle) -> use {% rule "java/codestyle/FieldNamingConventions" %} and such
+* WhileLoopsMustUseBraces (java-codestyle) -> use {% rule "java/codestyle/ControlStatementBraces" %}
### Fixed Issues
@@ -178,6 +197,8 @@ The following previously deprecated rules have been finally removed:
* [#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
+* java-design
+ * [#2536](https://github.com/pmd/pmd/issues/2536): \[java] ClassWithOnlyPrivateConstructorsShouldBeFinal can't detect inner class
* 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
@@ -238,7 +259,8 @@ The metrics framework has been made simpler and more general.
* [#1658](https://github.com/pmd/pmd/pull/1658): \[core] Node support for Antlr-based languages - [Matías Fraga](https://github.com/matifraga)
* [#1698](https://github.com/pmd/pmd/pull/1698): \[core] [swift] Antlr Base Parser adapter and Swift Implementation - [Lucas Soncini](https://github.com/lsoncini)
* [#1774](https://github.com/pmd/pmd/pull/1774): \[core] Antlr visitor rules - [Lucas Soncini](https://github.com/lsoncini)
-* [#1877](https://github.com/pmd/pmd/pull/1877): \[swift] Feature/swift rules - [Matias Fraga](https://github.com/matifraga)
+* [#1877](https://github.com/pmd/pmd/pull/1877): \[swift] Feature/swift rules - [Matías Fraga](https://github.com/matifraga)
+* [#1881](https://github.com/pmd/pmd/pull/1881): \[doc] Add ANTLR documentation - [Matías Fraga](https://github.com/matifraga)
* [#1882](https://github.com/pmd/pmd/pull/1882): \[swift] UnavailableFunction Swift rule - [Tomás de Lucca](https://github.com/tomidelucca)
* [#2830](https://github.com/pmd/pmd/pull/2830): \[apex] Apexlink POC - [Kevin Jones](https://github.com/nawforce)
diff --git a/docs/pages/next_major_development.md b/docs/pages/next_major_development.md
index a6dc241374..97d9c9329d 100644
--- a/docs/pages/next_major_development.md
+++ b/docs/pages/next_major_development.md
@@ -246,6 +246,10 @@ the breaking API changes will be performed in 7.0.0.
an API is tagged as `@Deprecated` or not in the latest minor release. During the development of 7.0.0,
we may decide to remove some APIs that were not tagged as deprecated, though we'll try to avoid it." %}
+#### 6.38.0
+
+No changes.
+
#### 6.37.0
##### PMD CLI
@@ -1352,35 +1356,35 @@ large projects, with many duplications, it was causing `OutOfMemoryError`s (see
is deprecated in favour of {% rule "java/bestpractices/UnusedAssignment" %} (`java-bestpractices`),
which was introduced in PMD 6.26.0.
-* The java rule {% rule "java/codestyle/DefaultPackage" %} has been deprecated in favor of
+* The java rule `DefaultPackage` (java-codestyle) has been deprecated in favor of
{% rule "java/codestyle/CommentDefaultAccessModifier" %}.
-* The Java rule {% rule "java/errorprone/CloneThrowsCloneNotSupportedException" %} has been deprecated without
+* The Java rule `CloneThrowsCloneNotSupportedException` (java-errorprone) has been deprecated without
replacement.
* The following Java rules are deprecated and removed from the quickstart ruleset,
as the new rule {% rule java/bestpractices/SimplifiableTestAssertion %} merges
their functionality:
- * {% rule java/bestpractices/UseAssertEqualsInsteadOfAssertTrue %}
- * {% rule java/bestpractices/UseAssertNullInsteadOfAssertTrue %}
- * {% rule java/bestpractices/UseAssertSameInsteadOfAssertTrue %}
- * {% rule java/bestpractices/UseAssertTrueInsteadOfAssertEquals %}
- * {% rule java/design/SimplifyBooleanAssertion %}
+ * `UseAssertEqualsInsteadOfAssertTrue` (java-bestpractices)
+ * `UseAssertNullInsteadOfAssertTrue` (java-bestpractices)
+ * `UseAssertSameInsteadOfAssertTrue` (java-bestpractices)
+ * `UseAssertTrueInsteadOfAssertEquals` (java-bestpractices)
+ * `SimplifyBooleanAssertion` (java-design)
-* The Java rule {% rule java/errorprone/ReturnEmptyArrayRatherThanNull %} is deprecated and removed from
+* The Java rule `ReturnEmptyArrayRatherThanNull` (java-errorprone) is deprecated and removed from
the quickstart ruleset, as the new rule {% rule java/errorprone/ReturnEmptyCollectionRatherThanNull %}
supersedes it.
* The following Java rules are deprecated and removed from the quickstart ruleset,
as the new rule {% rule java/bestpractices/PrimitiveWrapperInstantiation %} merges
their functionality:
- * {% rule java/performance/BooleanInstantiation %}
- * {% rule java/performance/ByteInstantiation %}
- * {% rule java/performance/IntegerInstantiation %}
- * {% rule java/performance/LongInstantiation %}
- * {% rule java/performance/ShortInstantiation %}
+ * java/performance/BooleanInstantiation
+ * java/performance/ByteInstantiation
+ * java/performance/IntegerInstantiation
+ * java/performance/LongInstantiation
+ * java/performance/ShortInstantiation
-* The Java rule {% rule java/performance/UnnecessaryWrapperObjectCreation %} is deprecated
+* The Java rule java/performance/UnnecessaryWrapperObjectCreation is deprecated
with no planned replacement before PMD 7. In it's current state, the rule is not useful
as it finds only contrived cases of creating a primitive wrapper and unboxing it explicitly
in the same expression. In PMD 7 this and more cases will be covered by a
diff --git a/docs/pages/pmd/devdocs/major_contributions/adding_a_new_antlr_based_language.md b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_antlr_based_language.md
new file mode 100644
index 0000000000..7f156054d7
--- /dev/null
+++ b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_antlr_based_language.md
@@ -0,0 +1,156 @@
+---
+title: Adding PMD support for a new ANTLR grammar based language
+short_title: Adding a new language with ANTLR
+tags: [devdocs, extending]
+summary: "How to add a new language to PMD using ANTLR grammar."
+last_updated: July 21, 2019
+sidebar: pmd_sidebar
+permalink: pmd_devdocs_major_adding_new_language_antlr.html
+folder: pmd/devdocs
+
+# needs to be changed to branch master instead of pmd/7.0.x
+# https://github.com/pmd/pmd/blob/pmd/7.0.x -> https://github.com/pmd/pmd/blob/master
+---
+
+
+## 1. Start with a new sub-module.
+* See pmd-swift for examples.
+
+## 2. Implement an AST parser for your language
+* ANTLR will generate the parser for you based on the grammar file. The grammar file needs to be placed in the
+ folder `src/main/antlr4` in the appropriate sub package `ast` of the language. E.g. for swift, the grammar
+ file is [Swift.g4](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/antlr4/net/sourceforge/pmd/lang/swift/ast/Swift.g4)
+ and is placed in the package `net.sourceforge.pmd.lang.swift.ast`.
+
+## 3. Create AST node classes
+* The individual AST nodes are generated, but you need to define the common interface for them.
+* You need a need to define the supertype interface for all nodes of the language. For that, we provide
+ [`AntlrNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrNode.java).
+* See [`SwiftNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftNode.java)
+ as an example.
+* Additionally, you need several base classes:
+ * a language specific inner node - these nodes represent the production rules from the grammar.
+ In Antlr, they are called "ParserRuleContext". We call them "InnerNode". Use the
+ base class from pmd-core
+ [`BaseAntlrInnerNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/BaseAntlrInnerNode.java)
+ . And example is [`SwiftInnerNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftInnerNode.java).
+ * a language specific root node - this provides the root of the AST and our parser will return
+ subtypes of this node. The root node itself is a "InnerNode".
+ See [`SwiftRootNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftRootNode.java).
+ * a language specific terminal node.
+ See [`SwiftTerminalNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftTerminalNode.java).
+ * a language specific error node.
+ See [`SwiftErrorNode`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftErrorNode.java).
+* In order for the generated code to match and use our custom classes, we have a common ant script, that fiddles with
+ the generated code. The ant script is [`antlr4-wrapper.xml`](https://github.com/pmd/pmd/blob/pmd/7.0.x/antlr4-wrapper.xml) and
+ does not need to be adjusted - it has plenty of parameters to set. The ant script is added in the
+ language module's `pom.xml` where the parameters are set (e.g. name of root name class). Have a look at
+ Swift's example: [`pmd-swift/pom.xml`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/pom.xml).
+* You can add additional methods in your "InnerNode" (e.g. `SwiftInnerNode`) that are available on all nodes.
+ But on most cases you won't need to do anything.
+
+## 4. Generate your parser
+* Make sure, you have the property `true` in your `pom.xml` file.
+* This is just a matter of building the language module. ANTLR is called via ant, and this step is added
+ to the phase `generate-sources`. So you can just call e.g. `./mvnw generate-source -pl pmd-swift` to
+ have the parser generated.
+* The generated code will be placed under `target/generated-sources/antlr4` and will not be committed to
+ source control.
+* You should review the [swift pom](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/pom.xml).
+
+## 5. Create a TokenManager
+* This is needed to support CPD (copy paste detection)
+* We provide a default implementation using [`AntlrTokenManager`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/cpd/internal/AntlrTokenizer.java).
+* You must create your own "AntlrTokenizer" such as we do with
+ [`SwiftTokenizer`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java).
+* If you wish to filter specific tokens (e.g. comments to support CPD suppression via "CPD-OFF" and "CPD-ON")
+ you can create your own implementation of
+ [`AntlrTokenFilter`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/AntlrTokenFilter.java).
+ You'll need to override then the protected method `getTokenFilter(AntlrTokenManager)`
+ and return your custom filter. See the tokenizer for C# as an exmaple:
+ [`CsTokenizer`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java).
+
+ If you don't need a custom token filter, you don't need to override the method. It returns the default
+ `AntlrTokenFilter` which doesn't filter anything.
+
+## 6. Create a PMD parser “adapter”
+* Create your own parser, that adapts the ANLTR interface to PMD's parser interface.
+* We provide a [`AntlrBaseParser`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseParser.java)
+ implementation that you need to extend to create your own adapter as we do with
+ [`PmdSwiftParser`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/PmdSwiftParser.java).
+
+## 7. Create a rule violation factory
+* This is an optional step. Most like, the default implementation will do what you need.
+ The default implementation is [`DefaultRuleViolationFactory`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/impl/DefaultRuleViolationFactory.java).
+* The purpose of a rule violation factory is to create a rule violation instance for your handler (spoiler).
+ In case you want to provide additional data in your rule violation, you can create a custom one. However,
+ adding additional date here is discouraged, as you would need a custom renderer to actually use this
+ additional data. Such extensions are not language agnostic.
+
+## 8. Create a version handler
+* Now you need to create your version handler, as we did with [`SwiftHandler`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftHandler.java).
+* This class is sort of a gateway between PMD and all parsing logic specific to your language. It has 2 purposes:
+ * `getRuleViolationFactory` method returns an instance of your rule violation factory *(see step #7)*.
+ By default, this returns the default rule violation factory.
+ * `getParser` returns an instance of your parser adapter *(see step #6)*.
+ That's the only method, that needs to be implemented here.
+
+## 9. Create a parser visitor adapter
+* A parser visitor adapter is not needed anymore with PMD 7. The visitor interface now provides a default
+ implementation.
+* The visitor for ANTLR based AST is generated along the parser from the ANTLR grammar file. The
+ base interface for a visitor is [`AstVisitor`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/AstVisitor.java).
+* The generated visitor class for Swift is called `SwiftVisitor`.
+* In order to help use this visitor later on, a base visitor class should be created.
+ See [`SwiftVisitorBase`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/ast/SwiftVisitorBase.java)
+ as an example.
+
+## 10. Create a rule chain visitor
+* This step is not needed anymore. For using rule chain, there is no additional adjustment necessary anymore
+ in the languages.
+* This feature has been merged into AbstractRule via the overridable method
+ {% jdoc !!core::lang.rule.AbstractRule#buildTargetSelector() %}. Individual rules can make use of this optimization
+ by overriding this method and return an appropriate RuleTargetSelector.
+
+## 11. Make PMD recognize your language
+* Create your own subclass of `net.sourceforge.pmd.lang.BaseLanguageModule`, see Swift as an example:
+ [`SwiftLanguageModule`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java).
+* Add your default version with `addDefaultVersion` in your language module's constructor.
+* Add for each additional version of your language a call to `addVersion` as well.
+* Create the service registration via the text file `src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language`. Add your fully qualified class name as a single line into it.
+
+## 12. Create an abstract rule class for the language
+* You need to create your own `AbstractRule` in order to interface your language with PMD's generic rule
+ execution.
+* See [`AbstractSwiftRule`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java) as an example.
+* While the rule basically just extends
+ [`AntlrBaseRule`](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/impl/antlr4/AntlrBaseRule.java) without adding anything, every language should have its own base class for rule.
+ This helps to organize the code.
+* All other rules for your language should extend this class. The purpose of this class is to provide a visitor
+ via the method `buildVisitor()` for analyzing the AST. The provided visitor only implements the visit methods
+ for specific AST nodes. The other node types use the default behavior and you don't need to care about them.
+
+## 13. Create rules
+* Creating rules is already pretty well documented in PMD - and it’s no different for a new language, except you
+ may have different AST nodes.
+* PMD supports 2 types of rules, through visitors or XPath.
+* To add a visitor rule:
+ * You need to extend the abstract rule you created on the previous step, you can use the swift
+ rule [UnavailableFunctionRule](https://github.com/pmd/pmd/blob/pmd/7.0.x/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/bestpractices/UnavailableFunctionRule.java)
+ as an example. Note, that all rule classes should be suffixed with `Rule` and should be placed
+ in a package the corresponds to their category.
+* To add an XPath rule you can follow our guide [Writing XPath Rules](pmd_userdocs_extending_writing_xpath_rules.html).
+
+## 14. Test the rules
+* See UnavailableFunctionRuleTest for example. Each rule has it's own test class.
+* You have to create the category rule set for your language *(see pmd-swift/src/main/resources/bestpractices.xml for example)*
+* When executing the test class
+ * this triggers the unit test to read the corresponding XML file with the rule test data
+ *(see `UnavailableFunctionRule.xml` for example)*
+ * This test XML file contains sample pieces of code which should trigger a specified number of
+ violations of this rule. The unit test will execute the rule on this piece of code, and verify
+ that the number of violations matches.
+* To verify the validity of all the created rulesets, create a subclass of `AbstractRuleSetFactoryTest` (*see `RuleSetFactoryTest` in pmd-swift for example)*.
+ This will load all rulesets and verify, that all required attributes are provided.
+
+ *Note:* You'll need to add your ruleset to `categories.properties`, so that it can be found.
diff --git a/docs/pages/pmd/devdocs/major_contributions/adding_new_language.md b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_javacc_based_language.md
similarity index 96%
rename from docs/pages/pmd/devdocs/major_contributions/adding_new_language.md
rename to docs/pages/pmd/devdocs/major_contributions/adding_a_new_javacc_based_language.md
index 1ec23a6dd9..c3b470247c 100644
--- a/docs/pages/pmd/devdocs/major_contributions/adding_new_language.md
+++ b/docs/pages/pmd/devdocs/major_contributions/adding_a_new_javacc_based_language.md
@@ -1,11 +1,11 @@
---
-title: Adding PMD support for a new language
-short_title: Adding a new language
+title: Adding PMD support for a new JAVACC grammar based language
+short_title: Adding a new language with JAVACC
tags: [devdocs, extending]
-summary: "How to add a new language to PMD."
+summary: "How to add a new language to PMD using JAVACC grammar."
last_updated: October 5, 2019
sidebar: pmd_sidebar
-permalink: pmd_devdocs_major_adding_new_language.html
+permalink: pmd_devdocs_major_adding_new_language_javacc.html
folder: pmd/devdocs
---
@@ -47,10 +47,9 @@ folder: pmd/devdocs
## 8. Create a version handler
* Extend `AbstractLanguageVersionHandler` *(see VmHandler for example)*
-* This class is sort of a gateway between PMD and all parsing logic specific to your language. It has 3 purposes:
+* This class is sort of a gateway between PMD and all parsing logic specific to your language. It has 2 purposes:
* `getRuleViolationFactory` method returns an instance of your rule violation factory *(see step #7)*
* `getParser` returns an instance of your parser adapter *(see step #6)*
- * `getDumpFacade` returns a `VisitorStarter` that allows to dump a text representation of the AST into a writer *(likely for debugging purposes)*
## 9. Create a parser visitor adapter
* If you use JJT to generate your parser, it should also generate an interface for a parser visitor *(see VmParserVisitor for example)*
diff --git a/docs/pages/pmd/devdocs/major_contributions/rule_guidelines.md b/docs/pages/pmd/devdocs/major_contributions/rule_guidelines.md
new file mode 100644
index 0000000000..2b252ba996
--- /dev/null
+++ b/docs/pages/pmd/devdocs/major_contributions/rule_guidelines.md
@@ -0,0 +1,77 @@
+---
+title: Guidelines for standard rules
+short_title: Rule guidelines
+tags: [devdocs, extending]
+summary: "Guidelines for rules that are included in the standard distribution"
+last_updated: August, 2021
+sidebar: pmd_sidebar
+permalink: pmd_devdocs_major_rule_guidelines.html
+---
+
+{% include note.html content="
+These guidelines are new and most rules don't follow these guidelines yet.
+The goal is, that eventually all rules are updated.
+" %}
+
+## Why do we need these guidelines?
+
+* To prevent low quality contributions
+* To reduce time reviewing rules
+
+They just apply to rules included in the standard distribution.
+
+## Requirements for standard rules
+
+To be included in stock PMD, a rule needs
+
+* Broad applicability. It may be specific to a framework, but then, this framework should be widely used
+* Solid documentation. See below
+* If it's a performance rule: solid benchmarks. No micro-optimization rules
+* No overlap with other rules
+
+## Dos/Don'ts (rule rules)
+
+* Rule naming
+ * **Don't** put the implementation of the rule in the name, because it will be awkward
+ if the scope of the rule changes
+ * Eg. *SwitchStmtShouldHaveDefault* -> since enums are a thing they don't necessarily
+ need to have a default anymore, they should be exhaustive. So the rule name lies now...
+ * Eg. *MissingBreakInSwitch* -> it's obvious that this is supposed to find fall-through
+ switches. Counting breaks is not a clever way to do it, but since it's in the name
+ we can't change it without renaming the rule.
+ * **Do** use rule names that name the underlying problem that violations exhibit
+ * Eg. instead of *SwitchStmtShouldHaveDefault*, use *NonExhaustiveSwitchStatement* -> this
+ is the problem, the description of the rule will clarify why it is a problem and how
+ to fix it (add a default, or add branches, or something else in the future)
+ * Eg. instead of *MissingBreakInSwitch*, use *SwitchCaseFallsThrough*
+ * **Don't** create several rules for instances of the same problem
+ * *EmptyIfStmt* and *EmptyWhileStmt* are actually the same problem, namely,
+ that there's useless syntax in the tree.
+ * **Don't** limit the rule name to strictly what the rule can do today
+ * Eg. *UnusedPrivateField* is a bad name. The problem is that there is an unused field,
+ not that it is private as well. If we had the ability to find unused package-private
+ fields, we would report them too. So if one day we get that ability,
+ using a name like *UnusedField* would allow us to keep the name.
+* Rule messages
+ * **Do** write rule messages that neutrally point out a problem or construct that should
+ be reviewed ("Unnecessary parentheses")
+ * **Don't** write rule messages that give an order ("Avoid unnecessary parentheses")
+ especially without explaining why, like here
+ * **Don't** write rule messages that are tautological ("Unnecessary parentheses should be removed").
+ The answer to this would be an annoyed "yes I know, so what?".
+* **Do** use Markdown in rule descriptions and break lines at a reasonable 80 chars
+* **Do** thoroughly comment rule examples. It must be obvious where to look
+* **Do** comment your xpath expressions too
+
+## Rule description template
+
+* What the rule reports (1 summary line)
+* Why the rule exists and where it might be useful (including, since which language version, etc)
+* Blank line
+* Explain all assumptions that the rule makes and keywords used in the previous paragraph.
+ ("overridden methods are ignored", "for the purposes of this rule, a 'visible' field is
+ non-private").
+* Describe known limitations if any
+* Blank line
+* For each property, explain how it modifies the assumptions and why you would want to use it.
+ **If you can't explain why it's there then it shouldn’t be there!**
diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md
index d1a771e9ec..41b5a8a3d6 100644
--- a/docs/pages/pmd/projectdocs/credits.md
+++ b/docs/pages/pmd/projectdocs/credits.md
@@ -428,7 +428,7 @@ author: Tom Copeland
* Mat Booth - #1109 Patch to build with Javacc 5.0
* Stuart Turton - for PLSQL support. See also [pldoc](http://pldoc.sourceforge.net/)
* Andrey Utis - for adding Apache Velocity as a new language and writing up a
- [howto for adding new languages](pmd_devdocs_major_adding_new_language.html).
+ [howto for adding new languages JavaCC](pmd_devdocs_major_adding_new_language_javacc.html).
* Alan Hohn - for adding Standard and modified cyclomatic complexity rules
* Jan van Nunen - for adding CPD support for Matlab, Objective-C, Python, Scala and various bug fixes
* Juan Martín Sotuyo Dodero - for many bugfixes/pull requests improving Java grammar and performance
diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md
index f2b41c6432..1922dce49d 100644
--- a/docs/pages/release_notes.md
+++ b/docs/pages/release_notes.md
@@ -21,14 +21,14 @@ This is a {{ site.pmd.release_type }} release.
### Fixed Issues
-* java-bestpractices
- * [#3403](https://github.com/pmd/pmd/issues/3403): \[java] MethodNamingConventions junit5TestPattern does not detect parameterized tests
+* core
+ * [#3499](https://github.com/pmd/pmd/pull/3499): \[core] Fix XPath rulechain with combined node tests
+* java-errorprone
+ * [#3493](https://github.com/pmd/pmd/pull/3493): \[java] AvoidAccessibilityAlteration: add tests and fix rule
### API Changes
### External Contributions
-* [#3445](https://github.com/pmd/pmd/pull/3445): \[java] Fix #3403 about MethodNamingConventions and JUnit5 parameterized tests - [Cyril Sicard](https://github.com/CyrilSicard)
-
{% endtocmaker %}
diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md
index 8f725ea160..bb4f14fc50 100644
--- a/docs/pages/release_notes_old.md
+++ b/docs/pages/release_notes_old.md
@@ -5,6 +5,38 @@ permalink: pmd_release_notes_old.html
Previous versions of PMD can be downloaded here: https://github.com/pmd/pmd/releases
+## 28-August-2021 - 6.38.0
+
+The PMD team is pleased to announce PMD 6.38.0.
+
+This is a minor release.
+
+### Table Of Contents
+
+* [Fixed Issues](#fixed-issues)
+* [External Contributions](#external-contributions)
+* [Stats](#stats)
+
+### Fixed Issues
+
+* apex
+ * [#3462](https://github.com/pmd/pmd/issues/3462): \[apex] SOQL performed in a for-each loop doesn't trigger ApexCRUDViolationRule
+ * [#3484](https://github.com/pmd/pmd/issues/3484): \[apex] ApexCRUDViolationRule maintains state across files
+* core
+ * [#3446](https://github.com/pmd/pmd/issues/3446): \[core] Allow XPath rules to access the current file name
+* java-bestpractices
+ * [#3403](https://github.com/pmd/pmd/issues/3403): \[java] MethodNamingConventions junit5TestPattern does not detect parameterized tests
+
+### External Contributions
+
+* [#3445](https://github.com/pmd/pmd/pull/3445): \[java] Fix #3403 about MethodNamingConventions and JUnit5 parameterized tests - [Cyril Sicard](https://github.com/CyrilSicard)
+* [#3470](https://github.com/pmd/pmd/pull/3470): \[apex] Fix ApexCRUDViolationRule - add super call - [Josh Feingold](https://github.com/jfeingold35)
+
+### Stats
+* 32 commits
+* 8 closed tickets & PRs
+* Days since last release: 27
+
## 28-August-2021 - 6.38.0-SNAPSHOT
The PMD team is pleased to announce PMD 6.38.0-SNAPSHOT.
diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexCRUDViolationRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexCRUDViolationRule.java
index bee47a8bcd..a50b071fb5 100644
--- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexCRUDViolationRule.java
+++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexCRUDViolationRule.java
@@ -18,6 +18,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
+import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.apex.ast.ASTAssignmentExpression;
import net.sourceforge.pmd.lang.apex.ast.ASTBlockStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTDmlDeleteStatement;
@@ -85,12 +86,25 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
private static final Pattern WITH_SECURITY_ENFORCED = Pattern.compile("(?is).*[^']\\s*WITH\\s+SECURITY_ENFORCED\\s*[^']*");
- private final Map varToTypeMapping = new HashMap<>();
- private final ListMultimap typeToDMLOperationMapping = ArrayListMultimap.create();
- private final Map checkedTypeToDMLOperationViaESAPI = new HashMap<>();
- private final Map classMethods = new WeakHashMap<>();
+ private Map varToTypeMapping;
+ private ListMultimap typeToDMLOperationMapping;
+ private Map checkedTypeToDMLOperationViaESAPI;
+ private Map classMethods;
private String className;
+ @Override
+ public void start(RuleContext ctx) {
+ // At the start of each rule execution, these member variables need to be fresh. So they're initialized in the
+ // .start() method instead of the constructor, since .start() is called before every execution.
+ varToTypeMapping = new HashMap<>();
+ typeToDMLOperationMapping = ArrayListMultimap.create();
+ checkedTypeToDMLOperationViaESAPI = new HashMap<>();
+ classMethods = new WeakHashMap<>();
+ className = null;
+ super.start(ctx);
+ }
+
+
@Override
public Object visit(ASTUserClass node, Object data) {
if (Helper.isTestMethodOrClass(node) || Helper.isSystemLevelClass(node)) {
@@ -240,7 +254,7 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
checkForAccessibility(soql, data);
}
- return data;
+ return super.visit(node, data);
}
private void addVariableToMapping(final String variableName, final String type) {
@@ -533,7 +547,7 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
}
- private void validateCRUDCheckPresent(final ApexNode> node, final Object data, final String crudMethod,
+ private boolean validateCRUDCheckPresent(final ApexNode> node, final Object data, final String crudMethod,
final String typeCheck) {
boolean missingKey = !typeToDMLOperationMapping.containsKey(typeCheck);
boolean isImproperDMLCheck = !isProperESAPICheckForDML(typeCheck, crudMethod);
@@ -542,6 +556,7 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
//if condition returns true, add violation, otherwise return.
if (isImproperDMLCheck && noSecurityEnforced) {
addViolation(data, node);
+ return true;
}
} else {
boolean properChecksHappened = false;
@@ -560,8 +575,10 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
if (!properChecksHappened) {
addViolation(data, node);
+ return true;
}
}
+ return false;
}
private void checkForAccessibility(final ASTSoqlExpression node, Object data) {
@@ -585,7 +602,7 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
if (wrappingMethod != null) {
returnType = getReturnType(wrappingMethod);
}
-
+ boolean violationAdded = false;
final ASTVariableDeclaration variableDecl = node.getFirstParentOfType(ASTVariableDeclaration.class);
if (variableDecl != null) {
String type = variableDecl.getType();
@@ -594,15 +611,20 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
.append(":").append(type);
if (typesFromSOQL.isEmpty()) {
- validateCRUDCheckPresent(node, data, ANY, typeCheck.toString());
+ violationAdded = validateCRUDCheckPresent(node, data, ANY, typeCheck.toString());
} else {
for (String typeFromSOQL : typesFromSOQL) {
- validateCRUDCheckPresent(node, data, ANY, typeFromSOQL);
+ violationAdded |= validateCRUDCheckPresent(node, data, ANY, typeFromSOQL);
}
}
}
+ // If the node's already in violation, we don't need to keep checking.
+ if (violationAdded) {
+ return;
+ }
+
final ASTAssignmentExpression assignment = node.getFirstParentOfType(ASTAssignmentExpression.class);
if (assignment != null) {
final ASTVariableExpression variable = assignment.getFirstChildOfType(ASTVariableExpression.class);
@@ -611,10 +633,10 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
if (varToTypeMapping.containsKey(variableWithClass)) {
String type = varToTypeMapping.get(variableWithClass);
if (typesFromSOQL.isEmpty()) {
- validateCRUDCheckPresent(node, data, ANY, type);
+ violationAdded = validateCRUDCheckPresent(node, data, ANY, type);
} else {
for (String typeFromSOQL : typesFromSOQL) {
- validateCRUDCheckPresent(node, data, ANY, typeFromSOQL);
+ violationAdded |= validateCRUDCheckPresent(node, data, ANY, typeFromSOQL);
}
}
}
@@ -622,17 +644,27 @@ public class ApexCRUDViolationRule extends AbstractApexRule {
}
+ // If the node's already in violation, we don't need to keep checking.
+ if (violationAdded) {
+ return;
+ }
+
final ASTReturnStatement returnStatement = node.getFirstParentOfType(ASTReturnStatement.class);
if (returnStatement != null) {
if (typesFromSOQL.isEmpty()) {
- validateCRUDCheckPresent(node, data, ANY, returnType);
+ violationAdded = validateCRUDCheckPresent(node, data, ANY, returnType);
} else {
for (String typeFromSOQL : typesFromSOQL) {
- validateCRUDCheckPresent(node, data, ANY, typeFromSOQL);
+ violationAdded |= validateCRUDCheckPresent(node, data, ANY, typeFromSOQL);
}
}
}
+ // If the node's already in violation, we don't need to keep checking.
+ if (violationAdded) {
+ return;
+ }
+
final ASTForEachStatement forEachStatement = node.getFirstParentOfType(ASTForEachStatement.class);
if (forEachStatement != null) {
if (typesFromSOQL.isEmpty()) {
diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java
index fa10da7d26..bfd713a34d 100644
--- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java
+++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTest.java
@@ -43,6 +43,15 @@ public class ApexParserTest extends ApexParserTestBase {
assertEquals(4, methods.size());
}
+ @Test
+ public void fileName() {
+ String code = "class Outer { class Inner {}}";
+
+ ASTUserClass rootNode = (ASTUserClass) parse(code, "src/filename.cls");
+
+ assertEquals("src/filename.cls", rootNode.getAstInfo().getFileName());
+ }
+
private final String testCodeForLineNumbers =
"public class SimpleClass {\n" // line 1
+ " public void method1() {\n" // line 2
diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTestBase.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTestBase.java
index 71c58ae95f..6ad7de0e66 100644
--- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTestBase.java
+++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserTestBase.java
@@ -13,6 +13,10 @@ public class ApexParserTestBase {
return apex.parse(code).getMainNode();
}
+ protected ASTUserClassOrInterface> parse(String code, String fileName) {
+ return apex.parse(code, null, fileName).getMainNode();
+ }
+
protected ASTUserClassOrInterface> parseResource(String code) {
return apex.parseResource(code).getMainNode();
}
diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserXPathTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserXPathTest.java
deleted file mode 100644
index af43119509..0000000000
--- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexParserXPathTest.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.apex.ast;
-
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-
-import org.apache.commons.io.IOUtils;
-import org.junit.Assert;
-import org.junit.Test;
-
-import net.sourceforge.pmd.lang.ast.Node;
-
-public class ApexParserXPathTest extends ApexParserTestBase {
-
- @Test
- public void testBooleanExpressions() throws Exception {
- ApexNode> node = parse(IOUtils.toString(ApexParserXPathTest.class.getResourceAsStream("BooleanExpressions.cls"),
- StandardCharsets.UTF_8));
- List booleanExpressions = node.descendants(ASTBooleanExpression.class).toList();
- Assert.assertEquals(2, booleanExpressions.size());
- Assert.assertEquals("&&", booleanExpressions.get(0).getOperator().toString());
- Assert.assertEquals("!=", booleanExpressions.get(1).getOperator().toString());
-
- List extends Node> xpathResult = node.findChildNodesWithXPath("//BooleanExpression[@Operator='&&']");
- Assert.assertEquals(1, xpathResult.size());
- Assert.assertSame(booleanExpressions.get(0), xpathResult.get(0));
- }
-}
diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeDumpTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeDumpTest.java
index dc7c66b6f1..6ce49d352e 100644
--- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeDumpTest.java
+++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeDumpTest.java
@@ -23,7 +23,7 @@ public class ApexTreeDumpTest extends BaseTreeDumpTest {
}
@Test
- public void safeNavigationOperator() throws Exception {
+ public void safeNavigationOperator() {
doTest("SafeNavigationOperator");
}
}
diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/ApexXPathRuleTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/ApexXPathRuleTest.java
new file mode 100644
index 0000000000..b90d4a26ce
--- /dev/null
+++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/rule/ApexXPathRuleTest.java
@@ -0,0 +1,48 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.apex.rule;
+
+import static net.sourceforge.pmd.lang.ast.test.TestUtilsKt.assertSize;
+
+import org.junit.Test;
+
+import net.sourceforge.pmd.Report;
+import net.sourceforge.pmd.lang.LanguageRegistry;
+import net.sourceforge.pmd.lang.apex.ApexLanguageModule;
+import net.sourceforge.pmd.lang.apex.ast.ApexParserTestBase;
+import net.sourceforge.pmd.lang.rule.XPathRule;
+import net.sourceforge.pmd.lang.rule.xpath.XPathVersion;
+
+/**
+ * @author daniels
+ */
+public class ApexXPathRuleTest extends ApexParserTestBase {
+
+ private XPathRule makeXPath(String expression) {
+ XPathRule rule = new XPathRule(XPathVersion.XPATH_2_0, expression);
+ rule.setLanguage(LanguageRegistry.getLanguage(ApexLanguageModule.NAME));
+ rule.setMessage("XPath Rule Failed");
+ return rule;
+ }
+
+
+ @Test
+ public void testFileNameInXpath() {
+ Report report = apex.executeRule(makeXPath("/UserClass[pmd:fileName() = 'Foo.cls']"),
+ "class Foo {}",
+ "src/Foo.cls");
+
+ assertSize(report, 1);
+ }
+
+ @Test
+ public void testBooleanExpressions() {
+ Report report = apex.executeRuleOnResource(makeXPath("//BooleanExpression[@Operator='&&']"),
+ "BooleanExpressions.cls");
+ assertSize(report, 1);
+ }
+
+
+}
diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/BooleanExpressions.cls b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/BooleanExpressions.cls
similarity index 100%
rename from pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/BooleanExpressions.cls
rename to pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/BooleanExpressions.cls
diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexCRUDViolation.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexCRUDViolation.xml
index 6cd0a03809..697ec2b31b 100644
--- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexCRUDViolation.xml
+++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexCRUDViolation.xml
@@ -1049,6 +1049,38 @@ public class Foo {
]]>
+
+ No CRUD check inside for-each loop
+ 1
+ ();
+ for (Id accId : accIds) {
+ Account acc = [SELECT Id FROM Account WHERE Id = :accId];
+ }
+ }
+}
+ ]]>
+
+
+
+ Proper CRUD check inside for-each loop
+ 0
+ ();
+ if (Account.sObjectType.getDescribe().isAccessible()) {
+ for (Id accId : accIds) {
+ Account a = [SELECT Id FROM Account WHERE Id = :accId];
+ }
+ }
+ }
+}
+ ]]>
+
+
Proper CRUD check in SOQL for-loop with security enforced
0
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/NodeStream.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/NodeStream.java
index d12c91f76c..75b2f90b3f 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/NodeStream.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/ast/NodeStream.java
@@ -14,6 +14,7 @@ import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.function.ToIntFunction;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -620,6 +621,23 @@ public interface NodeStream<@NonNull T extends Node> extends Iterable<@NonNull T
return result;
}
+ /**
+ * Sum the elements of this stream by associating them to an integer.
+ *
+ * @param toInt Map an element to an integer, which will be added
+ * to the running sum
+ * returns the next intermediate result
+ *
+ * @return The sum, zero if the stream is empty.
+ */
+ default int sumBy(ToIntFunction super T> toInt) {
+ int result = 0;
+ for (T node : this) {
+ result += toInt.applyAsInt(node);
+ }
+ return result;
+ }
+
/**
* Returns the number of nodes in this stream.
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/AbstractXPathFunctionDef.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/AbstractXPathFunctionDef.java
index 47a2d86815..7a466ea25c 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/AbstractXPathFunctionDef.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/AbstractXPathFunctionDef.java
@@ -19,12 +19,18 @@ public abstract class AbstractXPathFunctionDef extends ExtensionFunctionDefiniti
private static final String PMD_URI_PREFIX = "http://pmd.sourceforge.net/";
private final StructuredQName qname;
- protected AbstractXPathFunctionDef(String localName, String languageTerseName) {
- String namespacePrefix = "pmd-" + languageTerseName;
- String uri = PMD_URI_PREFIX + namespacePrefix;
+ private AbstractXPathFunctionDef(String localName, String namespacePrefix, String uri) {
this.qname = new StructuredQName(namespacePrefix, uri, localName);
}
+ protected AbstractXPathFunctionDef(String localName) {
+ this(localName, "pmd", PMD_URI_PREFIX + "pmd-core");
+ }
+
+ protected AbstractXPathFunctionDef(String localName, String languageTerseName) {
+ this(localName, "pmd-" + languageTerseName, PMD_URI_PREFIX + "pmd-" + languageTerseName);
+ }
+
@Override
public final StructuredQName getFunctionQName() {
return qname;
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/XPathHandler.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/XPathHandler.java
index 3e048f3adb..7ca9d5893c 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/XPathHandler.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/impl/XPathHandler.java
@@ -5,8 +5,10 @@
package net.sourceforge.pmd.lang.rule.xpath.impl;
import java.util.Collections;
+import java.util.HashSet;
import java.util.Set;
+import net.sourceforge.pmd.lang.rule.xpath.internal.DefaultXPathFunctions;
import net.sourceforge.pmd.util.CollectionUtil;
import net.sf.saxon.lib.ExtensionFunctionDefinition;
@@ -26,15 +28,16 @@ public interface XPathHandler {
static XPathHandler noFunctionDefinitions() {
- return Collections::emptySet;
+ return () -> DefaultXPathFunctions.getDefaultFunctions();
}
-
/**
* Returns a default XPath handler.
*/
static XPathHandler getHandlerForFunctionDefs(ExtensionFunctionDefinition first, ExtensionFunctionDefinition... defs) {
- Set set = CollectionUtil.setOf(first, defs);
- return () -> set;
+ Set set = new HashSet<>(CollectionUtil.setOf(first, defs));
+ set.addAll(DefaultXPathFunctions.getDefaultFunctions());
+
+ return () -> Collections.unmodifiableSet(set);
}
}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DefaultXPathFunctions.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DefaultXPathFunctions.java
new file mode 100644
index 0000000000..bf0a074f70
--- /dev/null
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/DefaultXPathFunctions.java
@@ -0,0 +1,26 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+
+package net.sourceforge.pmd.lang.rule.xpath.internal;
+
+import java.util.Set;
+
+import net.sourceforge.pmd.util.CollectionUtil;
+
+import net.sf.saxon.lib.ExtensionFunctionDefinition;
+
+/**
+ * Default XPath functions provided by pmd-core.
+ */
+public final class DefaultXPathFunctions {
+
+ private DefaultXPathFunctions() {
+ // utility class
+ }
+
+ public static Set getDefaultFunctions() {
+ return CollectionUtil.setOf(FileNameXPathFunction.INSTANCE);
+ }
+}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/FileNameXPathFunction.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/FileNameXPathFunction.java
new file mode 100644
index 0000000000..7605b11856
--- /dev/null
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/FileNameXPathFunction.java
@@ -0,0 +1,62 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.rule.xpath.internal;
+
+import java.nio.file.Paths;
+import java.util.Objects;
+
+import net.sourceforge.pmd.lang.ast.Node;
+import net.sourceforge.pmd.lang.ast.RootNode;
+import net.sourceforge.pmd.lang.rule.xpath.impl.AbstractXPathFunctionDef;
+
+import net.sf.saxon.expr.XPathContext;
+import net.sf.saxon.lib.ExtensionFunctionCall;
+import net.sf.saxon.om.Sequence;
+import net.sf.saxon.trans.XPathException;
+import net.sf.saxon.value.SequenceType;
+import net.sf.saxon.value.StringValue;
+
+/**
+ * A function that returns the current file name.
+ *
+ * @author Clément Fournier
+ */
+public final class FileNameXPathFunction extends AbstractXPathFunctionDef {
+
+ public static final FileNameXPathFunction INSTANCE = new FileNameXPathFunction();
+
+ private FileNameXPathFunction() {
+ super("fileName");
+ }
+
+ @Override
+ public SequenceType[] getArgumentTypes() {
+ return new SequenceType[0];
+ }
+
+ @Override
+ public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) {
+ return SequenceType.STRING_SEQUENCE;
+ }
+
+ @Override
+ public ExtensionFunctionCall makeCallExpression() {
+ return new ExtensionFunctionCall() {
+
+ @Override
+ public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
+ Node node = ((AstElementNode) context.getContextItem()).getUnderlyingNode();
+ RootNode root = node.getRoot();
+ Objects.requireNonNull(root, "No root node in tree?");
+
+ String fileName = root.getAstInfo().getFileName();
+ Objects.requireNonNull(fileName, "File name was not set");
+ String simpleFilename = Paths.get(fileName).getFileName().toString();
+
+ return new StringValue(simpleFilename);
+ }
+ };
+ }
+}
diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/RuleChainAnalyzer.java b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/RuleChainAnalyzer.java
index fe04a55145..afaf60ff6b 100644
--- a/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/RuleChainAnalyzer.java
+++ b/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/xpath/internal/RuleChainAnalyzer.java
@@ -6,8 +6,10 @@ package net.sourceforge.pmd.lang.rule.xpath.internal;
import static net.sourceforge.pmd.util.CollectionUtil.listOf;
+import java.util.ArrayDeque;
import java.util.Collections;
import java.util.Comparator;
+import java.util.Deque;
import java.util.List;
import net.sourceforge.pmd.lang.ast.Node;
@@ -22,6 +24,7 @@ import net.sf.saxon.expr.SlashExpression;
import net.sf.saxon.expr.VennExpression;
import net.sf.saxon.expr.sort.DocumentSorter;
import net.sf.saxon.om.AxisInfo;
+import net.sf.saxon.pattern.CombinedNodeTest;
import net.sf.saxon.pattern.NameTest;
import net.sf.saxon.type.Type;
@@ -45,6 +48,7 @@ public class RuleChainAnalyzer extends SaxonExprVisitor {
private boolean rootElementReplaced;
private boolean insideExpensiveExpr;
private boolean foundPathInsideExpensive;
+ private boolean foundCombinedNodeTest;
public RuleChainAnalyzer(Configuration currentConfiguration) {
this.configuration = currentConfiguration;
@@ -92,7 +96,17 @@ public class RuleChainAnalyzer extends SaxonExprVisitor {
Expression step = newPath.getStep();
if (step instanceof FilterExpression) {
FilterExpression filterExpression = (FilterExpression) step;
- result = new FilterExpression(new AxisExpression(AxisInfo.SELF, null), filterExpression.getFilter());
+
+ Deque filters = new ArrayDeque<>();
+ Expression walker = filterExpression;
+ while (walker instanceof FilterExpression) {
+ filters.push(((FilterExpression) walker).getFilter());
+ walker = ((FilterExpression) walker).getBase();
+ }
+ result = new FilterExpression(new AxisExpression(AxisInfo.SELF, null), filters.pop());
+ while (!filters.isEmpty()) {
+ result = new FilterExpression(result, filters.pop());
+ }
rootElementReplaced = true;
} else if (step instanceof AxisExpression) {
Expression start = newPath.getStart();
@@ -124,13 +138,15 @@ public class RuleChainAnalyzer extends SaxonExprVisitor {
@Override
public Expression visit(AxisExpression e) {
- if (rootElement == null && e.getNodeTest() instanceof NameTest) {
+ if (rootElement == null && e.getNodeTest() instanceof NameTest && !foundCombinedNodeTest) {
NameTest test = (NameTest) e.getNodeTest();
if (test.getPrimitiveType() == Type.ELEMENT && e.getAxis() == AxisInfo.DESCENDANT) {
rootElement = listOf(configuration.getNamePool().getClarkName(test.getFingerprint()));
} else if (test.getPrimitiveType() == Type.ELEMENT && e.getAxis() == AxisInfo.CHILD) {
rootElement = listOf(configuration.getNamePool().getClarkName(test.getFingerprint()));
}
+ } else if (e.getNodeTest() instanceof CombinedNodeTest) {
+ foundCombinedNodeTest = true;
}
return super.visit(e);
}
diff --git a/pmd-core/src/main/resources/rulesets/releases/34.xml b/pmd-core/src/main/resources/rulesets/releases/34.xml
index a3328515ae..6d2924711e 100644
--- a/pmd-core/src/main/resources/rulesets/releases/34.xml
+++ b/pmd-core/src/main/resources/rulesets/releases/34.xml
@@ -15,7 +15,7 @@ This ruleset contains links to rules that are new in PMD v3.4
-
+
diff --git a/pmd-core/src/main/resources/rulesets/releases/35.xml b/pmd-core/src/main/resources/rulesets/releases/35.xml
index 7753b454c6..debffe92c2 100644
--- a/pmd-core/src/main/resources/rulesets/releases/35.xml
+++ b/pmd-core/src/main/resources/rulesets/releases/35.xml
@@ -16,9 +16,9 @@ This ruleset contains links to rules that are new in PMD v3.5
-
+
-
+
diff --git a/pmd-core/src/main/resources/rulesets/releases/36.xml b/pmd-core/src/main/resources/rulesets/releases/36.xml
index 16a32f41f4..8a5cdf594f 100644
--- a/pmd-core/src/main/resources/rulesets/releases/36.xml
+++ b/pmd-core/src/main/resources/rulesets/releases/36.xml
@@ -11,7 +11,7 @@ This ruleset contains links to rules that are new in PMD v3.6
-
+
diff --git a/pmd-core/src/main/resources/rulesets/releases/38.xml b/pmd-core/src/main/resources/rulesets/releases/38.xml
index b0528c8caa..9dacc12123 100644
--- a/pmd-core/src/main/resources/rulesets/releases/38.xml
+++ b/pmd-core/src/main/resources/rulesets/releases/38.xml
@@ -10,7 +10,7 @@ This ruleset contains links to rules that are new in PMD v3.8
-
+
diff --git a/pmd-core/src/main/resources/rulesets/releases/40rc1.xml b/pmd-core/src/main/resources/rulesets/releases/40rc1.xml
index 132f866adf..0ef4736820 100644
--- a/pmd-core/src/main/resources/rulesets/releases/40rc1.xml
+++ b/pmd-core/src/main/resources/rulesets/releases/40rc1.xml
@@ -8,9 +8,9 @@
This ruleset contains links to rules that are new in PMD v4.0rc1
-
-
-
+
+
+
@@ -26,4 +26,3 @@ This ruleset contains links to rules that are new in PMD v4.0rc1
-
\ No newline at end of file
diff --git a/pmd-core/src/main/resources/rulesets/releases/41.xml b/pmd-core/src/main/resources/rulesets/releases/41.xml
index 031efb5aee..cbd7252332 100644
--- a/pmd-core/src/main/resources/rulesets/releases/41.xml
+++ b/pmd-core/src/main/resources/rulesets/releases/41.xml
@@ -13,7 +13,7 @@ This ruleset contains links to rules that are new in PMD v4.1
-
+
diff --git a/pmd-core/src/main/resources/rulesets/releases/42.xml b/pmd-core/src/main/resources/rulesets/releases/42.xml
index 01fe98bc02..aa5f42de36 100644
--- a/pmd-core/src/main/resources/rulesets/releases/42.xml
+++ b/pmd-core/src/main/resources/rulesets/releases/42.xml
@@ -11,7 +11,7 @@ This ruleset contains links to rules that are new in PMD v4.2
-
+
diff --git a/pmd-core/src/main/resources/rulesets/releases/50.xml b/pmd-core/src/main/resources/rulesets/releases/50.xml
index d612ceac00..7406926431 100644
--- a/pmd-core/src/main/resources/rulesets/releases/50.xml
+++ b/pmd-core/src/main/resources/rulesets/releases/50.xml
@@ -38,7 +38,7 @@ This ruleset contains links to rules that are new in PMD v5.0
-
+
diff --git a/pmd-core/src/main/resources/rulesets/releases/550.xml b/pmd-core/src/main/resources/rulesets/releases/550.xml
index 5fb17c056b..82a29edb22 100644
--- a/pmd-core/src/main/resources/rulesets/releases/550.xml
+++ b/pmd-core/src/main/resources/rulesets/releases/550.xml
@@ -9,7 +9,7 @@ This ruleset contains links to rules that are new in PMD v5.5.0
-
+
diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQueryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQueryTest.java
index 454ccc12a5..eab4f0f9f6 100644
--- a/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQueryTest.java
+++ b/pmd-core/src/test/java/net/sourceforge/pmd/lang/rule/xpath/internal/SaxonXPathRuleQueryTest.java
@@ -322,6 +322,38 @@ public class SaxonXPathRuleQueryTest {
assertExpression("docOrder((((/)/descendant::element(Q{}dummyNode))[matches(convertUntyped(data(@SimpleName)), \"a\", \"\")])/child::element(Q{}foo))", query.getFallbackExpr());
}
+
+ @Test
+ public void ruleChainWithUnionsCustomFunctionsVariant1() {
+ SaxonXPathRuleQuery query = createQuery("(//ForStatement | //WhileStatement | //DoStatement)//dummyNode[@Image != '']");
+ List ruleChainVisits = query.getRuleChainVisits();
+ Assert.assertEquals(0, ruleChainVisits.size());
+ }
+
+ @Test
+ public void ruleChainWithUnionsCustomFunctionsVariant2() {
+ SaxonXPathRuleQuery query = createQuery("//(ForStatement | WhileStatement | DoStatement)//dummyNode[@Image != '']");
+ List ruleChainVisits = query.getRuleChainVisits();
+ Assert.assertEquals(0, ruleChainVisits.size());
+ }
+
+ @Test
+ public void ruleChainWithUnionsCustomFunctionsVariant3() {
+ SaxonXPathRuleQuery query = createQuery("//ForStatement//dummyNode[@Image != '']"
+ + " | //WhileStatement//dummyNode[@Image != '']"
+ + " | //DoStatement//dummyNode[@Image != '']");
+ List ruleChainVisits = query.getRuleChainVisits();
+ Assert.assertEquals(3, ruleChainVisits.size());
+ Assert.assertTrue(ruleChainVisits.contains("ForStatement"));
+ Assert.assertTrue(ruleChainVisits.contains("WhileStatement"));
+ Assert.assertTrue(ruleChainVisits.contains("DoStatement"));
+
+ final String expectedSubexpression = "(self::node()/descendant::element(dummyNode))[(string(data(@Image))) ne \"\"]";
+ assertExpression(expectedSubexpression, query.nodeNameToXPaths.get("ForStatement").get(0));
+ assertExpression(expectedSubexpression, query.nodeNameToXPaths.get("WhileStatement").get(0));
+ assertExpression(expectedSubexpression, query.nodeNameToXPaths.get("DoStatement").get(0));
+ }
+
private static void assertExpression(String expected, Expression actual) {
assertEquals(normalizeExprDump(expected),
normalizeExprDump(actual.toString()));
diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml
index 1663f9d031..7ba243789b 100644
--- a/pmd-dist/pom.xml
+++ b/pmd-dist/pom.xml
@@ -252,7 +252,7 @@
org.apache.commons
commons-compress
- 1.19
+ 1.21
test
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnonymousClassDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnonymousClassDeclaration.java
index 1969d8e16c..de7b83edb4 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnonymousClassDeclaration.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnonymousClassDeclaration.java
@@ -4,13 +4,9 @@
package net.sourceforge.pmd.lang.java.ast;
-import static net.sourceforge.pmd.util.CollectionUtil.listOf;
-
-import java.util.Collections;
-import java.util.List;
-
import org.checkerframework.checker.nullness.qual.NonNull;
+import net.sourceforge.pmd.lang.ast.NodeStream;
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
/**
@@ -44,15 +40,15 @@ public final class ASTAnonymousClassDeclaration extends AbstractAnyTypeDeclarati
}
@Override
- public @NonNull List getSuperInterfaceTypeNodes() {
+ public @NonNull NodeStream getSuperInterfaceTypeNodes() {
if (getParent() instanceof ASTConstructorCall) {
ASTConstructorCall ctor = (ASTConstructorCall) getParent();
@NonNull JTypeMirror type = ctor.getTypeMirror();
if (type.isInterface()) {
- return listOf(ctor.getTypeNode());
+ return NodeStream.of(ctor.getTypeNode());
}
}
- return Collections.emptyList();
+ return NodeStream.empty();
}
@Override
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java
index 799249e581..5a51c7b109 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnyTypeDeclaration.java
@@ -6,8 +6,6 @@ package net.sourceforge.pmd.lang.java.ast;
import static net.sourceforge.pmd.lang.java.ast.JModifier.ABSTRACT;
-import java.util.List;
-
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -279,9 +277,8 @@ public interface ASTAnyTypeDeclaration
* Returns the list of interfaces implemented by this class, or
* extended by this interface. Returns null if no such list is declared.
*/
- @NonNull
- default List getSuperInterfaceTypeNodes() {
- return ASTList.orEmpty(isInterface() ? getFirstChildOfType(ASTExtendsList.class)
- : getFirstChildOfType(ASTImplementsList.class));
+ default @NonNull NodeStream getSuperInterfaceTypeNodes() {
+ return ASTList.orEmptyStream(isInterface() ? firstChild(ASTExtendsList.class)
+ : firstChild(ASTImplementsList.class));
}
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryBoxingRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryBoxingRule.java
index 3ac1554cac..33f56b41b8 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryBoxingRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryBoxingRule.java
@@ -8,6 +8,8 @@ import static net.sourceforge.pmd.util.CollectionUtil.setOf;
import java.util.Set;
+import org.apache.commons.lang3.StringUtils;
+
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
@@ -19,6 +21,7 @@ import net.sourceforge.pmd.lang.java.types.JMethodSig;
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
import net.sourceforge.pmd.lang.java.types.OverloadSelectionResult;
import net.sourceforge.pmd.lang.java.types.TypePrettyPrint;
+import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
import net.sourceforge.pmd.lang.java.types.ast.ExprContext;
/**
@@ -71,6 +74,8 @@ public class UnnecessaryBoxingRule extends AbstractJavaRulechainRule {
if (isValueOf && isWrapperValueOf(m)) {
checkBox((RuleContext) data, "boxing", node, node.getArguments().get(0), m.getFormalParameters().get(0));
+ } else if (isValueOf && isStringValueOf(m) && qualifier != null) {
+ checkUnboxing((RuleContext) data, node, qualifier.getTypeMirror());
} else if (!isValueOf && isUnboxingCall(m) && qualifier != null) {
checkBox((RuleContext) data, "unboxing", node, qualifier, qualifier.getTypeMirror());
}
@@ -89,6 +94,13 @@ public class UnnecessaryBoxingRule extends AbstractJavaRulechainRule {
&& m.getFormalParameters().get(0).isPrimitive();
}
+ private boolean isStringValueOf(JMethodSig m) {
+ return m.isStatic()
+ && (m.getArity() == 1 || m.getArity() == 2)
+ && m.getDeclaringType().isBoxedPrimitive()
+ && TypeTestUtil.isA(String.class, m.getFormalParameters().get(0));
+ }
+
private void checkBox(
RuleContext rctx,
String opKind,
@@ -150,6 +162,28 @@ public class UnnecessaryBoxingRule extends AbstractJavaRulechainRule {
}
}
+ private void checkUnboxing(
+ RuleContext rctx,
+ ASTMethodCall methodCall,
+ JTypeMirror conversionOutput
+ ) {
+ // methodCall is e.g. Integer.valueOf("42")
+ // this checks, whether the resulting type "Integer" is e.g. assigned to an "int"
+ // which triggers implicit unboxing.
+ ExprContext ctx = methodCall.getConversionContext();
+ JTypeMirror ctxType = ctx.getTargetType();
+
+ if (ctxType != null) {
+ if (isImplicitlyConvertible(conversionOutput, ctxType)) {
+ if (conversionOutput.unbox().equals(ctxType)) {
+ addViolation(rctx, methodCall, "implicit unboxing. Use "
+ + conversionOutput.getSymbol().getSimpleName() + ".parse"
+ + StringUtils.capitalize(ctxType.getSymbol().getSimpleName()) + "(...) instead");
+ }
+ }
+ }
+ }
+
private boolean isImplicitlyConvertible(JTypeMirror i, JTypeMirror o) {
return i.box().isSubtypeOf(o.box())
|| i.unbox().isSubtypeOf(o.unbox());
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ClassWithOnlyPrivateConstructorsShouldBeFinalRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ClassWithOnlyPrivateConstructorsShouldBeFinalRule.java
new file mode 100644
index 0000000000..85720dedc4
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/ClassWithOnlyPrivateConstructorsShouldBeFinalRule.java
@@ -0,0 +1,49 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design;
+
+import static net.sourceforge.pmd.lang.java.ast.AccessNode.Visibility.V_PRIVATE;
+
+import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
+import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
+import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
+import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
+
+public class ClassWithOnlyPrivateConstructorsShouldBeFinalRule extends AbstractJavaRulechainRule {
+
+ public ClassWithOnlyPrivateConstructorsShouldBeFinalRule() {
+ super(ASTClassOrInterfaceDeclaration.class);
+ }
+
+ @Override
+ public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
+ if (node.isRegularClass()
+ && !node.isFinal()
+ && hasOnlyPrivateCtors(node)
+ && hasNoSubclasses(node)) {
+ addViolation(data, node);
+ }
+ return null;
+ }
+
+ private boolean hasNoSubclasses(ASTClassOrInterfaceDeclaration klass) {
+ return klass.getRoot()
+ .descendants(ASTAnyTypeDeclaration.class)
+ .crossFindBoundaries()
+ .none(it -> doesExtend(it, klass));
+ }
+
+ private boolean doesExtend(ASTAnyTypeDeclaration sub, ASTClassOrInterfaceDeclaration superClass) {
+ return sub != superClass && TypeTestUtil.isA(superClass.getTypeMirror(), sub);
+ }
+
+ private boolean hasOnlyPrivateCtors(ASTClassOrInterfaceDeclaration node) {
+ return node.getDeclarations(ASTConstructorDeclaration.class).all(it -> it.getVisibility() == V_PRIVATE)
+ && (node.getVisibility() == V_PRIVATE // then the default ctor is private
+ || node.getDeclarations(ASTConstructorDeclaration.class).nonEmpty());
+ }
+
+}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyConditionalRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyConditionalRule.java
new file mode 100644
index 0000000000..a5312867cf
--- /dev/null
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyConditionalRule.java
@@ -0,0 +1,63 @@
+/*
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.java.rule.design;
+
+import static net.sourceforge.pmd.lang.java.ast.BinaryOp.CONDITIONAL_AND;
+import static net.sourceforge.pmd.lang.java.ast.BinaryOp.CONDITIONAL_OR;
+import static net.sourceforge.pmd.lang.java.ast.BinaryOp.INSTANCEOF;
+import static net.sourceforge.pmd.lang.java.ast.BinaryOp.NE;
+import static net.sourceforge.pmd.lang.java.ast.BinaryOp.isInfixExprWithOperator;
+import static net.sourceforge.pmd.lang.java.rule.internal.JavaRuleUtil.getOtherOperandIfInInfixExpr;
+import static net.sourceforge.pmd.lang.java.rule.internal.JavaRuleUtil.isBooleanNegation;
+import static net.sourceforge.pmd.lang.java.rule.internal.JavaRuleUtil.isNullCheck;
+
+import net.sourceforge.pmd.lang.java.ast.ASTExpression;
+import net.sourceforge.pmd.lang.java.ast.ASTInfixExpression;
+import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
+import net.sourceforge.pmd.lang.java.rule.internal.StablePathMatcher;
+
+
+public class SimplifyConditionalRule extends AbstractJavaRulechainRule {
+
+ public SimplifyConditionalRule() {
+ super(ASTInfixExpression.class);
+ }
+
+
+ @Override
+ public Object visit(ASTInfixExpression node, Object data) {
+ if (node.getOperator() == INSTANCEOF) {
+
+ StablePathMatcher instanceOfSubject = StablePathMatcher.matching(node.getLeftOperand());
+ if (instanceOfSubject == null) {
+ return null;
+ }
+
+ ASTExpression nullCheckExpr;
+ boolean negated;
+ if (isInfixExprWithOperator(node.getParent(), CONDITIONAL_AND)) {
+ // a != null && a instanceof T
+ negated = false;
+ nullCheckExpr = getOtherOperandIfInInfixExpr(node);
+ } else if (isBooleanNegation(node.getParent())
+ && isInfixExprWithOperator(node.getParent().getParent(), CONDITIONAL_OR)) {
+ // a == null || a instanceof T
+ negated = true;
+ nullCheckExpr = getOtherOperandIfInInfixExpr(node.getParent());
+ } else {
+ return null;
+ }
+
+ if (!isNullCheck(nullCheckExpr, instanceOfSubject)) {
+ return null;
+ }
+
+ if (negated != isInfixExprWithOperator(nullCheckExpr, NE)) {
+ addViolation(data, nullCheckExpr);
+ }
+ }
+ return null;
+ }
+}
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 97c3db3541..21f8d2bcb1 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
@@ -6,11 +6,11 @@ package net.sourceforge.pmd.lang.java.rule.design;
import static net.sourceforge.pmd.properties.constraints.NumericConstraints.positive;
-import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTStatement;
-import net.sourceforge.pmd.lang.java.ast.ASTSwitchLabel;
+import net.sourceforge.pmd.lang.java.ast.ASTSwitchBranch;
+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.ast.JavaParserVisitorAdapter;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
import net.sourceforge.pmd.properties.PropertyDescriptor;
import net.sourceforge.pmd.properties.PropertyFactory;
@@ -24,6 +24,7 @@ import net.sourceforge.pmd.properties.PropertyFactory;
* looking at Subclasses or State Pattern to alleviate the problem.
*
* @author David Dixon-Peugh
+ * @author Clément Fournier
*/
public class SwitchDensityRule extends AbstractJavaRulechainRule {
@@ -36,51 +37,32 @@ public class SwitchDensityRule extends AbstractJavaRulechainRule {
.build();
public SwitchDensityRule() {
- super(ASTSwitchStatement.class);
+ super(ASTSwitchStatement.class, ASTSwitchExpression.class);
definePropertyDescriptor(REPORT_LEVEL);
}
@Override
public Object visit(ASTSwitchStatement node, Object data) {
- double density = new SwitchDensityVisitor().compute(node);
+ return visitSwitchLike(node, data);
+ }
+
+ @Override
+ public Object visit(ASTSwitchExpression node, Object data) {
+ return visitSwitchLike(node, data);
+ }
+
+ public Void visitSwitchLike(ASTSwitchLike node, Object data) {
+ // note: this does not cross find boundaries.
+ int stmtCount = node.descendants(ASTStatement.class).count();
+ int labelCount = node.getBranches()
+ .map(ASTSwitchBranch::getLabel)
+ .sumBy(label -> label.isDefault() ? 1 : label.getExprList().count());
+
+ // note: if labelCount is zero, double division will produce +Infinity or NaN, not ArithmeticException
+ double density = stmtCount / (double) labelCount;
if (density >= getProperty(REPORT_LEVEL)) {
addViolation(data, node);
}
- return super.visit(node, data);
- }
-
- private static class SwitchDensityVisitor extends JavaParserVisitorAdapter {
-
- private int labels = 0;
- private int stmts = 0;
- private ASTSwitchStatement root;
-
-
- double compute(ASTSwitchStatement root) {
- this.root = root;
- root.jjtAccept(this, null);
- return labels == 0 ? 0 : ((double) stmts) / labels;
- }
-
-
- @Override
- public Object visitStatement(ASTStatement statement, Object data) {
- stmts++;
- return super.visitStatement(statement, data);
- }
-
- @Override
- public Object visit(ASTExpression node, Object data) {
- // don't recurse on anonymous class, etc
- return data;
- }
-
- @Override
- public Object visit(ASTSwitchLabel switchLabel, Object data) {
- if (switchLabel.getParent() == root) {
- labels++;
- }
- return super.visit(switchLabel, data);
- }
+ return null;
}
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassRule.java
index 672c6b56b8..abeeb9d7b7 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassRule.java
@@ -6,98 +6,85 @@ package net.sourceforge.pmd.lang.java.rule.design;
import static net.sourceforge.pmd.util.CollectionUtil.setOf;
-import java.util.Collection;
+import java.util.Set;
-import net.sourceforge.pmd.lang.ast.Node;
import net.sourceforge.pmd.lang.java.ast.ASTAnnotation;
-import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
+import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr;
+import net.sourceforge.pmd.lang.java.ast.ASTBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
-import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTMemberValuePair;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
-import net.sourceforge.pmd.lang.java.ast.ASTResultType;
-import net.sourceforge.pmd.lang.java.rule.AbstractLombokAwareRule;
+import net.sourceforge.pmd.lang.java.ast.AccessNode.Visibility;
+import net.sourceforge.pmd.lang.java.ast.JavaNode;
+import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
+import net.sourceforge.pmd.lang.java.rule.internal.JavaRuleUtil;
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
-public class UseUtilityClassRule extends AbstractLombokAwareRule {
+public class UseUtilityClassRule extends AbstractJavaRulechainRule {
- @Override
- protected Collection defaultSuppressionAnnotations() {
- return setOf("lombok.experimental.UtilityClass");
+ private static final Set IGNORED_CLASS_ANNOT = setOf(
+ "lombok.experimental.UtilityClass",
+ "org.junit.runner.RunWith" // for suites and such
+ );
+
+ public UseUtilityClassRule() {
+ super(ASTClassOrInterfaceDeclaration.class);
}
@Override
- public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
- if (hasIgnoredAnnotation(node)) {
+ public Object visit(ASTClassOrInterfaceDeclaration klass, Object data) {
+ if (JavaRuleUtil.hasAnyAnnotation(klass, IGNORED_CLASS_ANNOT)
+ || TypeTestUtil.isA("junit.framework.TestSuite", klass) // suite method is ok
+ || klass.isInterface()
+ || klass.isAbstract()
+ || klass.getSuperClassTypeNode() != null
+ || klass.getSuperInterfaceTypeNodes().nonEmpty()
+ ) {
return data;
}
- return super.visit(node, data);
- }
- @Override
- public Object visit(ASTClassOrInterfaceBody decl, Object data) {
- Object result = super.visit(decl, data);
-
- if (decl.getParent() instanceof ASTClassOrInterfaceDeclaration) {
- ASTClassOrInterfaceDeclaration parent = (ASTClassOrInterfaceDeclaration) decl.getParent();
- if (parent.isAbstract() || parent.isInterface() || parent.getSuperClassTypeNode() != null) {
- return result;
+ boolean hasAnyMethods = false;
+ boolean hasNonPrivateCtor = false;
+ boolean hasAnyCtor = false;
+ for (ASTBodyDeclaration declaration : klass.getDeclarations()) {
+ if (declaration instanceof ASTFieldDeclaration
+ && !((ASTFieldDeclaration) declaration).isStatic()) {
+ return null;
}
-
- if (hasLombokNoArgsConstructor(parent)) {
- return result;
- }
-
- int i = decl.getNumChildren();
- int methodCount = 0;
- boolean isOK = false;
- while (i > 0) {
- Node p = decl.getChild(--i);
- if (p.getNumChildren() == 0) {
- continue;
- }
- Node n = skipAnnotations(p);
- if (n instanceof ASTFieldDeclaration) {
- if (!((ASTFieldDeclaration) n).isStatic()) {
- isOK = true;
- break;
- }
- } else if (n instanceof ASTConstructorDeclaration) {
- if (((ASTConstructorDeclaration) n).isPrivate()) {
- isOK = true;
- break;
- }
- } else if (n instanceof ASTMethodDeclaration) {
- ASTMethodDeclaration m = (ASTMethodDeclaration) n;
- if (!m.isPrivate()) {
- methodCount++;
- }
- if (!m.isStatic()) {
- isOK = true;
- break;
- }
-
- // TODO use symbol table
- if ("suite".equals(m.getName())) {
- ASTResultType res = m.getResultType();
- ASTClassOrInterfaceType c = res.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
- if (c != null && c.hasImageEqualTo("Test")) {
- isOK = true;
- break;
- }
- }
+ if (declaration instanceof ASTConstructorDeclaration) {
+ hasAnyCtor = true;
+ if (((ASTConstructorDeclaration) declaration).getVisibility() != Visibility.V_PRIVATE) {
+ hasNonPrivateCtor = true;
}
}
- if (!isOK && methodCount > 0) {
- addViolation(data, decl);
+
+ if (declaration instanceof ASTMethodDeclaration) {
+ if (((ASTMethodDeclaration) declaration).getVisibility() != Visibility.V_PRIVATE) {
+ hasAnyMethods = true;
+ }
+ if (!((ASTMethodDeclaration) declaration).isStatic()) {
+ return null;
+ }
}
}
- return result;
+
+ // account for default ctor
+ hasNonPrivateCtor |= !hasAnyCtor
+ && klass.getVisibility() != Visibility.V_PRIVATE
+ && !hasLombokPrivateCtor(klass);
+
+
+ String message;
+ if (hasAnyMethods && hasNonPrivateCtor) {
+ message = "This utility class has a non-private constructor";
+ addViolationWithMessage(data, klass, message);
+ }
+ return null;
}
- private boolean hasLombokNoArgsConstructor(ASTClassOrInterfaceDeclaration parent) {
+ private boolean hasLombokPrivateCtor(ASTClassOrInterfaceDeclaration parent) {
// check if there's a lombok no arg private constructor, if so skip the rest of the rules
return parent.getDeclaredAnnotations()
@@ -105,18 +92,16 @@ public class UseUtilityClassRule extends AbstractLombokAwareRule {
.flatMap(ASTAnnotation::getMembers)
// to set the access level of a constructor in lombok, you set the access property on the annotation
.filterMatching(ASTMemberValuePair::getName, "access")
- .map(ASTMemberValuePair::getValue)
// This is from the AccessLevel enum in Lombok
// if the constructor is found and the accesslevel is private no need to check anything else
- .any(it -> "PRIVATE".equals(it.getImage()));
+ .any(it -> isAccessToVarWithName(it.getValue(), "PRIVATE"));
}
- private Node skipAnnotations(Node p) {
- int index = 0;
- Node n = p.getChild(index++);
- while (n instanceof ASTAnnotation && index < p.getNumChildren()) {
- n = p.getChild(index++);
+ private static boolean isAccessToVarWithName(JavaNode node, String name) {
+ if (node instanceof ASTNamedReferenceExpr) {
+ return ((ASTNamedReferenceExpr) node).getName().equals(name);
}
- return n;
+ return false;
}
+
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/JavaRuleUtil.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/JavaRuleUtil.java
index 5cfd743803..72d81182ae 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/JavaRuleUtil.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/JavaRuleUtil.java
@@ -659,7 +659,7 @@ public final class JavaRuleUtil {
return e instanceof ASTBooleanLiteral;
}
- public static boolean isBooleanNegation(ASTExpression e) {
+ public static boolean isBooleanNegation(JavaNode e) {
return e instanceof ASTUnaryExpression && ((ASTUnaryExpression) e).getOperator() == UnaryOp.NEGATION;
}
@@ -963,4 +963,24 @@ public final class JavaRuleUtil {
public static boolean hasLombokAnnotation(Annotatable node) {
return LOMBOK_ANNOTATIONS.stream().anyMatch(node::isAnnotationPresent);
}
+
+ /**
+ * Returns true if the expression is a null check on the given variable.
+ */
+ public static boolean isNullCheck(ASTExpression expr, JVariableSymbol var) {
+ return isNullCheck(expr, StablePathMatcher.matching(var));
+ }
+
+ public static boolean isNullCheck(ASTExpression expr, StablePathMatcher matcher) {
+ if (expr instanceof ASTInfixExpression) {
+ ASTInfixExpression condition = (ASTInfixExpression) expr;
+ if (condition.getOperator().hasSamePrecedenceAs(BinaryOp.EQ)) {
+ ASTNullLiteral nullLit = condition.firstChild(ASTNullLiteral.class);
+ if (nullLit != null) {
+ return matcher.matches(getOtherOperandIfInInfixExpr(nullLit));
+ }
+ }
+ }
+ return false;
+ }
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/StablePathMatcher.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/StablePathMatcher.java
index f3c43de9f7..c6df092758 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/StablePathMatcher.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/internal/StablePathMatcher.java
@@ -4,7 +4,9 @@
package net.sourceforge.pmd.lang.java.rule.internal;
-import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
import java.util.Objects;
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -31,9 +33,9 @@ public final class StablePathMatcher {
// if owner == null, then the owner is `this`.
private final @Nullable JVariableSymbol owner;
- private final ArrayDeque path;
+ private final List path;
- private StablePathMatcher(@Nullable JVariableSymbol owner, ArrayDeque path) {
+ private StablePathMatcher(@Nullable JVariableSymbol owner, List path) {
this.owner = owner;
this.path = path;
}
@@ -88,18 +90,21 @@ public final class StablePathMatcher {
* Otherwise returns null.
*/
public static @Nullable StablePathMatcher matching(ASTExpression e) {
+ if (e == null) {
+ return null;
+ }
JVariableSymbol owner = null;
- ArrayDeque segments = new ArrayDeque<>();
+ List segments = new ArrayList<>();
while (e != null) {
if (e instanceof ASTFieldAccess) {
ASTFieldAccess access = (ASTFieldAccess) e;
- segments.addLast(new Segment(access.getName(), true));
+ segments.add(new Segment(access.getName(), true));
e = access.getQualifier();
} else if (e instanceof ASTMethodCall) {
ASTMethodCall call = (ASTMethodCall) e;
if (JavaRuleUtil.isGetterCall(call)) {
- segments.addLast(new Segment(call.getMethodName(), false));
+ segments.add(new Segment(call.getMethodName(), false));
e = call.getQualifier();
} else {
return null;
@@ -128,6 +133,10 @@ public final class StablePathMatcher {
return new StablePathMatcher(owner, segments);
}
+ public static StablePathMatcher matching(JVariableSymbol e) {
+ return new StablePathMatcher(e, Collections.emptyList());
+ }
+
private static final class Segment {
final String name;
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/DoubleCheckedLockingRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/DoubleCheckedLockingRule.java
index 04427bf008..a944309044 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/DoubleCheckedLockingRule.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/multithreading/DoubleCheckedLockingRule.java
@@ -14,15 +14,13 @@ import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr
import net.sourceforge.pmd.lang.java.ast.ASTAssignmentExpression;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTIfStatement;
-import net.sourceforge.pmd.lang.java.ast.ASTInfixExpression;
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
-import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral;
import net.sourceforge.pmd.lang.java.ast.ASTPrimitiveType;
import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement;
import net.sourceforge.pmd.lang.java.ast.ASTSynchronizedStatement;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
-import net.sourceforge.pmd.lang.java.ast.BinaryOp;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
+import net.sourceforge.pmd.lang.java.rule.internal.JavaRuleUtil;
import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
import net.sourceforge.pmd.lang.java.symbols.JLocalVariableSymbol;
import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol;
@@ -93,15 +91,15 @@ public class DoubleCheckedLockingRule extends AbstractJavaRule {
List isl = node.findDescendantsOfType(ASTIfStatement.class);
if (isl.size() == 2) {
ASTIfStatement outerIf = isl.get(0);
- if (isNullCheck(outerIf.getCondition(), returnVariable)) {
+ if (JavaRuleUtil.isNullCheck(outerIf.getCondition(), returnVariable)) {
// find synchronized
List ssl = outerIf.findDescendantsOfType(ASTSynchronizedStatement.class);
if (ssl.size() == 1 && ssl.get(0).ancestors().any(it -> it == outerIf)) {
ASTIfStatement is2 = isl.get(1);
- if (isNullCheck(is2.getCondition(), returnVariable)) {
+ if (JavaRuleUtil.isNullCheck(is2.getCondition(), returnVariable)) {
List assignments = is2.findDescendantsOfType(ASTAssignmentExpression.class);
if (assignments.size() == 1
- && isReferenceTo(assignments.get(0).getLeftOperand(), returnVariable)) {
+ && JavaRuleUtil.isReferenceToVar(assignments.get(0).getLeftOperand(), returnVariable)) {
addViolation(data, node);
}
@@ -127,7 +125,7 @@ public class DoubleCheckedLockingRule extends AbstractJavaRule {
return (initializer == null || isVolatileFieldReference(initializer))
&& method.descendants(ASTAssignmentExpression.class)
- .filter(it -> isReferenceTo(it.getLeftOperand(), local))
+ .filter(it -> JavaRuleUtil.isReferenceToVar(it.getLeftOperand(), local))
.all(it -> isVolatileFieldReference(it.getRightOperand()));
}
@@ -140,26 +138,4 @@ public class DoubleCheckedLockingRule extends AbstractJavaRule {
}
}
- private boolean isReferenceTo(@Nullable ASTExpression expr, JVariableSymbol symbol) {
- if (expr instanceof ASTNamedReferenceExpr) {
- return symbol != null && symbol.equals(((ASTNamedReferenceExpr) expr).getReferencedSym());
- } else {
- return false;
- }
- }
-
- private boolean isNullCheck(ASTExpression expr, JVariableSymbol var) {
- if (expr instanceof ASTInfixExpression) {
- ASTInfixExpression condition = (ASTInfixExpression) expr;
- if (condition.getOperator().hasSamePrecedenceAs(BinaryOp.EQ)) {
- ASTNullLiteral nullLit = condition.getFirstChildOfType(ASTNullLiteral.class);
- if (nullLit != null) {
- ASTExpression otherChild = (ASTExpression) condition.getChild(1 - nullLit.getIndexInParent());
- return isReferenceTo(otherChild, var);
- }
- }
- }
- return false;
- }
-
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/BooleanInstantiationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/BooleanInstantiationRule.java
deleted file mode 100644
index b8b345c071..0000000000
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/BooleanInstantiationRule.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.performance;
-
-import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
-import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits;
-import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral;
-import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
-import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit;
-import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration;
-import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
-import net.sourceforge.pmd.lang.java.ast.ASTName;
-import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
-import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
-import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
-import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
-import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
-
-/**
- * Avoid instantiating Boolean objects; you can reference Boolean.TRUE,
- * Boolean.FALSE, or call Boolean.valueOf() instead.
- *
- *
- * public class Foo {
- * Boolean bar = new Boolean("true"); // just do a Boolean
- * bar = Boolean.TRUE; //ok
- * Boolean buz = Boolean.valueOf(false); // just do a Boolean buz = Boolean.FALSE;
- * }
- *
- */
-public class BooleanInstantiationRule extends AbstractJavaRule {
-
- /*
- * see bug 1744065 : If somebody create it owns Boolean, the rule should not
- * be triggered Therefore, we use this boolean to flag if the source code
- * contains such an import
- *
- */
- private boolean customBoolean;
-
- @Override
- public Object visit(ASTCompilationUnit decl, Object data) {
- // customBoolean needs to be reset for each new file
- customBoolean = false;
-
- return super.visit(decl, data);
- }
-
- @Override
- public Object visit(ASTImportDeclaration decl, Object data) {
- // If the import actually import a Boolean class that overrides
- // java.lang.Boolean
- if (decl.getImportedName().endsWith("Boolean") && !"java.lang".equals(decl.getImportedName())) {
- customBoolean = true;
- }
- return super.visit(decl, data);
- }
-
- @Override
- public Object visit(ASTAllocationExpression node, Object data) {
-
- if (!customBoolean) {
- if (node.hasDescendantOfType(ASTArrayDimsAndInits.class)) {
- return super.visit(node, data);
- }
-
- ASTClassOrInterfaceType n1 = node.getFirstChildOfType(ASTClassOrInterfaceType.class);
- if (TypeTestUtil.isA(Boolean.class, n1)) {
- super.addViolation(data, node);
- return data;
- }
- }
- return super.visit(node, data);
- }
-
- @Override
- public Object visit(ASTPrimaryPrefix node, Object data) {
-
- if (!customBoolean) {
- if (node.getNumChildren() == 0 || !(node.getChild(0) instanceof ASTName)) {
- return super.visit(node, data);
- }
-
- if ("Boolean.valueOf".equals(((ASTName) node.getChild(0)).getImage())
- || "java.lang.Boolean.valueOf".equals(((ASTName) node.getChild(0)).getImage())) {
- ASTPrimaryExpression parent = (ASTPrimaryExpression) node.getParent();
- ASTPrimarySuffix suffix = parent.getFirstDescendantOfType(ASTPrimarySuffix.class);
- if (suffix == null) {
- return super.visit(node, data);
- }
- ASTPrimaryPrefix prefix = suffix.getFirstDescendantOfType(ASTPrimaryPrefix.class);
- if (prefix == null) {
- return super.visit(node, data);
- }
-
- if (prefix.hasDescendantOfType(ASTBooleanLiteral.class)) {
- super.addViolation(data, node);
- return data;
- }
- ASTLiteral literal = prefix.getFirstDescendantOfType(ASTLiteral.class);
- if (literal != null
- && ("\"true\"".equals(literal.getImage()) || "\"false\"".equals(literal.getImage()))) {
- super.addViolation(data, node);
- return data;
- }
- }
- }
- return super.visit(node, data);
- }
-}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UnnecessaryWrapperObjectCreationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UnnecessaryWrapperObjectCreationRule.java
deleted file mode 100644
index 41521dda36..0000000000
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/performance/UnnecessaryWrapperObjectCreationRule.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.performance;
-
-import static net.sourceforge.pmd.util.CollectionUtil.setOf;
-
-import java.util.Set;
-
-import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
-import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
-import net.sourceforge.pmd.lang.java.rule.codestyle.UnnecessaryBoxingRule;
-
-/**
- * @deprecated Replaced by {@link UnnecessaryBoxingRule}.
- */
-@Deprecated
-public class UnnecessaryWrapperObjectCreationRule extends AbstractJavaRulechainRule {
- private static final Set SUFFIX_SET = setOf("toString", "byteValue",
- "shortValue", "intValue", "longValue", "floatValue", "doubleValue", "charValue", "booleanValue");
-
- public UnnecessaryWrapperObjectCreationRule() {
- super(ASTMethodCall.class);
- }
-
- @Override
- public Object visit(ASTMethodCall node, Object data) {
- if (!"valueOf".equals(node.getMethodName()) || node.getQualifier() == null
- || !node.getQualifier().getTypeMirror().isBoxedPrimitive()
- || !(node.getParent() instanceof ASTMethodCall)) {
- return data;
- }
-
- ASTMethodCall nextMethodCall = (ASTMethodCall) node.getParent();
- String methodName = nextMethodCall.getMethodName();
- if (SUFFIX_SET.contains(methodName)) {
- addViolation(data, node);
- }
-
- return data;
- }
-}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java
index 933646f934..d5a018fdcf 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/symbols/JClassSymbol.java
@@ -166,6 +166,7 @@ public interface JClassSymbol extends JTypeDeclSymbol,
* Returns a set with all enum constant names. If this symbol does
* not represent an enum, returns null.
*/
+ @SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull")
default @Nullable Set getEnumConstantNames() {
return null;
}
diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeTestUtil.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeTestUtil.java
index 4b7017df95..98150320be 100644
--- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeTestUtil.java
+++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeTestUtil.java
@@ -95,7 +95,7 @@ public final class TypeTestUtil {
return isExactlyA(clazz, type.getSymbol());
}
- return isA(type, otherType);
+ return isA(otherType, type);
}
@@ -134,26 +134,35 @@ public final class TypeTestUtil {
return isA(canonicalName, thisType, null);
}
+ public static boolean isA(@NonNull JTypeMirror t1, @Nullable TypeNode t2) {
+ return t2 != null && isA(t1, t2.getTypeMirror());
+ }
+
/**
- * This is the subtyping routine we use, which prunes some behavior
- * of isSubtypeOf that we don't want (eg, that unresolved types are
- * subtypes of everything).
+ * Checks whether the first type is a subtype of the second. This
+ * removes some behavior of isSubtypeOf that we don't want (eg, that
+ * unresolved types are subtypes of everything).
+ *
+ * @param t1 A supertype
+ * @param t2 A type
+ *
+ * @return Whether t1 is a subtype of t2
*/
- private static boolean isA(JTypeMirror t1, JTypeMirror t2) {
- if (t1 == null || t2 == null) {
+ private static boolean isA(@Nullable JTypeMirror t1, @NonNull JTypeMirror t2) {
+ if (t1 == null) {
return false;
- } else if (t1.isPrimitive() || t2.isPrimitive()) {
- return t1.equals(t2); // isSubtypeOf considers primitive widening like subtyping
- } else if (TypeOps.isUnresolved(t1)) {
+ } else if (t2.isPrimitive() || t1.isPrimitive()) {
+ return t2.equals(t1); // isSubtypeOf considers primitive widening like subtyping
+ } else if (TypeOps.isUnresolved(t2)) {
// we can't get any useful info from this, isSubtypeOf would return true
return false;
- } else if (t2.isClassOrInterface() && ((JClassType) t2).getSymbol().isAnonymousClass()) {
+ } else if (t1.isClassOrInterface() && ((JClassType) t1).getSymbol().isAnonymousClass()) {
return false; // conventionally
- } else if (t1 instanceof JTypeVar) {
- return t2.isTop() || isA(((JTypeVar) t1).getUpperBound(), t2);
+ } else if (t2 instanceof JTypeVar) {
+ return t1.isTop() || isA(t1, ((JTypeVar) t2).getUpperBound());
}
- return t1.isSubtypeOf(t2);
+ return t2.isSubtypeOf(t1);
}
private static boolean isA(@NonNull String canonicalName, @NonNull JTypeMirror thisType, @Nullable UnresolvedClassStore unresolvedStore) {
@@ -173,7 +182,7 @@ public final class TypeTestUtil {
TypeSystem ts = thisType.getTypeSystem();
@Nullable JTypeMirror otherType = TypesFromReflection.loadType(ts, canonicalName, unresolvedStore);
- return isA(thisType, otherType);
+ return isA(otherType, thisType);
}
/**
diff --git a/pmd-java/src/main/resources/category/java/bestpractices.xml b/pmd-java/src/main/resources/category/java/bestpractices.xml
index e3a667f011..3a2e29b77a 100644
--- a/pmd-java/src/main/resources/category/java/bestpractices.xml
+++ b/pmd-java/src/main/resources/category/java/bestpractices.xml
@@ -1326,11 +1326,6 @@ public class Foo {
Reports test assertions that may be simplified using a more specific
assertion method. This enables better error messages, and makes the
assertions more readable.
-
- The rule only applies within test classes for the moment. It replaces
- the deprecated rules {% rule UseAssertEqualsInsteadOfAssertTrue %},
- {% rule UseAssertNullInsteadOfAssertTrue %}, {% rule UseAssertSameInsteadOfAssertTrue %},
- {% rule UseAssertTrueInsteadOfAssertEquals %}, and {% rule java/design/SimplifyBooleanAssertion %}.
3
@@ -1647,176 +1642,6 @@ public class Something {
-
-
-This rule detects JUnit assertions in object equality. These assertions should be made by more specific methods, like assertEquals.
-
-Deprecated since PMD 6.37.0, use {% rule SimplifiableTestAssertion %} instead.
-
- 3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-This rule detects JUnit assertions in object references equality. These assertions should be made by
-more specific methods, like assertNull, assertNotNull.
-
-Deprecated since PMD 6.37.0, use {% rule SimplifiableTestAssertion %} instead.
-
- 3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-This rule detects JUnit assertions in object references equality. These assertions should be made
-by more specific methods, like assertSame, assertNotSame.
-
-Deprecated since PMD 6.37.0, use {% rule SimplifiableTestAssertion %} instead.
-
- 3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-When asserting a value is the same as a literal or Boxed boolean, use assertTrue/assertFalse, instead of assertEquals.
-
-Deprecated since PMD 6.37.0, use {% rule SimplifiableTestAssertion %} instead.
-
- 3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Use explicit scoping instead of accidental usage of default package private level.
-The rule allows methods and fields annotated with Guava's @VisibleForTesting and JUnit 5's annotations.
-
-This rule is deprecated since PMD 6.35.0. It assumes that any usage of package-access is accidental,
-and by doing so, prohibits using a really fundamental and useful feature of the language.
-
-To satisfy the rule, you have to make the member public even if it doesn't need to, or make it protected,
-which muddies your intent even more if you don't intend the class to be extended, and may be at odds with
-other rules like {% rule "java/codestyle/AvoidProtectedFieldInFinalClass" %}.
-
-The rule {% rule "java/codestyle/CommentDefaultAccessModifier" %} should be used instead. This rule flags
-the same thing, but has an escape hatch.
-
- 3
-
-
-
-
-
-
-
-
-
3
diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml
index c3c579c464..964bd92fae 100644
--- a/pmd-java/src/main/resources/category/java/design.xml
+++ b/pmd-java/src/main/resources/category/java/design.xml
@@ -312,27 +312,15 @@ public void foo() throws RuntimeException {
-A class with only private constructors should be final, unless the private constructor
-is invoked by a inner class.
+Reports classes that may be made final because they cannot be extended from outside
+their compilation unit anyway. This is because all their constructors are private,
+so a subclass could not call the super constructor.
1
-
-
-
-
-
-
-
@@ -1162,64 +1148,6 @@ public class Foo {
-
-
-Avoid negation in an assertTrue or assertFalse test.
-
-For example, rephrase:
-
- assertTrue(!expr);
-
-as:
-
- assertFalse(expr);
-
-Deprecated since PMD 6.37.0, use {% rule java/bestpractices/SimplifiableTestAssertion %} instead.
-
- 3
-
-
-
-
-
-
-
-
-
-
-
No need to check for null before an instanceof; the instanceof keyword returns false when given a null argument.
3
-
-
-
-
-
-
-
-Methods such as getDeclaredConstructors(), getDeclaredConstructor(Class[]) and setAccessible(),
-as the interface PrivilegedAction, allow for the runtime alteration of variable, class, or
-method visibility, even if they are private. This violates the principle of encapsulation.
+Methods such as `getDeclaredConstructors()`, `getDeclaredMethods()`, and `getDeclaredFields()` also
+return private constructors, methods and fields. These can be made accessible by calling `setAccessible(true)`.
+This gives access to normally protected data which violates the principle of encapsulation.
+
+This rule detects calls to `setAccessible` and finds possible accessibility alterations.
+If the call to `setAccessible` is wrapped within a `PrivilegedAction`, then the access alteration
+is assumed to be deliberate and is not reported.
+
+Note that with Java 17 the Security Manager, which is used for `PrivilegedAction` execution,
+is deprecated: [JEP 411: Deprecate the Security Manager for Removal](https://openjdk.java.net/jeps/411).
+For future-proof code, deliberate access alteration should be suppressed using the usual
+suppression methods (e.g. by using `@SuppressWarnings` annotation).
3
constructor = this.getClass().getDeclaredConstructor(String.class);
+ // call to forbidden setAccessible
+ constructor.setAccessible(true);
- // Possible call to forbidden PrivilegedAction
- PrivilegedAction priv = (PrivilegedAction) new Object(); priv.run();
- }
+ Method privateMethod = this.getClass().getDeclaredMethod("aPrivateMethod");
+ // call to forbidden setAccessible
+ privateMethod.setAccessible(true);
+
+ // deliberate accessibility alteration
+ String privateField = AccessController.doPrivileged(new PrivilegedAction() {
+ @Override
+ public String run() {
+ try {
+ Field field = Violation.class.getDeclaredField("aPrivateField");
+ field.setAccessible(true);
+ return (String) field.get(null);
+ } catch (ReflectiveOperationException | SecurityException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
}
]]>
@@ -637,8 +636,6 @@ k = i * j; // set k with 80 not 120
-
-
-
-
-The method clone() should throw a CloneNotSupportedException.
-
-This rule is deprecated since PMD 6.35.0 without replacement. The rule has no real value as
-`CloneNotSupportedException` is a checked exception and therefore you need to deal with it while
-implementing the `clone()` method. You either need to declare the exception or catch it. If you catch it,
-then subclasses can't throw it themselves explicitly. However, `Object.clone()` will still throw this
-exception if the `Cloneable` interface is not implemented.
-
- 3
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1963,12 +1904,7 @@ If the finalize() is implemented, it should do something besides just calling su
@@ -2032,7 +1968,7 @@ Note that Oracle has declared Object.finalize() as deprecated since JDK 9.
@@ -2123,12 +2059,9 @@ Avoid instantiating an object just to call getClass() on it; use the .class publ
@@ -2144,10 +2077,6 @@ Class c = String.class;
-
-
-
-
@@ -2546,7 +2472,7 @@ confusing.
@@ -2706,54 +2632,6 @@ public class Foo {
-
-
-For any method that returns an array, it is a better to return an empty array rather than a
-null reference. This removes the need for null checking all results and avoids inadvertent
-NullPointerExceptions.
-
-Deprecated since PMD 6.37.0, use {% rule java/errorprone/ReturnEmptyCollectionRatherThanNull %} instead.
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
3
- //FinallyStatement//ReturnStatement except //FinallyStatement//(MethodDeclaration|LambdaExpression)//ReturnStatement
+ //FinallyClause//ReturnStatement except //FinallyClause//(MethodDeclaration|LambdaExpression)//ReturnStatement
@@ -3422,16 +3300,18 @@ public class Main {
class="net.sourceforge.pmd.lang.rule.XPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#useequalstocomparestrings">
-Using '==' or '!=' to compare strings only works if intern version is used on both sides.
-Use the equals() method instead.
+Using '==' or '!=' to compare strings is only reliable if the interned string (`String#intern()`)
+is used on both sides.
+
+Use the `equals()` method instead.
3
diff --git a/pmd-java/src/main/resources/category/java/performance.xml b/pmd-java/src/main/resources/category/java/performance.xml
index f265b4d939..ffe1823903 100644
--- a/pmd-java/src/main/resources/category/java/performance.xml
+++ b/pmd-java/src/main/resources/category/java/performance.xml
@@ -275,51 +275,6 @@ public class Something {
-
-
-Note: this rule is deprecated, as its rationale does not hold.
-
-Java uses the 'short' type to reduce memory usage, not to optimize calculation. In fact, the JVM does not have any
-arithmetic capabilities for the short type: the JVM must convert the short into an int, do the proper calculation
-and convert the int back to a short. Thus any storage gains found through use of the 'short' type may be offset by
-adverse impacts on performance.
-
- 1
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Avoid instantiating Boolean objects; you can reference Boolean.TRUE, Boolean.FALSE, or call Boolean.valueOf() instead.
-Note that new Boolean() is deprecated since JDK 9 for that reason.
-
-Deprecated since PMD 6.37.0, use {% rule java/bestpractices/PrimitiveWrapperInstantiation %} instead.
-
- 2
-
-
-
-
-
-
-
-Calling new Byte() causes memory allocation that can be avoided by the static Byte.valueOf().
-It makes use of an internal cache that recycles earlier instances making it more memory efficient.
-Note that new Byte() is deprecated since JDK 9 for that reason.
-
-Deprecated since PMD 6.37.0, use {% rule java/bestpractices/PrimitiveWrapperInstantiation %} instead.
-
- 2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Calling new Integer() causes memory allocation that can be avoided by the static Integer.valueOf().
-It makes use of an internal cache that recycles earlier instances making it more memory efficient.
-Note that new Integer() is deprecated since JDK 9 for that reason.
-
-Deprecated since PMD 6.37.0, use {% rule java/bestpractices/PrimitiveWrapperInstantiation %} instead.
-
- 2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Calling new Long() causes memory allocation that can be avoided by the static Long.valueOf().
-It makes use of an internal cache that recycles earlier instances making it more memory efficient.
-Note that new Long() is deprecated since JDK 9 for that reason.
-
-Deprecated since PMD 6.37.0, use {% rule java/bestpractices/PrimitiveWrapperInstantiation %} instead.
-
- 2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Note: this rule is deprecated for removal, as the optimization is insignificant.
-
-Calls to `string.startsWith("x")` with a string literal of length 1 can be rewritten using `string.charAt(0)`,
-at the expense of some readability. To prevent `IndexOutOfBoundsException` being thrown by the `charAt` method,
-ensure that the string is not empty by making an additional check first.
-
- 3
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Calling new Short() causes memory allocation that can be avoided by the static Short.valueOf().
-It makes use of an internal cache that recycles earlier instances making it more memory efficient.
-Note that new Short() is deprecated since JDK 9 for that reason.
-
-Deprecated since PMD 6.37.0, use {% rule java/bestpractices/PrimitiveWrapperInstantiation %} instead.
-
- 2
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-Most wrapper classes provide static conversion methods that avoid the need to create intermediate objects
-just to create the primitive forms. Using these avoids the cost of creating objects that also need to be
-garbage-collected later.
-
-Deprecated since PMD 6.37.0. The planned replacement is not expected before PMD 7.0.0.
-
- 3
-
-
-
-
-
-
+
diff --git a/pmd-java/src/main/resources/rulesets/java/clone.xml b/pmd-java/src/main/resources/rulesets/java/clone.xml
index f662ff5473..ec7dc50558 100644
--- a/pmd-java/src/main/resources/rulesets/java/clone.xml
+++ b/pmd-java/src/main/resources/rulesets/java/clone.xml
@@ -12,7 +12,7 @@ The Clone Implementation ruleset contains a collection of rules that find questi
-
+
-
\ No newline at end of file
+
diff --git a/pmd-java/src/main/resources/rulesets/java/controversial.xml b/pmd-java/src/main/resources/rulesets/java/controversial.xml
index 5b2be135bd..1efb0be7c9 100644
--- a/pmd-java/src/main/resources/rulesets/java/controversial.xml
+++ b/pmd-java/src/main/resources/rulesets/java/controversial.xml
@@ -24,7 +24,7 @@ They are held here to allow people to include them as they see fit within their
-
+
@@ -33,7 +33,7 @@ They are held here to allow people to include them as they see fit within their
-
+
diff --git a/pmd-java/src/main/resources/rulesets/java/design.xml b/pmd-java/src/main/resources/rulesets/java/design.xml
index 9ac4ae2fda..e2bde4ae93 100644
--- a/pmd-java/src/main/resources/rulesets/java/design.xml
+++ b/pmd-java/src/main/resources/rulesets/java/design.xml
@@ -28,18 +28,18 @@ are suggested.
-
+
-
+
-
+
diff --git a/pmd-java/src/main/resources/rulesets/java/junit.xml b/pmd-java/src/main/resources/rulesets/java/junit.xml
index d122e26f81..057cd7f536 100644
--- a/pmd-java/src/main/resources/rulesets/java/junit.xml
+++ b/pmd-java/src/main/resources/rulesets/java/junit.xml
@@ -17,10 +17,10 @@ These rules deal with different problems that can occur with JUnit tests.
-
-
-
-
+
+
+
+
-
+
diff --git a/pmd-java/src/main/resources/rulesets/java/logging-java.xml b/pmd-java/src/main/resources/rulesets/java/logging-java.xml
index e4882f5f14..65858b65d8 100644
--- a/pmd-java/src/main/resources/rulesets/java/logging-java.xml
+++ b/pmd-java/src/main/resources/rulesets/java/logging-java.xml
@@ -10,7 +10,7 @@ The Java Logging ruleset contains a collection of rules that find questionable u
-
+
diff --git a/pmd-java/src/main/resources/rulesets/java/migrating.xml b/pmd-java/src/main/resources/rulesets/java/migrating.xml
index bc7681960a..9046281651 100644
--- a/pmd-java/src/main/resources/rulesets/java/migrating.xml
+++ b/pmd-java/src/main/resources/rulesets/java/migrating.xml
@@ -24,9 +24,9 @@ rather, use a wrapper ruleset such as migrating_to_13.xml.
-
-
-
-
+
+
+
+
diff --git a/pmd-java/src/main/resources/rulesets/java/migrating_to_15.xml b/pmd-java/src/main/resources/rulesets/java/migrating_to_15.xml
index 58f833176f..a1514ce199 100644
--- a/pmd-java/src/main/resources/rulesets/java/migrating_to_15.xml
+++ b/pmd-java/src/main/resources/rulesets/java/migrating_to_15.xml
@@ -9,9 +9,9 @@ Contains rules for migrating to JDK 1.5
-
-
-
-
+
+
+
+
diff --git a/pmd-java/src/main/resources/rulesets/java/optimizations.xml b/pmd-java/src/main/resources/rulesets/java/optimizations.xml
index 4439c5385e..ec6d63d4f0 100644
--- a/pmd-java/src/main/resources/rulesets/java/optimizations.xml
+++ b/pmd-java/src/main/resources/rulesets/java/optimizations.xml
@@ -17,10 +17,10 @@ These rules deal with different optimizations that generally apply to best pract
-
-
+
+
-
\ No newline at end of file
+
diff --git a/pmd-java/src/main/resources/rulesets/java/quickstart.xml b/pmd-java/src/main/resources/rulesets/java/quickstart.xml
index 8c0ed47cc6..eca04a16fe 100644
--- a/pmd-java/src/main/resources/rulesets/java/quickstart.xml
+++ b/pmd-java/src/main/resources/rulesets/java/quickstart.xml
@@ -88,7 +88,6 @@
-
@@ -295,7 +294,6 @@
-
@@ -304,7 +302,6 @@
-
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ParserCornersTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ParserCornersTest.java
index c8043d4f0b..f337873ede 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ParserCornersTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/ast/ParserCornersTest.java
@@ -40,8 +40,8 @@ public class ParserCornersTest extends BaseJavaTreeDumpTest {
@Test
public void testInvalidUnicodeEscape() {
expect.expect(TokenMgrError.class); // previously Error
- expect.expectMessage("Lexical error at line 1, column 2. Encountered: Invalid unicode escape");
- java.parse("\\u00k0");
+ expect.expectMessage("Lexical error in file x/filename.java at line 1, column 2. Encountered: Invalid unicode escape");
+ java.parse("\\u00k0", null, "x/filename.java");
}
/**
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertEqualsInsteadOfAssertTrueTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertEqualsInsteadOfAssertTrueTest.java
deleted file mode 100644
index 4df42d6789..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertEqualsInsteadOfAssertTrueTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.bestpractices;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class UseAssertEqualsInsteadOfAssertTrueTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertNullInsteadOfAssertTrueTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertNullInsteadOfAssertTrueTest.java
deleted file mode 100644
index a593a9e0ff..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertNullInsteadOfAssertTrueTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.bestpractices;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class UseAssertNullInsteadOfAssertTrueTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertSameInsteadOfAssertTrueTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertSameInsteadOfAssertTrueTest.java
deleted file mode 100644
index e874a309b1..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertSameInsteadOfAssertTrueTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.bestpractices;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class UseAssertSameInsteadOfAssertTrueTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertTrueInsteadOfAssertEqualsTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertTrueInsteadOfAssertEqualsTest.java
deleted file mode 100644
index cb8ded71bf..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UseAssertTrueInsteadOfAssertEqualsTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.bestpractices;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class UseAssertTrueInsteadOfAssertEqualsTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/DefaultPackageTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/DefaultPackageTest.java
deleted file mode 100644
index 19c6c714fd..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/DefaultPackageTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.codestyle;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class DefaultPackageTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/ClassWithOnlyPrivateConstructorsShouldBeFinalTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/ClassWithOnlyPrivateConstructorsShouldBeFinalTest.java
index 929c188965..1687261131 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/ClassWithOnlyPrivateConstructorsShouldBeFinalTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/ClassWithOnlyPrivateConstructorsShouldBeFinalTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.design;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class ClassWithOnlyPrivateConstructorsShouldBeFinalTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SimplifiedTernaryTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SimplifiedTernaryTest.java
index b57ae4b5b8..c381684027 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SimplifiedTernaryTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SimplifiedTernaryTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.design;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class SimplifiedTernaryTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyBooleanAssertionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyBooleanAssertionTest.java
deleted file mode 100644
index 365bb56a0d..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyBooleanAssertionTest.java
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.design;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-@org.junit.Ignore("Rule has not been updated yet")
-public class SimplifyBooleanAssertionTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyConditionalTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyConditionalTest.java
index 43ed3e5754..927ae8d8f8 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyConditionalTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SimplifyConditionalTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.design;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class SimplifyConditionalTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityTest.java
index c19a339f55..0da92cecac 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/SwitchDensityTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.design;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class SwitchDensityTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassTest.java
index b9275c8101..36e7942a09 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/design/UseUtilityClassTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.design;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class UseUtilityClassTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/ReturnEmptyArrayRatherThanNullTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidAccessibilityAlterationTest.java
similarity index 64%
rename from pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/ReturnEmptyArrayRatherThanNullTest.java
rename to pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidAccessibilityAlterationTest.java
index 428d6737bf..cd5c41a995 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/ReturnEmptyArrayRatherThanNullTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidAccessibilityAlterationTest.java
@@ -1,4 +1,4 @@
-/**
+/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
-public class ReturnEmptyArrayRatherThanNullTest extends PmdRuleTst {
+public class AvoidAccessibilityAlterationTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloneThrowsCloneNotSupportedExceptionTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloneThrowsCloneNotSupportedExceptionTest.java
deleted file mode 100644
index 2dfbc243d2..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/CloneThrowsCloneNotSupportedExceptionTest.java
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.errorprone;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-@org.junit.Ignore("Rule has not been updated yet")
-public class CloneThrowsCloneNotSupportedExceptionTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeDoesNotCallSuperFinalizeTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeDoesNotCallSuperFinalizeTest.java
index f74194a4d5..97017d2b87 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeDoesNotCallSuperFinalizeTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeDoesNotCallSuperFinalizeTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class FinalizeDoesNotCallSuperFinalizeTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeOnlyCallsSuperFinalizeTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeOnlyCallsSuperFinalizeTest.java
index 929b7ebe7b..af0ab11739 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeOnlyCallsSuperFinalizeTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeOnlyCallsSuperFinalizeTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class FinalizeOnlyCallsSuperFinalizeTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeOverloadedTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeOverloadedTest.java
index 5efb414193..e123e98a1c 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeOverloadedTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeOverloadedTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class FinalizeOverloadedTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeShouldBeProtectedTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeShouldBeProtectedTest.java
index 5fb2be61f2..73b0ee58fc 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeShouldBeProtectedTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/FinalizeShouldBeProtectedTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class FinalizeShouldBeProtectedTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/InstantiationToGetClassTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/InstantiationToGetClassTest.java
index 002a4b5e05..f27f820f6f 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/InstantiationToGetClassTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/InstantiationToGetClassTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class InstantiationToGetClassTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/MissingSerialVersionUIDTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/MissingSerialVersionUIDTest.java
index 608f84996c..b2437fbaf8 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/MissingSerialVersionUIDTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/MissingSerialVersionUIDTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class MissingSerialVersionUIDTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/NonStaticInitializerTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/NonStaticInitializerTest.java
index 8f3c4fa311..f009ce5ab2 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/NonStaticInitializerTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/NonStaticInitializerTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class NonStaticInitializerTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/ReturnFromFinallyBlockTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/ReturnFromFinallyBlockTest.java
index 1d83115c71..5945a9133f 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/ReturnFromFinallyBlockTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/ReturnFromFinallyBlockTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class ReturnFromFinallyBlockTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/UseEqualsToCompareStringsTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/UseEqualsToCompareStringsTest.java
index 2ac4f0f2dc..903c0d420d 100644
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/UseEqualsToCompareStringsTest.java
+++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/errorprone/UseEqualsToCompareStringsTest.java
@@ -6,7 +6,6 @@ package net.sourceforge.pmd.lang.java.rule.errorprone;
import net.sourceforge.pmd.testframework.PmdRuleTst;
-@org.junit.Ignore("Rule has not been updated yet")
public class UseEqualsToCompareStringsTest extends PmdRuleTst {
// no additional unit tests
}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/AvoidUsingShortTypeTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/AvoidUsingShortTypeTest.java
deleted file mode 100644
index 5a639a8a74..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/AvoidUsingShortTypeTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.performance;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class AvoidUsingShortTypeTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/BooleanInstantiationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/BooleanInstantiationTest.java
deleted file mode 100644
index 57510e54c8..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/BooleanInstantiationTest.java
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.performance;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-@org.junit.Ignore("Rule has not been updated yet")
-public class BooleanInstantiationTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/ByteInstantiationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/ByteInstantiationTest.java
deleted file mode 100644
index 2db2199779..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/ByteInstantiationTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.performance;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class ByteInstantiationTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/IntegerInstantiationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/IntegerInstantiationTest.java
deleted file mode 100644
index a951c8eda7..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/IntegerInstantiationTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.performance;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class IntegerInstantiationTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/LongInstantiationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/LongInstantiationTest.java
deleted file mode 100644
index a2b951cb00..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/LongInstantiationTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.performance;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class LongInstantiationTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/ShortInstantiationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/ShortInstantiationTest.java
deleted file mode 100644
index 564c94b6fd..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/ShortInstantiationTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.performance;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class ShortInstantiationTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/SimplifyStartsWithTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/SimplifyStartsWithTest.java
deleted file mode 100644
index e2a3fbcd15..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/SimplifyStartsWithTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.performance;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class SimplifyStartsWithTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/UnnecessaryWrapperObjectCreationTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/UnnecessaryWrapperObjectCreationTest.java
deleted file mode 100644
index 08da381245..0000000000
--- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/performance/UnnecessaryWrapperObjectCreationTest.java
+++ /dev/null
@@ -1,11 +0,0 @@
-/**
- * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
- */
-
-package net.sourceforge.pmd.lang.java.rule.performance;
-
-import net.sourceforge.pmd.testframework.PmdRuleTst;
-
-public class UnnecessaryWrapperObjectCreationTest extends PmdRuleTst {
- // no additional unit tests
-}
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertEqualsInsteadOfAssertTrue.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertEqualsInsteadOfAssertTrue.xml
deleted file mode 100644
index b604960de4..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertEqualsInsteadOfAssertTrue.xml
+++ /dev/null
@@ -1,99 +0,0 @@
-
-
-
-
- Identity test doesn't match
- 0
-
-
-
-
- Junit 3 problem
- 1
-
-
-
-
- Overload of equal doesn't match
- 0
-
-
-
-
- JUnit 4, even outside of @Test method
- 1
-
-
-
-
- JUnit4 - match
- 1
-
-
-
-
- JUnit5 - @Test
- 1
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertNullInsteadOfAssertTrue.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertNullInsteadOfAssertTrue.xml
deleted file mode 100644
index fdd79d4e26..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertNullInsteadOfAssertTrue.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-
-
-
-
- assertTrue with null
- 1
-
-
-
-
- assertFalse with != null
- 1
-
-
-
-
- assertTrue with x == y
- 0
-
-
-
-
- Not a JUnit test - assertTrue with null
- 0
-
-
-
-
- JUnit 4 - assertTrue with null
- 1
-
-
-
-
- JUnit 5 - assertTrue with null - @Test
- 1
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertSameInsteadOfAssertTrue.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertSameInsteadOfAssertTrue.xml
deleted file mode 100644
index 5a0a74559e..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertSameInsteadOfAssertTrue.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-
-
-
-
- assert true a == b
- 1
-
-
-
-
- assert true a != b
- 1
-
-
-
-
- assert false a == b
- 1
-
-
-
-
- assert false a != b
- 1
-
-
-
-
- skip assertTrue(x == null), UseAssertNullInsteadOfAssertTrue will pick those up
- 0
-
-
-
-
- bug 1626715, the null check in the rule shouldn't match the null outside the assert method
- 1
-
-
-
-
- assert true a == b BUT not a Junit test
- 0
-
-
-
-
- JUnit 4 - assert true a == b
- 1
-
-
-
-
- JUnit 5 - assert true a == b - @Test
- 1
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertTrueInsteadOfAssertEquals.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertTrueInsteadOfAssertEquals.xml
deleted file mode 100644
index 13358b5119..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UseAssertTrueInsteadOfAssertEquals.xml
+++ /dev/null
@@ -1,96 +0,0 @@
-
-
-
-
- JUnit Test contains assertEquals on other than boolean literal
- 0
-
-
-
-
- JUnit Test contains assertEquals on boolean literal
- 5
-
-
-
-
- #1323 False positive case of UseAssertTrueInsteadOfAssertEquals
- 0
-
-
-
-
- JUnit Test contains assertEquals with Boxed booleans
- 8
-
-
-
-
- JUnit Test contains assertEquals with Boxed booleans as param
- 0
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/DefaultPackage.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/DefaultPackage.xml
deleted file mode 100644
index 5882f7e174..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/DefaultPackage.xml
+++ /dev/null
@@ -1,176 +0,0 @@
-
-
-
-
- ok
- 0
-
-
-
-
- bad
- 1
-
-
-
-
- interface methods are always public
- 0
-
-
-
-
- interface field are always public
- 0
-
-
-
-
- bad
- 1
-
-
-
-
- #1410 DefaultPackage triggers on field annotated with @VisibleForTesting
- 0
-
-
-
-
- #2573 DefaultPackage triggers on field annotated with JUnit 5 @Test
- 0
-
-
-
-
- #2573 DefaultPackage triggers on field annotated with JUnit 5 @RepeatedTest
- 0
-
-
-
-
- #2573 DefaultPackage triggers on field annotated with JUnit 5 @ParameterizedTest
- 0
-
-
-
-
- #2573 DefaultPackage triggers on field annotated with JUnit 5 @TestFactory
- 0
-
-
-
-
- #2573 DefaultPackage triggers on field annotated with JUnit 5 @TestTemplate
- 0
-
-
-
-
- #2573 DefaultPackage triggers on field annotated with JUnit 5 @BeforeAll
- 0
-
-
-
-
- #2573 DefaultPackage triggers on field annotated with JUnit 5 @AfterAll
- 0
-
-
-
-
- #2573 DefaultPackage triggers on field annotated with JUnit 5 @BeforeEach
- 0
-
-
-
-
- #2573 DefaultPackage triggers on field annotated with JUnit 5 @AfterEach
- 0
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryBoxing.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryBoxing.xml
index a4b5e0ea2d..d891877022 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryBoxing.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryBoxing.xml
@@ -200,4 +200,137 @@ public class Foo {
}
}
]]>
-
+
+
+
+ Uses of Integer.valueOf(someString) where an int is expected
+ 4
+ 3,4,5,6
+
+ Unnecessary implicit unboxing. Use Integer.parseInt(...) instead
+ Unnecessary implicit unboxing. Use Integer.parseInt(...) instead
+ Unnecessary implicit unboxing. Use Integer.parseInt(...) instead
+ Unnecessary implicit unboxing. Use Integer.parseInt(...) instead
+
+
+
+
+
+ Uses of Long.valueOf(someString) where an long is expected
+ 4
+ 3,4,5,6
+
+ Unnecessary implicit unboxing. Use Long.parseLong(...) instead
+ Unnecessary implicit unboxing. Use Long.parseLong(...) instead
+ Unnecessary implicit unboxing. Use Long.parseLong(...) instead
+ Unnecessary implicit unboxing. Use Long.parseLong(...) instead
+
+
+
+
+
+ Uses of Double.valueOf(someString) where an double is expected
+ 2
+ 3,4
+
+ Unnecessary implicit unboxing. Use Double.parseDouble(...) instead
+ Unnecessary implicit unboxing. Use Double.parseDouble(...) instead
+
+
+
+
+
+ Uses of Float.valueOf(someString) where an float is expected
+ 2
+ 3,4
+
+ Unnecessary implicit unboxing. Use Float.parseFloat(...) instead
+ Unnecessary implicit unboxing. Use Float.parseFloat(...) instead
+
+
+
+
+
+ Uses of Short.valueOf(someString) where an short is expected
+ 4
+ 3,4,5,6
+
+ Unnecessary implicit unboxing. Use Short.parseShort(...) instead
+ Unnecessary implicit unboxing. Use Short.parseShort(...) instead
+ Unnecessary implicit unboxing. Use Short.parseShort(...) instead
+ Unnecessary implicit unboxing. Use Short.parseShort(...) instead
+
+
+
+
+
+ Uses of Boolean.valueOf(someString) where an boolean is expected
+ 2
+ 3,4
+
+ Unnecessary implicit unboxing. Use Boolean.parseBoolean(...) instead
+ Unnecessary implicit unboxing. Use Boolean.parseBoolean(...) instead
+
+
+
+
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ClassWithOnlyPrivateConstructorsShouldBeFinal.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ClassWithOnlyPrivateConstructorsShouldBeFinal.xml
index 538aca8368..fe66fa1313 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ClassWithOnlyPrivateConstructorsShouldBeFinal.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/ClassWithOnlyPrivateConstructorsShouldBeFinal.xml
@@ -135,4 +135,28 @@ class ClassWithOnlyPrivateConstructorsShouldBeFinal {
}
]]>
+
+ #2536 [java] ClassWithOnlyPrivateConstructorsShouldBeFinal can't detect inner class with only private constructor
+ 1
+ 2
+
+
+
+ Private inner class with no ctor
+ 1
+ 2
+
+
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifiedTernary.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifiedTernary.xml
index 2002135780..e3305ee2ff 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifiedTernary.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifiedTernary.xml
@@ -9,7 +9,7 @@
1
1
1
1
condition ? true : false
- 0
+ 1
@@ -69,8 +69,8 @@ public class Foo {
0
@@ -81,7 +81,7 @@ public class SimplifiedTernary {
0
-
-
-
- assertFalse(!)
- 1
-
-
-
-
- assertTrue(!)
- 1
-
-
-
-
- ok
- 0
-
-
-
-
- not a JUnit test - assertFalse(!)
- 0
-
-
-
-
- JUnit 4 - assertFalse(!)
- 1
-
-
-
-
- JUnit 5 - assertFalse(!)
- 1
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifyConditional.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifyConditional.xml
index 32846c87f2..ad2f14df16 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifyConditional.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/SimplifyConditional.xml
@@ -98,11 +98,10 @@ public class Bug1843273 {
Bug 2317099 : False + in SimplifyConditional
0
+
+ Switch expr
+ 4
+ 1
+
+
+
+ Switch expr, composite label
+ 4
+ 0
+
+
One stmt in one switch case, ok
@@ -69,6 +113,44 @@ public class SwitchDensity3 {
}
}
}
+}
+ ]]>
+
+
+
+ False positive with default label
+ 10
+ 0
+
+
+
+ Empty switch
+ 0
+
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UseUtilityClass.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UseUtilityClass.xml
index 81ab0468f8..32af58ff8f 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UseUtilityClass.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/UseUtilityClass.xml
@@ -7,6 +7,9 @@
should be utility class since all static, public constructor
1
+
+ This utility class has a non-private constructor
+
- junit 'suite' method is OK
+ junit 3 'suite' method is OK
0
+
+ junit 4 'suite' method is OK
+ 0
+
+
Reproducing bug [ 2315599 ] False +: UseSingleton with class containing constructor: Although there is a static method, the class also has a non-private constructor. This is a common design for custom exceptions which contain a private static method to format error message strings.
@@ -206,19 +226,17 @@ public class MyException extends RuntimeException {
#1467 UseUtilityClass can't correctly check functions with multiple annotations
0
@@ -257,21 +275,6 @@ public class Foo {
]]>
-
- Lombok NoArgsConstructor no import- ok
- 0
-
-
-
Lombok NoArgsConstructor with no access level- should be a utility class
1
@@ -352,9 +355,21 @@ public class MyUtil {
Inner class in abstract class false-negative
1
+ 2
+
+
+ Private inner class in abstract class
+ 0
+ 1
1
Inner class in sub-class false-negative
1
+ 2
+
+
+
+ Example code snippet
+ 2
+ 11,15
+ constructor = this.getClass().getDeclaredConstructor(String.class);
+ // call to forbidden setAccessible
+ constructor.setAccessible(true);
+
+ Method privateMethod = this.getClass().getDeclaredMethod("aPrivateMethod");
+ // call to forbidden setAccessible
+ privateMethod.setAccessible(true);
+
+ // deliberate accessibility alteration
+ String privateField = AccessController.doPrivileged(new PrivilegedAction() {
+ @Override
+ public String run() {
+ try {
+ Field field = Violation.class.getDeclaredField("aPrivateField");
+ field.setAccessible(true);
+ return (String) field.get(null);
+ } catch (ReflectiveOperationException | SecurityException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
+ }
+}
+ ]]>
+
+
+
+ Detect calls to setAccessible
+ 9
+ 9,12,13,16,19,20,23,26,27
+ constructor : this.getClass().getConstructors()) {
+ constructor.setAccessible(true);
+ }
+ Constructor>[] constructors = this.getClass().getConstructors();
+ AccessibleObject.setAccessible(constructors, true);
+ Constructor.setAccessible(constructors, true);
+
+ for (Method method : this.getClass().getMethods()) {
+ method.setAccessible(true);
+ }
+ Method[] methods = this.getClass().getMethods();
+ AccessibleObject.setAccessible(methods, true);
+ Method.setAccessible(methods, true);
+
+ for (Field field : this.getClass().getFields()) {
+ field.setAccessible(true);
+ }
+ Field[] fields = this.getClass().getFields();
+ AccessibleObject.setAccessible(fields, true);
+ Field.setAccessible(fields, true);
+ }
+}
+ ]]>
+
+
+
+
+ Make sure to detect method call chains
+ 6
+ 3,4,5,6,7,8
+
+
+
+
+ Anonymous privileged action is OK
+ 0
+ () {
+ @Override
+ public Method[] run() {
+ Method[] declaredMethods = Violation.class.getDeclaredMethods();
+ AccessibleObject.setAccessible(declaredMethods, true);
+ return declaredMethods;
+ }
+ });
+ try {
+ methods[0].invoke(null);
+ } catch (ReflectiveOperationException e) {
+ e.printStackTrace();
+ }
+ }
+}
+ ]]>
+
+
+
+ Inner class privileged action is OK
+ 0
+ {
+ @Override
+ public Field[] run() {
+ Field[] declaredFields = Violation.class.getDeclaredFields();
+ AccessibleObject.setAccessible(declaredFields, true);
+ return declaredFields;
+ }
+ }
+}
+ ]]>
+
+
+
+ false positive when accessible object is used as primary prefix
+ 0
+ > list = new ArrayList<>();
+ Constructor> ctor = NoViolation.class.getConstructor();
+ list.add(ctor);
+} }
+ ]]>
+
+
+
+ setAccessible(false) is ok
+ 0
+ constructor = this.getClass().getDeclaredConstructor(String.class);
+ // call to setAccessible with false - that's ok
+ constructor.setAccessible(false);
+
+ Constructor>[] constructors = this.getClass().getConstructors();
+ AccessibleObject.setAccessible(constructors, false);
+ Constructor.setAccessible(constructors, false);
+ }
+}
+ ]]>
+
+
\ No newline at end of file
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/CloneThrowsCloneNotSupportedException.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/CloneThrowsCloneNotSupportedException.xml
deleted file mode 100644
index f4e4da306f..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/CloneThrowsCloneNotSupportedException.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-
-
-
-
- ok, throws CloneNotSupportedException
- 0
-
-
-
-
- bad
- 1
-
-
-
-
- final class, rule does not apply
- 0
-
-
-
-
- testing with multiple methods
- 1
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingSerialVersionUID.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingSerialVersionUID.xml
index e88e57ea14..3da6fa9c53 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingSerialVersionUID.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/MissingSerialVersionUID.xml
@@ -17,6 +17,8 @@ public class Foo {
Simple failure case
1
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ReturnEmptyArrayRatherThanNull.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ReturnEmptyArrayRatherThanNull.xml
deleted file mode 100644
index dbdbc79bb5..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ReturnEmptyArrayRatherThanNull.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
- Basic test case
- 1
-
-
-
-
- good behavior should not trigger violation
- 0
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/UseEqualsToCompareStrings.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/UseEqualsToCompareStrings.xml
index 934090bf33..d535631744 100644
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/UseEqualsToCompareStrings.xml
+++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/UseEqualsToCompareStrings.xml
@@ -144,6 +144,8 @@ public class O {
#2979 UseEqualsToCompareStrings: FP with "var" variables
0
#2979 UseEqualsToCompareStrings: FP with "var" variables (control, types are explicit)
0
+
+
+ False positive with string concatentation
+ 0
+
+
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/AvoidUsingShortType.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/AvoidUsingShortType.xml
deleted file mode 100644
index 95eecb27da..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/AvoidUsingShortType.xml
+++ /dev/null
@@ -1,144 +0,0 @@
-
-
-
-
- Short as field
- 1
-
-
-
-
- Short as local variable
- 1
-
-
-
-
- Short as method return type
- 2
-
-
-
-
- Short as method return type
- 0
-
-
-
-
- #1449 false positive when casting a variable to short
- 0
-
-
-
-
- short as method parameter
- 1
-
-
-
-
- short as method parameter with @Override
- 0
-
-
-
-
- [java] AvoidUsingShortType erroneously triggered on overrides of 3rd party methods (anon. class) #586
- 0
-
-
-
-
- [java] AvoidUsingShortType erroneously triggered on overrides of 3rd party methods #586
- 0
-
-
-
-
- short as annotation property
- 1
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/BooleanInstantiation.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/BooleanInstantiation.xml
deleted file mode 100644
index 4d38c36a64..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/BooleanInstantiation.xml
+++ /dev/null
@@ -1,163 +0,0 @@
-
-
-
-
- simple failure case
- 1
-
-
-
-
- new java.lang.Boolean
- 1
-
-
-
-
- ok
- 0
-
-
-
-
- don't use Boolean.valueOf() with literal
- 2
-
-
-
-
- valueOf() with variable is fine
- 0
-
-
-
-
- don't use Boolean.valueOf() with string literal
- 1
-
-
-
-
- don't use Boolean.valueOf() in method call
- 1
-
-
-
-
- don't use new Boolean() in method call
- 1
-
-
-
-
- ok
- 0
-
-
-
-
- ok
- 0
-
-
-
-
- don't use new Boolean() in static block
- 1
-
-
-
-
- Bug 1744065, should be ok
- 0
-
-
-
-
- Test for failure after rule with custom Boolean, should report failure if rule reset done correctly
- 1
-
-
-
-
- #1533 [java] BooleanInstantiation: ClassCastException with Annotation
- 0
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/ByteInstantiation.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/ByteInstantiation.xml
deleted file mode 100644
index 2cbd7a2b44..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/ByteInstantiation.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- new Byte(), bad
- 1
-
-
-
-
- Byte.valueOf(), ok
- 0
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/IntegerInstantiation.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/IntegerInstantiation.xml
deleted file mode 100644
index 208c229141..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/IntegerInstantiation.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-
-
-
-
- new Integer(), bad
- 1
-
-
-
-
- Integer.valueOf(), ok
- 0
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/LongInstantiation.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/LongInstantiation.xml
deleted file mode 100644
index 154dc5c2ab..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/LongInstantiation.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- new Long(), bad
- 1
-
-
-
-
- Long.valueOf(), ok
- 0
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/ShortInstantiation.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/ShortInstantiation.xml
deleted file mode 100644
index 22f52ea6a1..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/ShortInstantiation.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-
-
-
-
- new Short(), bad
- 1
-
-
-
-
- Short.valueOf(), ok
- 0
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/SimplifyStartsWith.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/SimplifyStartsWith.xml
deleted file mode 100644
index 3a67cfa8b9..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/SimplifyStartsWith.xml
+++ /dev/null
@@ -1,90 +0,0 @@
-
-
-
-
- failure case
- 1
-
-
-
-
- startsWith multiple chars
- 0
-
-
-
-
- startsWith defined on some other class, doesn't take a String
- 0
-
-
-
-
- Document Jaxen exception parsing Unicode chars in startsWith
- 0
-
-
-
-
- #1392 SimplifyStartsWith false-negative
- 1
- 5
-
-
-
- #2712 SimplifyStartsWith false-positive on receiver != String
- 0
-
-
-
diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/UnnecessaryWrapperObjectCreation.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/UnnecessaryWrapperObjectCreation.xml
deleted file mode 100644
index 1ca86628de..0000000000
--- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/UnnecessaryWrapperObjectCreation.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
- failure case
- 1
- 3
-
-
-
-
- calling valueOf is OK
- 0
-
-
-
-
- failure case for 1.5+
- 1
- 3
-
-
-
-
- Patch 2075906: Add toString() to the rule UnnecessaryWrapperObjectCreation
- 1
- 3
-
-
-
-
- #1057 False positive for UnnecessaryWrapperObjectCreation
- 1
- 3
-
-
-
-
- NPE with static method call
- 0
-
-
-
diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/cpd/test/CpdTextComparisonTest.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/cpd/test/CpdTextComparisonTest.kt
index 9ea953c086..2a09f7874f 100644
--- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/cpd/test/CpdTextComparisonTest.kt
+++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/cpd/test/CpdTextComparisonTest.kt
@@ -46,8 +46,8 @@ abstract class CpdTextComparisonTest(
*/
@JvmOverloads
fun doTest(fileBaseName: String, expectedSuffix: String = "", properties: Properties = defaultProperties()) {
- super.doTest(fileBaseName, expectedSuffix) { sourceText ->
- val sourceCode = SourceCode(SourceCode.StringCodeLoader(sourceText, "$fileBaseName$extensionIncludingDot"))
+ super.doTest(fileBaseName, expectedSuffix) { fileData ->
+ val sourceCode = SourceCode(SourceCode.StringCodeLoader(fileData.fileText, fileData.fileName))
val tokens = Tokens().also {
val tokenizer = newTokenizer(properties)
tokenizer.tokenize(sourceCode, it)
@@ -58,10 +58,18 @@ abstract class CpdTextComparisonTest(
}
@JvmOverloads
- fun expectTokenMgrError(source: String, properties: Properties = defaultProperties()): TokenMgrError =
- shouldThrow {
- newTokenizer(properties).tokenize(sourceCodeOf(source), Tokens())
- }
+ fun expectTokenMgrError(
+ source: String,
+ fileName: String = SourceCode.StringCodeLoader.DEFAULT_NAME,
+ properties: Properties = defaultProperties()
+ ): TokenMgrError =
+ expectTokenMgrError(FileData(fileName, source), properties)
+
+ @JvmOverloads
+ fun expectTokenMgrError(fileData: FileData, properties: Properties = defaultProperties()): TokenMgrError =
+ shouldThrow {
+ newTokenizer(properties).tokenize(sourceCodeOf(fileData), Tokens())
+ }
private fun StringBuilder.format(tokens: Tokens) {
@@ -140,11 +148,13 @@ abstract class CpdTextComparisonTest(
fun sourceCodeOf(str: String): SourceCode = SourceCode(SourceCode.StringCodeLoader(str))
+ fun sourceCodeOf(fileData: FileData): SourceCode =
+ SourceCode(SourceCode.StringCodeLoader(fileData.fileText, fileData.fileName))
fun tokenize(tokenizer: Tokenizer, str: String): Tokens =
- Tokens().also {
- tokenizer.tokenize(sourceCodeOf(str), it)
- }
+ Tokens().also {
+ tokenizer.tokenize(sourceCodeOf(str), it)
+ }
private companion object {
const val Indent = " "
diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt
index 6e4453d7e1..f5d70c0767 100644
--- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt
+++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseParsingHelper.kt
@@ -60,7 +60,8 @@ abstract class BaseParsingHelper, T : RootNode
fun getVersion(version: String?): LanguageVersion {
val language = language
return if (version == null) language.defaultVersion
- else language.getVersion(version) ?: throw AssertionError("Unsupported version $version for language $language")
+ else language.getVersion(version)
+ ?: throw AssertionError("Unsupported version $version for language $language")
}
val language: Language
@@ -116,13 +117,17 @@ abstract class BaseParsingHelper, T : RootNode
* so.
*/
@JvmOverloads
- fun parse(sourceCode: String, version: String? = null, filename: String = FileAnalysisException.NO_FILE_NAME): T {
+ open fun parse(
+ sourceCode: String,
+ version: String? = null,
+ fileName: String = "src/a/test-file-name.${language.extensions[0]}"
+ ): T {
val lversion = if (version == null) defaultVersion else getVersion(version)
val handler = lversion.languageVersionHandler
val parser = handler.parser
- val source = DataSource.forString(sourceCode, filename)
+ val source = DataSource.forString(sourceCode, fileName)
val toString = DataSource.readToString(source, StandardCharsets.UTF_8) // this removed the BOM
- val task = Parser.ParserTask(lversion, filename, toString, SemanticErrorReporter.noop())
+ val task = Parser.ParserTask(lversion, fileName, toString, SemanticErrorReporter.noop())
task.properties.also {
handler.declareParserTaskProperties(it)
it.setProperty(Parser.ParserTask.COMMENT_MARKER, params.suppressMarker)
@@ -165,14 +170,14 @@ abstract class BaseParsingHelper, T : RootNode
*/
@JvmOverloads
open fun parseResource(resource: String, version: String? = null): T =
- parse(readResource(resource), version)
+ parse(readResource(resource), version, fileName = resource)
/**
* Fetches and [parse]s the [path].
*/
@JvmOverloads
open fun parseFile(path: Path, version: String? = null): T =
- parse(IOUtils.toString(Files.newBufferedReader(path)), version, filename = path.toAbsolutePath().toString())
+ parse(IOUtils.toString(Files.newBufferedReader(path)), version, fileName = path.toAbsolutePath().toString())
/**
* Fetches the source of the given [clazz].
@@ -220,7 +225,11 @@ abstract class BaseParsingHelper, T : RootNode
* found by the rule. The language version of the piece of code is determined by the [params].
*/
@JvmOverloads
- fun executeRule(rule: Rule, code: String, filename: String = "testfile.${language.extensions[0]}"): Report {
+ fun executeRule(
+ rule: Rule,
+ code: String,
+ fileName: String = "testfile.${language.extensions[0]}"
+ ): Report {
val config = PMDConfiguration().apply {
suppressMarker = params.suppressMarker
}
@@ -228,7 +237,7 @@ abstract class BaseParsingHelper, T : RootNode
val ctx = RuleContext()
val report = Report()
ctx.report = report
- ctx.sourceCodeFile = File(filename)
+ ctx.sourceCodeFile = File(fileName)
ctx.isIgnoreExceptions = false
val rules = RuleSet.forSingleRule(rule)
@@ -242,6 +251,4 @@ abstract class BaseParsingHelper, T : RootNode
fun executeRuleOnResource(rule: Rule, resourcePath: String): Report =
executeRule(rule, readResource(resourcePath))
-
-
}
diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseTreeDumpTest.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseTreeDumpTest.kt
index 2201b384a8..49af1e58ac 100644
--- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseTreeDumpTest.kt
+++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/lang/ast/test/BaseTreeDumpTest.kt
@@ -32,9 +32,13 @@ abstract class BaseTreeDumpTest(
*/
@JvmOverloads
fun doTest(fileBaseName: String, parser: BaseParsingHelper<*, *> = this.parser) {
- super.doTest(fileBaseName, "") { sourceText ->
+ super.doTest(fileBaseName, "") { fileData ->
buildString {
- printer.renderSubtree(parser.parse(sourceText), this)
+ val ast = parser.parse(
+ sourceCode = fileData.fileText,
+ fileName = fileData.fileName
+ )
+ printer.renderSubtree(ast, this)
}
}
}
diff --git a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/test/BaseTextComparisonTest.kt b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/test/BaseTextComparisonTest.kt
index b7a0cc9816..cb45c4ed41 100644
--- a/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/test/BaseTextComparisonTest.kt
+++ b/pmd-lang-test/src/main/kotlin/net/sourceforge/pmd/test/BaseTextComparisonTest.kt
@@ -27,6 +27,8 @@ abstract class BaseTextComparisonTest {
/** Extension that the unparsed source file is supposed to have. */
protected abstract val extensionIncludingDot: String
+ data class FileData(val fileName:String, val fileText:String)
+
/**
* Executes the test. The test files are looked up using the [parser].
* The reference test file must be named [fileBaseName] + [ExpectedExt].
@@ -37,7 +39,7 @@ abstract class BaseTextComparisonTest {
*/
internal fun doTest(fileBaseName: String,
expectedSuffix: String = "",
- transformTextContent: (String) -> String) {
+ transformTextContent: (FileData) -> String) {
val expectedFile = findTestFile(resourceLoader, "${resourcePrefix}/$fileBaseName$expectedSuffix$ExpectedExt").toFile()
val actual = transformTextContent(sourceText(fileBaseName))
@@ -56,7 +58,7 @@ abstract class BaseTextComparisonTest {
assertEquals(expected.normalize(), actual.normalize(), "File comparison failed, see the reference: $expectedFile")
}
- protected fun sourceText(fileBaseName: String): String {
+ protected fun sourceText(fileBaseName: String): FileData {
val sourceFile = findTestFile(resourceLoader, "${resourcePrefix}/$fileBaseName$extensionIncludingDot").toFile()
assert(sourceFile.isFile) {
@@ -64,7 +66,7 @@ abstract class BaseTextComparisonTest {
}
val sourceText = sourceFile.readText(Charsets.UTF_8).normalize()
- return sourceText
+ return FileData(fileName = sourceFile.toString(), fileText = sourceText)
}
protected open fun String.normalize() = replace(
diff --git a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java
index e36a3c0af7..6dff8fbf56 100644
--- a/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java
+++ b/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/SwiftLanguageModule.java
@@ -21,6 +21,6 @@ public class SwiftLanguageModule extends BaseLanguageModule {
*/
public SwiftLanguageModule() {
super(NAME, null, TERSE_NAME, "swift");
- addVersion("", new SwiftHandler(), true);
+ addDefaultVersion("", new SwiftHandler());
}
}
diff --git a/pmd-xml/src/test/java/net/sourceforge/pmd/lang/xml/rule/XmlXPathRuleTest.java b/pmd-xml/src/test/java/net/sourceforge/pmd/lang/xml/rule/XmlXPathRuleTest.java
new file mode 100644
index 0000000000..ef22aa88d8
--- /dev/null
+++ b/pmd-xml/src/test/java/net/sourceforge/pmd/lang/xml/rule/XmlXPathRuleTest.java
@@ -0,0 +1,39 @@
+/**
+ * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
+ */
+
+package net.sourceforge.pmd.lang.xml.rule;
+
+import static net.sourceforge.pmd.lang.ast.test.TestUtilsKt.assertSize;
+
+import org.junit.Test;
+
+import net.sourceforge.pmd.Report;
+import net.sourceforge.pmd.lang.LanguageRegistry;
+import net.sourceforge.pmd.lang.rule.XPathRule;
+import net.sourceforge.pmd.lang.rule.xpath.XPathVersion;
+import net.sourceforge.pmd.lang.xml.XmlLanguageModule;
+import net.sourceforge.pmd.lang.xml.XmlParsingHelper;
+
+public class XmlXPathRuleTest {
+
+ final XmlParsingHelper xml = XmlParsingHelper.XML;
+
+ private XPathRule makeXPath(String expression) {
+ XPathRule rule = new XPathRule(XPathVersion.XPATH_2_0, expression);
+ rule.setLanguage(LanguageRegistry.getLanguage(XmlLanguageModule.NAME));
+ rule.setMessage("XPath Rule Failed");
+ return rule;
+ }
+
+
+ @Test
+ public void testFileNameInXpath() {
+ Report report = xml.executeRule(makeXPath("//b[pmd:fileName() = 'Foo.xml']"),
+ "",
+ "src/Foo.xml");
+
+ assertSize(report, 1);
+ }
+
+}
diff --git a/pom.xml b/pom.xml
index 8a4ac7022f..83fa78759f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -76,7 +76,7 @@
- 2021-07-31T17:02:07Z
+ 2021-08-28T15:27:18Z
8
@@ -95,7 +95,7 @@
8.42
3.1.2
3.14.0
- 1.10.9
+ 1.10.11
3.2.0
4.8
@@ -105,7 +105,7 @@
-Xmx512m -Dfile.encoding=${project.build.sourceEncoding}
- 15
+ 16
6.37.0
${settings.localRepository}/net/java/dev/javacc/javacc/${javacc.version}/javacc-${javacc.version}.jar
@@ -412,15 +412,16 @@
+
net.sourceforge.pmd
pmd-core
- 6.37.0
+ 6.38.0
net.sourceforge.pmd
pmd-java
- 6.37.0
+ 6.38.0
@@ -1055,33 +1056,6 @@
-
-
- pmd-dogfood
-
- ${project.version}
-
-
-
-
- org.apache.maven.plugins
- maven-pmd-plugin
-
-
- net.sourceforge.pmd
- pmd-core
- ${pmd.dogfood.version}
-
-
- net.sourceforge.pmd
- pmd-java
- ${pmd.dogfood.version}
-
-
-
-
-
-