Merge branch '7.0.x' into pr/3486
This commit is contained in:
128 files changed
+1817
-3043
No files matched your search
+5
-5
@@ -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/<version>[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}.*<\/version>\( *<!-- pmd.dogfood.version -->\)/<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.
|
||||
|
||||
+9
-24
@@ -54,10 +54,6 @@
|
||||
<rule ref="category/java/bestpractices.xml/UnusedLocalVariable"/>
|
||||
<rule ref="category/java/bestpractices.xml/UnusedPrivateField"/>
|
||||
<rule ref="category/java/bestpractices.xml/UnusedPrivateMethod"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseAssertEqualsInsteadOfAssertTrue"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseAssertNullInsteadOfAssertTrue"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseAssertSameInsteadOfAssertTrue"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseAssertTrueInsteadOfAssertEquals"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseCollectionIsEmpty"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseStandardCharsets" />
|
||||
<rule ref="category/java/bestpractices.xml/UseTryWithResources"/>
|
||||
@@ -77,7 +73,6 @@
|
||||
<rule ref="category/java/codestyle.xml/CommentDefaultAccessModifier"/>
|
||||
<rule ref="category/java/codestyle.xml/ConfusingTernary"/>
|
||||
<rule ref="category/java/codestyle.xml/ControlStatementBraces"/>
|
||||
<rule ref="category/java/codestyle.xml/DefaultPackage"/>
|
||||
<rule ref="category/java/codestyle.xml/EmptyMethodInAbstractClassShouldBeAbstract"/>
|
||||
<rule ref="category/java/codestyle.xml/ExtendsObject"/>
|
||||
<rule ref="category/java/codestyle.xml/FieldDeclarationsShouldBeAtStartOfClass"/>
|
||||
@@ -153,17 +148,16 @@
|
||||
<rule ref="category/java/design.xml/NPathComplexity"/>
|
||||
<rule ref="category/java/design.xml/NcssCount"/>
|
||||
<!-- <rule ref="category/java/design.xml/SignatureDeclareThrowsException"/> -->
|
||||
<!-- <rule ref="category/java/design.xml/SimplifiedTernary"/> -->
|
||||
<!-- <rule ref="category/java/design.xml/SimplifyBooleanAssertion"/> -->
|
||||
<rule ref="category/java/design.xml/SimplifiedTernary"/>
|
||||
<rule ref="category/java/design.xml/SimplifyBooleanExpressions"/>
|
||||
<rule ref="category/java/design.xml/SimplifyBooleanReturns"/>
|
||||
<!-- <rule ref="category/java/design.xml/SimplifyConditional"/> -->
|
||||
<rule ref="category/java/design.xml/SimplifyConditional"/>
|
||||
<rule ref="category/java/design.xml/SingularField"/>
|
||||
<!-- <rule ref="category/java/design.xml/SwitchDensity"/> -->
|
||||
<rule ref="category/java/design.xml/SwitchDensity"/>
|
||||
<!-- <rule ref="category/java/design.xml/TooManyFields"/> -->
|
||||
<!-- <rule ref="category/java/design.xml/TooManyMethods"/> -->
|
||||
<!-- <rule ref="category/java/design.xml/UseObjectForClearerAPI"/> -->
|
||||
<!-- <rule ref="category/java/design.xml/UseUtilityClass"/> -->
|
||||
<rule ref="category/java/design.xml/UseUtilityClass"/>
|
||||
<!-- <rule ref="category/java/design.xml/UselessOverridingMethod"/> -->
|
||||
|
||||
<!-- documentation.xml -->
|
||||
@@ -210,7 +204,6 @@
|
||||
<!-- <rule ref="category/java/errorprone.xml/DataflowAnomalyAnalysis"/> -->
|
||||
<!-- <rule ref="category/java/errorprone.xml/DetachedTestCase"/> -->
|
||||
<!-- <rule ref="category/java/errorprone.xml/DoNotCallGarbageCollectionExplicitly"/> -->
|
||||
<!-- <rule ref="category/java/errorprone.xml/DoNotCallSystemExit"/> -->
|
||||
<!-- <rule ref="category/java/errorprone.xml/DoNotExtendJavaLangThrowable"/> -->
|
||||
<!-- <rule ref="category/java/errorprone.xml/DoNotHardCodeSDCard"/> -->
|
||||
<!-- <rule ref="category/java/errorprone.xml/DoNotThrowExceptionInFinally"/> -->
|
||||
@@ -268,9 +261,9 @@
|
||||
<!-- <rule ref="category/java/errorprone.xml/UnnecessaryConversionTemporary"/> -->
|
||||
<!-- <rule ref="category/java/errorprone.xml/UnusedNullCheckInEquals"/> -->
|
||||
<!-- <rule ref="category/java/errorprone.xml/UseCorrectExceptionLogging"/> -->
|
||||
<!-- <rule ref="category/java/errorprone.xml/UseEqualsToCompareStrings"/> -->
|
||||
<!-- <rule ref="category/java/errorprone.xml/UseLocaleWithCaseConversions"/> -->
|
||||
<!-- <rule ref="category/java/errorprone.xml/UseProperClassLoader"/> -->
|
||||
<rule ref="category/java/errorprone.xml/UseEqualsToCompareStrings"/>
|
||||
<rule ref="category/java/errorprone.xml/UseLocaleWithCaseConversions"/>
|
||||
<rule ref="category/java/errorprone.xml/UseProperClassLoader"/>
|
||||
<rule ref="category/java/errorprone.xml/UselessOperationOnImmutable"/>
|
||||
|
||||
<!-- multithreading.xml -->
|
||||
@@ -281,8 +274,8 @@
|
||||
<rule ref="category/java/multithreading.xml/DoNotUseThreads"/>
|
||||
<rule ref="category/java/multithreading.xml/DontCallThreadRun"/>
|
||||
<rule ref="category/java/multithreading.xml/DoubleCheckedLocking"/>
|
||||
<!-- <rule ref="category/java/multithreading.xml/NonThreadSafeSingleton"/> -->
|
||||
<!-- <rule ref="category/java/multithreading.xml/UnsynchronizedStaticFormatter"/> -->
|
||||
<rule ref="category/java/multithreading.xml/NonThreadSafeSingleton"/>
|
||||
<rule ref="category/java/multithreading.xml/UnsynchronizedStaticFormatter"/>
|
||||
<rule ref="category/java/multithreading.xml/UseConcurrentHashMap"/>
|
||||
<rule ref="category/java/multithreading.xml/UseNotifyAllInsteadOfNotify"/>
|
||||
|
||||
@@ -294,25 +287,17 @@
|
||||
<rule ref="category/java/performance.xml/AvoidCalendarDateCreation"/>
|
||||
<rule ref="category/java/performance.xml/AvoidFileStream"/>
|
||||
<rule ref="category/java/performance.xml/AvoidInstantiatingObjectsInLoops"/>
|
||||
<rule ref="category/java/performance.xml/AvoidUsingShortType"/>
|
||||
<rule ref="category/java/performance.xml/BigIntegerInstantiation"/>
|
||||
<!-- <rule ref="category/java/performance.xml/BooleanInstantiation"/> -->
|
||||
<rule ref="category/java/performance.xml/ByteInstantiation"/>
|
||||
<rule ref="category/java/performance.xml/ConsecutiveAppendsShouldReuse"/>
|
||||
<rule ref="category/java/performance.xml/ConsecutiveLiteralAppends"/>
|
||||
<rule ref="category/java/performance.xml/InefficientEmptyStringCheck"/>
|
||||
<rule ref="category/java/performance.xml/InefficientStringBuffering"/>
|
||||
<rule ref="category/java/performance.xml/InsufficientStringBufferDeclaration"/>
|
||||
<rule ref="category/java/performance.xml/IntegerInstantiation"/>
|
||||
<rule ref="category/java/performance.xml/LongInstantiation"/>
|
||||
<rule ref="category/java/performance.xml/OptimizableToArrayCall"/>
|
||||
<rule ref="category/java/performance.xml/RedundantFieldInitializer"/>
|
||||
<rule ref="category/java/performance.xml/ShortInstantiation"/>
|
||||
<rule ref="category/java/performance.xml/SimplifyStartsWith"/>
|
||||
<rule ref="category/java/performance.xml/StringInstantiation"/>
|
||||
<rule ref="category/java/performance.xml/StringToString"/>
|
||||
<rule ref="category/java/performance.xml/TooFewBranchesForASwitchStatement"/>
|
||||
<rule ref="category/java/performance.xml/UnnecessaryWrapperObjectCreation"/>
|
||||
<rule ref="category/java/performance.xml/UseArrayListInsteadOfVector"/>
|
||||
<rule ref="category/java/performance.xml/UseArraysAsList"/>
|
||||
<rule ref="category/java/performance.xml/UseIOStreamsWithApacheCommonsFileItem"/>
|
||||
|
||||
+1
-1
@@ -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
|
||||
+1
-1
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
<p>This function is available since PMD 6.38.0.</p>"
|
||||
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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -190,6 +209,7 @@ The following previously deprecated rules have been finally removed:
|
||||
* [#2880](https://github.com/pmd/pmd/issues/2880): \[java] CompareObjectsWithEquals - false negative with type res
|
||||
* [#2894](https://github.com/pmd/pmd/issues/2894): \[java] Improve MissingBreakInSwitch
|
||||
* [#3071](https://github.com/pmd/pmd/issues/3071): \[java] BrokenNullCheck FP with PMD 6.30.0
|
||||
* [#3173](https://github.com/pmd/pmd/issues/3173): \[java] UseProperClassLoader false positive
|
||||
* [#3351](https://github.com/pmd/pmd/issues/3351): \[java] ConstructorCallsOverridableMethod ignores abstract methods
|
||||
* java-multithreading
|
||||
* [#2537](https://github.com/pmd/pmd/issues/2537): \[java] DontCallThreadRun can't detect the case that call run() in `this.run()`
|
||||
@@ -240,7 +260,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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 `<antlr4.visitor>true</antlr4.visitor>` 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.
|
||||
+5
-6
@@ -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)*
|
||||
@@ -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!**
|
||||
@@ -428,7 +428,7 @@ author: Tom Copeland <tom@infoether.org>
|
||||
* 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
|
||||
|
||||
@@ -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 %}
|
||||
|
||||
@@ -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.
|
||||
|
||||
+45
-13
@@ -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<String, String> varToTypeMapping = new HashMap<>();
|
||||
private final ListMultimap<String, String> typeToDMLOperationMapping = ArrayListMultimap.create();
|
||||
private final Map<String, String> checkedTypeToDMLOperationViaESAPI = new HashMap<>();
|
||||
private final Map<String, ASTMethod> classMethods = new WeakHashMap<>();
|
||||
private Map<String, String> varToTypeMapping;
|
||||
private ListMultimap<String, String> typeToDMLOperationMapping;
|
||||
private Map<String, String> checkedTypeToDMLOperationViaESAPI;
|
||||
private Map<String, ASTMethod> 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()) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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<ASTBooleanExpression> 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));
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ public class ApexTreeDumpTest extends BaseTreeDumpTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void safeNavigationOperator() throws Exception {
|
||||
public void safeNavigationOperator() {
|
||||
doTest("SafeNavigationOperator");
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
File renamed without changes.
+32
@@ -1049,6 +1049,38 @@ public class Foo {
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>No CRUD check inside for-each loop</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
void bar() {
|
||||
Id[] accIds = new List<Id>();
|
||||
for (Id accId : accIds) {
|
||||
Account acc = [SELECT Id FROM Account WHERE Id = :accId];
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Proper CRUD check inside for-each loop</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
void bar() {
|
||||
Id[] accIds = new List<Id>();
|
||||
if (Account.sObjectType.getDescribe().isAccessible()) {
|
||||
for (Id accId : accIds) {
|
||||
Account a = [SELECT Id FROM Account WHERE Id = :accId];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Proper CRUD check in SOQL for-loop with security enforced</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
|
||||
@@ -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.
|
||||
|
||||
+9
-3
@@ -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;
|
||||
|
||||
@@ -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<ExtensionFunctionDefinition> set = CollectionUtil.setOf(first, defs);
|
||||
return () -> set;
|
||||
Set<ExtensionFunctionDefinition> set = new HashSet<>(CollectionUtil.setOf(first, defs));
|
||||
set.addAll(DefaultXPathFunctions.getDefaultFunctions());
|
||||
|
||||
return () -> Collections.unmodifiableSet(set);
|
||||
}
|
||||
}
|
||||
+26
@@ -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<ExtensionFunctionDefinition> getDefaultFunctions() {
|
||||
return CollectionUtil.setOf(FileNameXPathFunction.INSTANCE);
|
||||
}
|
||||
}
|
||||
+62
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+18
-2
@@ -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<Expression> 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);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ This ruleset contains links to rules that are new in PMD v3.4
|
||||
<rule ref="rulesets/java/design.xml/UncommentedEmptyMethod"/>
|
||||
<rule ref="rulesets/java/design.xml/UncommentedEmptyConstructor"/>
|
||||
|
||||
<rule ref="rulesets/java/controversial.xml/DefaultPackage"/>
|
||||
<!-- <rule ref="rulesets/java/controversial.xml/DefaultPackage"/>-->
|
||||
|
||||
<!-- Removed with 7.0.0 <rule ref="rulesets/java/naming.xml/MisleadingVariableName"/> -->
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ This ruleset contains links to rules that are new in PMD v3.5
|
||||
<rule ref="rulesets/java/strings.xml/ConsecutiveLiteralAppends"/>
|
||||
<rule ref="rulesets/java/strings.xml/UseIndexOfChar"/>
|
||||
|
||||
<rule ref="rulesets/java/migrating.xml/IntegerInstantiation"/>
|
||||
<!-- <rule ref="rulesets/java/migrating.xml/IntegerInstantiation"/>-->
|
||||
|
||||
<rule ref="rulesets/java/junit.xml/UseAssertNullInsteadOfAssertTrue"/>
|
||||
<!-- <rule ref="rulesets/java/junit.xml/UseAssertNullInsteadOfAssertTrue"/>-->
|
||||
|
||||
<rule ref="rulesets/java/design.xml/AvoidConstantsInterface"/>
|
||||
|
||||
|
||||
Loaded 30 of 128 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user