Merge branch '7.0.x' into pr/3474

This commit is contained in:
Clément Fournier committed 2021-09-18 14:10:20 +02:00
commit 1730ef91b0
131 files changed
+1714 -2974

No files matched your search

+5 -5
View File
@@ -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.
+14 -29
View File
@@ -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"/>
@@ -130,7 +125,7 @@
<rule ref="category/java/design.xml/AvoidThrowingNullPointerException"/>
<!-- <rule ref="category/java/design.xml/AvoidThrowingRawExceptionTypes"/> -->
<rule ref="category/java/design.xml/AvoidUncheckedExceptionsInSignatures"/>
<!-- <rule ref="category/java/design.xml/ClassWithOnlyPrivateConstructorsShouldBeFinal"/> -->
<rule ref="category/java/design.xml/ClassWithOnlyPrivateConstructorsShouldBeFinal"/>
<rule ref="category/java/design.xml/CognitiveComplexity" />
<rule ref="category/java/design.xml/CollapsibleIfStatements"/>
<!-- <rule ref="category/java/design.xml/CouplingBetweenObjects"/> -->
@@ -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"/> -->
@@ -228,31 +221,31 @@
<rule ref="category/java/errorprone.xml/EmptyTryBlock"/>
<rule ref="category/java/errorprone.xml/EmptyWhileStmt"/>
<rule ref="category/java/errorprone.xml/EqualsNull"/>
<!-- <rule ref="category/java/errorprone.xml/FinalizeDoesNotCallSuperFinalize"/> -->
<!-- <rule ref="category/java/errorprone.xml/FinalizeOnlyCallsSuperFinalize"/> -->
<!-- <rule ref="category/java/errorprone.xml/FinalizeOverloaded"/> -->
<!-- <rule ref="category/java/errorprone.xml/FinalizeShouldBeProtected"/> -->
<rule ref="category/java/errorprone.xml/FinalizeDoesNotCallSuperFinalize"/>
<rule ref="category/java/errorprone.xml/FinalizeOnlyCallsSuperFinalize"/>
<rule ref="category/java/errorprone.xml/FinalizeOverloaded"/>
<rule ref="category/java/errorprone.xml/FinalizeShouldBeProtected"/>
<rule ref="category/java/errorprone.xml/IdempotentOperations"/>
<rule ref="category/java/errorprone.xml/ImplicitSwitchFallThrough"/>
<!-- <rule ref="category/java/errorprone.xml/InstantiationToGetClass"/> -->
<rule ref="category/java/errorprone.xml/InstantiationToGetClass"/>
<!-- <rule ref="category/java/errorprone.xml/InvalidLogMessageFormat"/> -->
<rule ref="category/java/errorprone.xml/JUnitSpelling"/>
<rule ref="category/java/errorprone.xml/JUnitStaticSuite"/>
<!-- <rule ref="category/java/errorprone.xml/JumbledIncrementer"/> -->
<!-- <rule ref="category/java/errorprone.xml/MethodWithSameNameAsEnclosingClass"/> -->
<!-- <rule ref="category/java/errorprone.xml/MisplacedNullCheck"/> -->
<!-- <rule ref="category/java/errorprone.xml/MissingSerialVersionUID"/> -->
<rule ref="category/java/errorprone.xml/MissingSerialVersionUID"/>
<!-- <rule ref="category/java/errorprone.xml/MissingStaticMethodInNonInstantiatableClass"/> -->
<!-- <rule ref="category/java/errorprone.xml/MoreThanOneLogger"/> -->
<!-- <rule ref="category/java/errorprone.xml/NonCaseLabelInSwitchStatement"/> -->
<!-- <rule ref="category/java/errorprone.xml/NonStaticInitializer"/> -->
<rule ref="category/java/errorprone.xml/NonStaticInitializer"/>
<!-- <rule ref="category/java/errorprone.xml/NullAssignment"/> -->
<!-- <rule ref="category/java/errorprone.xml/OverrideBothEqualsAndHashcode"/> -->
<!-- <rule ref="category/java/errorprone.xml/ProperCloneImplementation"/> -->
<!-- <rule ref="category/java/errorprone.xml/ProperLogger"/> -->
<!-- <rule ref="category/java/errorprone.xml/ReturnEmptyArrayRatherThanNull"/> -->
<!-- <rule ref="category/java/errorprone.xml/ReturnEmptyCollectionRatherThanNull"/> -->
<!-- <rule ref="category/java/errorprone.xml/ReturnFromFinallyBlock"/> -->
<rule ref="category/java/errorprone.xml/ReturnFromFinallyBlock"/>
<!-- <rule ref="category/java/errorprone.xml/SimpleDateFormatNeedsLocale"/> -->
<!-- <rule ref="category/java/errorprone.xml/SingleMethodSingleton"/> -->
<!-- <rule ref="category/java/errorprone.xml/SingletonClassReturningNewInstance"/> -->
@@ -268,7 +261,7 @@
<!-- <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/UseEqualsToCompareStrings"/>
<!-- <rule ref="category/java/errorprone.xml/UseLocaleWithCaseConversions"/> -->
<!-- <rule ref="category/java/errorprone.xml/UseProperClassLoader"/> -->
<rule ref="category/java/errorprone.xml/UselessOperationOnImmutable"/>
@@ -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
View File
@@ -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
View File
@@ -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
+8 -2
View File
@@ -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
+16
View File
@@ -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 `&lt;b&gt;` tags in files called `Foo.xml`."
- name: "Java"
ns: "pmd-java"
funs:
+39 -17
View File
@@ -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)
+18 -14
View File
@@ -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 its 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.
@@ -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 shouldnt be there!**
+1 -1
View File
@@ -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
+4 -4
View File
@@ -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 %}
+32
View File
@@ -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.
@@ -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);
}
}
@@ -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.
@@ -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);
}
}
@@ -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);
}
}
@@ -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);
}
};
}
}
@@ -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 131 files, more files were not shown because too many files have changed in this diff. Show more