diff --git a/.ci/README.md b/.ci/README.md index 719d931872..bbfa516d5c 100644 --- a/.ci/README.md +++ b/.ci/README.md @@ -7,7 +7,8 @@ It uses the common scripts from [build-tools](https://github.com/pmd/build-tools This files contains the following environment variables: -* DANGER_GITHUB_API_TOKEN: Token for danger to add comments to PRs as +* DANGER_GITHUB_API_TOKEN: Token for danger to add comments to PRs as . + The token needs the scope "public_repo". * PMD_CI_CHUNK_TOKEN: Token for uploading reports to chunk.io The file is encrypted, so that the tokens are not automatically disabled when github detects them diff --git a/.ci/files/public-env.gpg b/.ci/files/public-env.gpg index 4504a0ef26..93404c7646 100644 --- a/.ci/files/public-env.gpg +++ b/.ci/files/public-env.gpg @@ -1,13 +1,14 @@ -----BEGIN PGP MESSAGE----- -jA0ECQMCkmcn6+I5p8D/0sDSAW6N6nliZko1kP0nXZ7303ywGHypHRzLyIhaiOKl -9afpeACRJ995FY66KL1NZdaeoujK3gFFl0QtTFrcde2KZTyoqrS1Nfro5RGkXYI8 -AyX/kaEd54bVlsiUbHWBjiAUvK83wJiIhClKhD13mpKtsVr5Ep+Rb6j/zeoIkJ8k -sKkS97qZjiXQVGwZzb42tO8W/K2fsahwBUfYU+pGzkqE9jPQPkVDBvWWZTczrj6p -PVWyuREFa0Tdpc2py7+/bS/ls+1JUer6GxYsNl+KiZvCUyBDVL67M42tNzU/cAcA -fdNVkzIB5TCgmUFlIrH43utl/f9O2bXC09NzK+xr3VPSp4BvO8fVA1DfDGswnMgz -OctjRQXeOJZys5Z+Ls01C37ropAC8JTzT+UHM/v0VoQmoKhBx6+ehHkqzwDeUmbV -QJ4HMFsWGyTPy64SCZbS4aOWaQx0q0NFFU7Kmdu4RQNq0u6aODZ99lEvdCODGe70 -vl5qVkzp2q8b6ayY1DUVo4kIvhu3KqFllETnVnHq4J8TCJLw -=goqq +jA0ECQMC6NJFOgCtLK790sDsAV7zf22dX5W7Ki3LdPBesQvoN+fU5xjNcu9ytrOQ +pNDQybzmGkBU7gJM5sasTEv2OKp7h+nt8xSfaE8u0i4G0+yLGZKxbCrZoHnoBiaW +udpjvvxyKdEV8wn1DPsh/W9ARmxdJezpreUwmwExamYiVEXsWOr2DWST+DPVX+4I +5vAxi/YqO1/Pn+s/wIOKM/57otuVxwzwyUFxItJF4GV3NeCKt1cDQHRT1OSn2Mlw +1LY8oUJgjKVCzI9F7xSlHYRYtvUK2icc7lvwrUliXIlcVetUB6Swe5AJmtmQ63y0 +EU52Uh7VPYjj929QgpoVpJHGTJl/Omyk63nb1EOrDWEVUMzg4fDsbAsmzvPyD/FR +R6S9OeJUCsLMXlu7MRHCQi0vDk3li25pVqJmFm9Ahk8tkY/yzgQLoWmVEOhl8xDY +oEQh0XNy9TxvzRzYlutYdU7K4ACohNsJN/MpKkRVzA3aMIBrNjVGa0dF8kd+7grg +fJ+MW8skcpIHDegDcxVAs+O4r9VO3UDAcx3E/kgdLAKSOV0sRt4ZbJZaML7sKkSV +muTtIhHzGwB41qKichY= +=fgy5 -----END PGP MESSAGE----- diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d38e793524..e007d1e2f1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,6 +11,7 @@ on: schedule: # build it monthly: At 04:00 on day-of-month 1. - cron: '0 4 1 * *' + workflow_dispatch: jobs: build: @@ -28,12 +29,13 @@ jobs: with: path: | ~/.m2/repository + ~/.gradle/caches ~/.cache ~/work/pmd/target/repositories vendor/bundle - key: ${{ runner.os }}-${{ hashFiles('**/pom.xml') }} + key: v1-${{ runner.os }}-${{ hashFiles('**/pom.xml') }} restore-keys: | - ${{ runner.os }}- + v1-${{ runner.os }}- - name: Set up Ruby 2.7 uses: actions/setup-ruby@v1 with: @@ -43,7 +45,7 @@ jobs: run: | echo "LANG=en_US.UTF-8" >> $GITHUB_ENV echo "MAVEN_OPTS=-Dmaven.wagon.httpconnectionManager.ttlSeconds=180 -Dmaven.wagon.http.retryHandler.count=3 -DautoReleaseAfterClose=true -DstagingProgressTimeoutMinutes=30" >> $GITHUB_ENV - echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/11/scripts" >> $GITHUB_ENV + echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/12/scripts" >> $GITHUB_ENV - name: Check Environment shell: bash run: | diff --git a/.github/workflows/git-repo-sync.yml b/.github/workflows/git-repo-sync.yml index 510f048c44..4476dcae95 100644 --- a/.github/workflows/git-repo-sync.yml +++ b/.github/workflows/git-repo-sync.yml @@ -21,7 +21,7 @@ jobs: shell: bash run: | echo "LANG=en_US.UTF-8" >> $GITHUB_ENV - echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/11/scripts" >> $GITHUB_ENV + echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/12/scripts" >> $GITHUB_ENV - name: Sync run: .ci/git-repo-sync.sh shell: bash diff --git a/.github/workflows/troubleshooting.yml b/.github/workflows/troubleshooting.yml index d5a8965dad..23c5d3fc33 100644 --- a/.github/workflows/troubleshooting.yml +++ b/.github/workflows/troubleshooting.yml @@ -16,12 +16,14 @@ jobs: - uses: actions/cache@v2 with: path: | - ~/.m2/repository - ~/.cache - vendor/bundle - key: push-${{ runner.os }}-${{ hashFiles('**/pom.xml') }} + ~/.m2/repository + ~/.gradle/caches + ~/.cache + ~/work/pmd/target/repositories + vendor/bundle + key: v1-${{ runner.os }}-${{ hashFiles('**/pom.xml') }} restore-keys: | - push-${{ runner.os }}- + v1-${{ runner.os }}- - name: Set up Ruby 2.7 uses: actions/setup-ruby@v1 with: @@ -31,7 +33,7 @@ jobs: run: | echo "LANG=en_US.UTF-8" >> $GITHUB_ENV echo "MAVEN_OPTS=-Dmaven.wagon.httpconnectionManager.ttlSeconds=180 -Dmaven.wagon.http.retryHandler.count=3 -DstagingProgressTimeoutMinutes=30" >> $GITHUB_ENV - echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/11/scripts" >> $GITHUB_ENV + echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/12/scripts" >> $GITHUB_ENV - name: Check Environment shell: bash run: | diff --git a/BUILDING.md b/BUILDING.md index 8654ec8953..6579e3ca2e 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -16,7 +16,8 @@ This will create the zip files in the directory `pmd-dist/target`: That's all ! -**Note:** While Java 11 is required for building, running PMD only requires Java 7 (or Java 8 for Apex and the Designer). +**Note:** While Java 11 is required for building, running PMD only requires Java 7 +(or Java 8 for Apex, JavaScript, Scala, Visualforce, and the Designer). **Note:** With PMD 6.24.0, we are creating [Reproducible Builds](https://reproducible-builds.org/). Since we use [Maven](https://maven.apache.org/guides/mini/guide-reproducible-builds.html) for building, the following diff --git a/Gemfile.lock b/Gemfile.lock index 3d17e8b730..fa8938b390 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -39,14 +39,14 @@ GEM kramdown (1.17.0) liquid (5.0.1) logger-colors (1.0.0) - mini_portile2 (2.5.0) + mini_portile2 (2.5.1) multipart-post (2.1.1) nap (1.1.0) no_proxy_fix (0.1.2) - nokogiri (1.11.3) + nokogiri (1.11.5) mini_portile2 (~> 2.5.0) racc (~> 1.4) - octokit (4.20.0) + octokit (4.21.0) faraday (>= 0.9) sawyer (~> 0.8.0, >= 0.5.3) open4 (1.3.4) @@ -68,7 +68,7 @@ GEM sawyer (0.8.2) addressable (>= 2.3.5) faraday (> 0.8, < 2.0) - slop (4.8.2) + slop (4.9.0) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) tzinfo (2.0.4) diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index 4b36ce2dfd..36eb9740c2 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,7 +1,7 @@ GEM remote: https://rubygems.org/ specs: - activesupport (6.0.3.6) + activesupport (6.0.3.7) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 0.7, < 2) minitest (~> 5.1) @@ -22,15 +22,19 @@ GEM em-websocket (0.5.2) eventmachine (>= 0.12.9) http_parser.rb (~> 0.6.0) - ethon (0.12.0) - ffi (>= 1.3.0) + ethon (0.14.0) + ffi (>= 1.15.0) eventmachine (1.2.7) - execjs (2.7.0) - faraday (1.3.0) + execjs (2.8.1) + faraday (1.4.1) + faraday-excon (~> 1.1) faraday-net_http (~> 1.0) + faraday-net_http_persistent (~> 1.1) multipart-post (>= 1.2, < 3) - ruby2_keywords + ruby2_keywords (>= 0.0.4) + faraday-excon (1.1.0) faraday-net_http (1.0.1) + faraday-net_http_persistent (1.1.0) ffi (1.15.0) forwardable-extended (2.6.0) gemoji (3.0.1) @@ -205,27 +209,27 @@ GEM rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) mercenary (0.3.6) - mini_portile2 (2.5.0) + mini_portile2 (2.5.1) minima (2.5.1) jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) minitest (5.14.4) multipart-post (2.1.1) - nokogiri (1.11.2) + nokogiri (1.11.5) mini_portile2 (~> 2.5.0) racc (~> 1.4) - octokit (4.20.0) + octokit (4.21.0) faraday (>= 0.9) sawyer (~> 0.8.0, >= 0.5.3) pathutil (0.16.2) forwardable-extended (~> 2.6) public_suffix (4.0.6) racc (1.5.2) - rb-fsevent (0.10.4) + rb-fsevent (0.11.0) rb-inotify (0.10.1) ffi (~> 1.0) - rexml (3.2.4) + rexml (3.2.5) rouge (3.26.0) ruby-enum (0.9.0) i18n diff --git a/docs/pages/pmd/devdocs/building.md b/docs/pages/pmd/devdocs/building.md index d9a7bcbc11..97196f2179 100644 --- a/docs/pages/pmd/devdocs/building.md +++ b/docs/pages/pmd/devdocs/building.md @@ -12,7 +12,8 @@ author: Tom Copeland, Xavier Le Vourch * JDK 11 or higher -{% include note.html content="While Java 11 is required for building, running PMD only requires Java 7 (or Java 8 for Apex, Scala, Visualforce, and the Designer)." %} +{% include note.html content="While Java 11 is required for building, running PMD only requires Java 7 +(or Java 8 for Apex, JavaScript, Scala, Visualforce, and the Designer)." %} You’ll need to either check out the source code or download the latest source release. Assuming you’ve got the latest source release, unzip it to a directory: diff --git a/docs/pages/pmd/userdocs/cli_reference.md b/docs/pages/pmd/userdocs/cli_reference.md index 2e6350ebc8..541f49eb25 100644 --- a/docs/pages/pmd/userdocs/cli_reference.md +++ b/docs/pages/pmd/userdocs/cli_reference.md @@ -111,7 +111,7 @@ The tool comes with a rather extensive help text, simply running with `-help`! %} {% include custom/cli_option_row.html options="-reportfile,-r" option_arg="path" - description="Path to a file in which the report output will be sent. By default the report is printed on standard output." + description="Path to a file to which report output is written. The file is created if it does not exist. If this option is not specified, the report is rendered to standard output." %} {% include custom/cli_option_row.html options="-shortnames" description="Prints shortened filenames in the report." diff --git a/docs/pages/pmd/userdocs/installation.md b/docs/pages/pmd/userdocs/installation.md index 7339d1b986..264b3dbdc0 100644 --- a/docs/pages/pmd/userdocs/installation.md +++ b/docs/pages/pmd/userdocs/installation.md @@ -11,7 +11,13 @@ sidebar: pmd_sidebar ### Requirements -* [Java JRE](http://www.oracle.com/technetwork/java/javase/downloads/index.html) 1.7 or higher +* [Java JRE](http://www.oracle.com/technetwork/java/javase/downloads/index.html), + OpenJDK from [Azul](https://www.azul.com/downloads/zulu-community/) + or [AdoptOpenJDK](https://adoptopenjdk.net/) 1.7 or higher. + + **Note:** For analyzing Apex, JavaScript, Scala or VisualForce or running the [Designer](pmd_userdocs_extending_designer_reference.html) + at least Java 8 is required. + * A zip archiver, e.g.: * For Windows: [Winzip](http://winzip.com) or the free [7-zip](http://www.7-zip.org/) diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index 3ffcb66921..7e967c8806 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -14,14 +14,99 @@ This is a {{ site.pmd.release_type }} release. ### New and noteworthy +#### Javascript module now requires at least Java 8 + +The latest version of [Rhino](https://github.com/mozilla/rhino), the implementation of JavaScript we use +for parsing JavaScript code, requires at least Java 8. Therefore we decided to upgrade the pmd-javascript +module to Java 8 as well. This means that from now on, a Java 8 or later runtime is required in order +to analyze JavaScript code. Note that PMD core still only requires Java 7. + +#### New rules + +* The new Java rule {% rule "java/bestpractices/JUnit5TestShouldBePackagePrivate" %} + enforces the convention that JUnit 5 tests should have minimal visibility. + You can try out this rule like so: +```xml + +``` + +#### Modified rules + +* The Java rule {% rule "java/errorprone/CompareObjectsWithEquals" %} has now a new property + `typesThatCompareByReference`. With that property, you can configure types, that should be whitelisted + for comparison by reference. By default, `java.lang.Enum` and `java.lang.Class` are allowed, but + you could add custom types here. + Additionally comparisons against constants are allowed now. This makes the rule less noisy when two constants + are compared. Constants are identified by looking for an all-caps identifier. + +#### Deprecated rules + +* The java rule {% rule "java/codestyle/DefaultPackage" %} has been deprecated in favor of + {% rule "java/codestyle/CommentDefaultAccessModifier" %}. + + The rule "DefaultPackage" assumes that any usage of package-access is accidental, + and by doing so, prohibits using a really fundamental and useful feature of the language. + + To satisfy the rule, you have to make the member public even if it doesn't need to, or make it protected, + which muddies your intent even more if you don't intend the class to be extended, and may be at odds with + other rules like {% rule "java/codestyle/AvoidProtectedFieldInFinalClass" %}. + + The rule {% rule "java/codestyle/CommentDefaultAccessModifier" %} should be used instead. + It flags the same thing, but has an escape hatch. + +* The Java rule {% rule "java/errorprone/CloneThrowsCloneNotSupportedException" %} has been deprecated without + replacement. + + The rule has no real value as `CloneNotSupportedException` is a + checked exception and therefore you need to deal with it while implementing the `clone()` method. You either + need to declare the exception or catch it. If you catch it, then subclasses can't throw it themselves explicitly. + However, `Object.clone()` will still throw this exception if the `Cloneable` interface is not implemented. + + Note, this rule has also been removed from the Quickstart Ruleset (`rulesets/java/quickstart.xml`). + ### Fixed Issues +* apex + * [#3183](https://github.com/pmd/pmd/issues/3183): \[apex] ApexUnitTestMethodShouldHaveIsTestAnnotation false positive with helper method + * [#3243](https://github.com/pmd/pmd/pull/3243): \[apex] Correct findBoundary when traversing AST +* core + * [#2639](https://github.com/pmd/pmd/issues/2639): \[core] PMD CLI output file is not created if directory or directories in path don't exist * doc * [#3230](https://github.com/pmd/pmd/issues/3230): \[doc] Remove "Edit me" button for language index pages +* dist + * [#2466](https://github.com/pmd/pmd/issues/2466): \[dist] Distribution archive doesn't include all batch scripts +* java + * [#3269](https://github.com/pmd/pmd/pull/3269): \[java] Fix NPE in MethodTypeResolution +* java-bestpractices + * [#1175](https://github.com/pmd/pmd/issues/1175): \[java] UnusedPrivateMethod FP with Junit 5 @MethodSource + * [#2219](https://github.com/pmd/pmd/issues/2219): \[java] Document Reasons to Avoid Reassigning Parameters + * [#2737](https://github.com/pmd/pmd/issues/2737): \[java] Fix misleading rule message on rule SwitchStmtsShouldHaveDefault with non-exhaustive enum switch + * [#3236](https://github.com/pmd/pmd/issues/3236): \[java] LiteralsFirstInComparisons should consider constant fields (cont'd) + * [#3254](https://github.com/pmd/pmd/issues/3254): \[java] AvoidReassigningParameters reports violations on wrong line numbers +* java-codestyle + * [#2655](https://github.com/pmd/pmd/issues/2655): \[java] UnnecessaryImport false positive for on-demand imports + * [#3206](https://github.com/pmd/pmd/issues/3206): \[java] Deprecate rule DefaultPackage + * [#3262](https://github.com/pmd/pmd/pull/3262): \[java] FieldDeclarationsShouldBeAtStartOfClass: false negative with anon classes + * [#3265](https://github.com/pmd/pmd/pull/3265): \[java] MethodArgumentCouldBeFinal: false negatives with interfaces and inner classes + * [#3266](https://github.com/pmd/pmd/pull/3266): \[java] LocalVariableCouldBeFinal: false negatives with interfaces, anon classes + * [#3274](https://github.com/pmd/pmd/pull/3274): \[java] OnlyOneReturn: false negative with anonymous class + * [#3275](https://github.com/pmd/pmd/pull/3275): \[java] UnnecessaryLocalBeforeReturn: false negatives with lambda and anon class +* java-design + * [#2780](https://github.com/pmd/pmd/issues/2780): \[java] DataClass example from documentation results in false-negative +* java-errorprone + * [#3110](https://github.com/pmd/pmd/issues/3110): \[java] Enhance CompareObjectsWithEquals with list of exceptions + * [#3112](https://github.com/pmd/pmd/issues/3112): \[java] Deprecate rule CloneThrowsCloneNotSupportedException + * [#3205](https://github.com/pmd/pmd/issues/3205): \[java] Make CompareObjectWithEquals allow comparing against constants + * [#3248](https://github.com/pmd/pmd/issues/3248): \[java] Documentation is wrong for SingletonClassReturningNewInstance rule + * [#3249](https://github.com/pmd/pmd/pull/3249): \[java] AvoidFieldNameMatchingTypeName: False negative with interfaces + * [#3268](https://github.com/pmd/pmd/pull/3268): \[java] ConstructorCallsOverridableMethod: IndexOutOfBoundsException with annotations +* javascript + * [#699](https://github.com/pmd/pmd/issues/699): \[javascript] Update Rhino library to 1.7.13 + * [#2081](https://github.com/pmd/pmd/issues/2081): \[javascript] Failing with OutOfMemoryError parsing a Javascript file ### API Changes ### External Contributions +* [#3272](https://github.com/pmd/pmd/pull/3272): \[apex] correction for ApexUnitTestMethodShouldHaveIsTestAnnotation false positives - [William Brockhus](https://github.com/YodaDaCoda) {% endtocmaker %} - diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierNode.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierNode.java index 59ce9ec6d3..d51b4cd877 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierNode.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTModifierNode.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.lang.apex.ast; +import static apex.jorje.semantic.symbol.type.ModifierTypeInfos.TEST_METHOD; + import net.sourceforge.pmd.annotation.InternalApi; import apex.jorje.semantic.ast.modifier.ModifierNode; @@ -62,10 +64,20 @@ public class ASTModifierNode extends AbstractApexNode implements A return (node.getModifiers().getJavaModifiers() & TRANSIENT) == TRANSIENT; } + /** + * Returns true if function has `@isTest` annotation or `testmethod` modifier + */ public boolean isTest() { return node.getModifiers().isTest(); } + /** + * Returns true if function has `testmethod` modifier + */ + public boolean hasDeprecatedTestMethod() { + return node.getModifiers().has(TEST_METHOD); + } + public boolean isTestOrTestSetup() { return node.getModifiers().isTestOrTestSetup(); } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexRootNode.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexRootNode.java index ffab8193bc..a14c241b44 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexRootNode.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexRootNode.java @@ -50,4 +50,9 @@ public abstract class ApexRootNode extends AbstractApexNode ASSERT_METHODS = new HashSet<>(); - - static { - ASSERT_METHODS.add("system.assert"); - ASSERT_METHODS.add("system.assertequals"); - ASSERT_METHODS.add("system.assertnotequals"); - } - - @Override - public Object visit(final ASTMethod node, final Object data) { - // test methods should have @isTest annotation. - if (isTestMethodOrClass(node)) { - return data; - } - return checkForAssertStatements(node, data); - } - - private Object checkForAssertStatements(final ASTMethod testMethod, final Object data) { - List methodCallList = testMethod.findDescendantsOfType(ASTMethodCallExpression.class); - String assertMethodName; - for (ASTMethodCallExpression assertMethodCall : methodCallList) { - assertMethodName = assertMethodCall.getFullMethodName().toLowerCase(Locale.ROOT); - if (ASSERT_METHODS.contains(assertMethodName)) { - addViolationWithMessage(data, testMethod, - "''{0}'' method should have @IsTest annotation.", - new Object[] { testMethod.getImage() }); - return data; - } - } - return data; - } -} diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexBadCryptoRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexBadCryptoRule.java index 5e6c322f3c..ccd4f7a19d 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexBadCryptoRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexBadCryptoRule.java @@ -35,6 +35,7 @@ public class ApexBadCryptoRule extends AbstractApexRule { private final Set potentiallyStaticBlob = new HashSet<>(); public ApexBadCryptoRule() { + addRuleChainVisit(ASTUserClass.class); setProperty(CODECLIMATE_CATEGORIES, "Security"); setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 100); setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexDangerousMethodsRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexDangerousMethodsRule.java index 9d908dcf10..f6a031ca98 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexDangerousMethodsRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexDangerousMethodsRule.java @@ -40,7 +40,7 @@ public class ApexDangerousMethodsRule extends AbstractApexRule { private final Set whiteListedVariables = new HashSet<>(); public ApexDangerousMethodsRule() { - super.addRuleChainVisit(ASTUserClass.class); + addRuleChainVisit(ASTUserClass.class); setProperty(CODECLIMATE_CATEGORIES, "Security"); setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 100); setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexOpenRedirectRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexOpenRedirectRule.java index 4cc197a0b5..be4827e185 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexOpenRedirectRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexOpenRedirectRule.java @@ -31,7 +31,7 @@ public class ApexOpenRedirectRule extends AbstractApexRule { private final Set listOfStringLiteralVariables = new HashSet<>(); public ApexOpenRedirectRule() { - super.addRuleChainVisit(ASTUserClass.class); + addRuleChainVisit(ASTUserClass.class); setProperty(CODECLIMATE_CATEGORIES, "Security"); setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 100); setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSOQLInjectionRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSOQLInjectionRule.java index 1e31919133..4248ce6759 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSOQLInjectionRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSOQLInjectionRule.java @@ -51,6 +51,7 @@ public class ApexSOQLInjectionRule extends AbstractApexRule { private final Map selectContainingVariables = new HashMap<>(); public ApexSOQLInjectionRule() { + addRuleChainVisit(ASTUserClass.class); setProperty(CODECLIMATE_CATEGORIES, "Security"); setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 100); setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSuggestUsingNamedCredRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSuggestUsingNamedCredRule.java index e7aa416651..5c650304e0 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSuggestUsingNamedCredRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexSuggestUsingNamedCredRule.java @@ -34,7 +34,7 @@ public class ApexSuggestUsingNamedCredRule extends AbstractApexRule { private final Set listOfAuthorizationVariables = new HashSet<>(); public ApexSuggestUsingNamedCredRule() { - super.addRuleChainVisit(ASTUserClass.class); + addRuleChainVisit(ASTUserClass.class); setProperty(CODECLIMATE_CATEGORIES, "Security"); setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 100); setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexXSSFromEscapeFalseRule.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexXSSFromEscapeFalseRule.java index afc190e55e..6b9c32e4ac 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexXSSFromEscapeFalseRule.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/security/ApexXSSFromEscapeFalseRule.java @@ -23,6 +23,7 @@ public class ApexXSSFromEscapeFalseRule extends AbstractApexRule { private static final String ADD_ERROR = "addError"; public ApexXSSFromEscapeFalseRule() { + addRuleChainVisit(ASTUserClass.class); setProperty(CODECLIMATE_CATEGORIES, "Security"); setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 100); setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); diff --git a/pmd-apex/src/main/resources/category/apex/bestpractices.xml b/pmd-apex/src/main/resources/category/apex/bestpractices.xml index 5c13033efc..78c89eb58f 100644 --- a/pmd-apex/src/main/resources/category/apex/bestpractices.xml +++ b/pmd-apex/src/main/resources/category/apex/bestpractices.xml @@ -64,16 +64,28 @@ public class Foo { -Apex test methods should have @isTest annotation. -As testMethod keyword is deprecated, Salesforce advices to use @isTest annotation for test class/methods. +Apex test methods should have `@isTest` annotation instead of the `testMethod` keyword, +as `testMethod` is deprecated. +Salesforce advices to use [@isTest](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_annotation_isTest.htm) +annotation for test classes and methods. 3 + + + + + + + + + + + + + false positive with @testsetup #3282 + 0 + diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexBadCrypto.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexBadCrypto.xml index 555fd10394..42cd5e3a07 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexBadCrypto.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexBadCrypto.xml @@ -7,6 +7,7 @@ Apex Crypto hardcoded IV 1 + 6 + + + + Apex Crypto hardcoded IV in inner class + 1 + 7 + diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSOQLInjection.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSOQLInjection.xml index 4fdafa534c..80e244a84c 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSOQLInjection.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexSOQLInjection.xml @@ -7,6 +7,7 @@ Potentially unsafe SOQL on concatenation of variables 1 1 + 5 res = Database.query('Select Id,Name From ' + (name == 'Account' ? name : 'Cases')); } +} + ]]> + + + + Potentially unsafe SOQL on concatenation of variables in nested class + 1 + 6 + diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexXSSFromEscapeFalse.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexXSSFromEscapeFalse.xml index 99cf9ac528..ca3907e778 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexXSSFromEscapeFalse.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/security/xml/ApexXSSFromEscapeFalse.xml @@ -7,6 +7,7 @@ Add error variable with escape false 1 + 3 + + + + Add error variable with escape false in nested class + 1 + 4 + diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java index 94cd430553..73490891a2 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cli/PMDParameters.java @@ -89,7 +89,10 @@ public class PMDParameters { converter = PropertyConverter.class) private List properties = new ArrayList<>(); - @Parameter(names = { "-reportfile", "-r" }, description = "Sends report output to a file; default to System.out.") + @Parameter(names = { "-reportfile", "-r" }, + description = "Path to a file to which report output is written. " + + "The file is created if it does not exist. " + + "If this option is not specified, the report is rendered to standard output.") private String reportfile = null; @Parameter(names = { "-version", "-v" }, description = "Specify version of a language PMD should use.") diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/IOUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/IOUtil.java index 1ef21f6135..50177007f5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/IOUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/IOUtil.java @@ -15,6 +15,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.charset.UnsupportedCharsetException; import java.nio.file.Files; +import java.nio.file.Path; import java.security.AccessController; import java.security.PrivilegedAction; @@ -62,16 +63,23 @@ public final class IOUtil { /** * Creates a writer that writes to the given file or to stdout. + * The file is created if it does not exist. * *

Warning: This writer always uses the system default charset. * * @param reportFile the file name (optional) - * @return the writer, never null + * + * @return the writer, never null */ public static Writer createWriter(String reportFile) { try { - return StringUtils.isBlank(reportFile) ? createWriter() - : Files.newBufferedWriter(new File(reportFile).toPath(), getDefaultCharset()); + if (StringUtils.isBlank(reportFile)) { + return createWriter(); + } + Path path = new File(reportFile).toPath(); + Files.createDirectories(path.getParent()); // ensure parent dir exists + // this will create the file if it doesn't exist + return Files.newBufferedWriter(path, getDefaultCharset()); } catch (IOException e) { throw new IllegalArgumentException(e); } diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java index 6d463c1702..7d8a36fcf5 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/util/StringUtil.java @@ -732,6 +732,34 @@ public final class StringUtil { return sb.toString(); } + /** + * If the string starts and ends with the delimiter, returns the substring + * within the delimiters. Otherwise returns the original string. The + * start and end delimiter must be 2 separate instances. + *

{@code
+     * removeSurrounding("",     _ )  = ""
+     * removeSurrounding("q",   'q')  = "q"
+     * removeSurrounding("qq",  'q')  = ""
+     * removeSurrounding("q_q", 'q')  = "_"
+     * }
+ */ + public static String removeSurrounding(String string, char delimiter) { + if (string.length() >= 2 + && string.charAt(0) == delimiter + && string.charAt(string.length() - 1) == delimiter) { + return string.substring(1, string.length() - 1); + } + return string; + } + + /** + * Like {@link #removeSurrounding(String, char) removeSurrounding} with + * a double quote as a delimiter. + */ + public static String removeDoubleQuotes(String string) { + return removeSurrounding(string, '"'); + } + /** * Returns an empty array of string diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cli/CoreCliTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cli/CoreCliTest.java new file mode 100644 index 0000000000..a3bba10c4d --- /dev/null +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cli/CoreCliTest.java @@ -0,0 +1,123 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.cli; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.RestoreSystemProperties; +import org.junit.rules.TemporaryFolder; + +import net.sourceforge.pmd.PMD; + +/** + * + */ +public class CoreCliTest { + + private static final String DUMMY_RULESET = "net/sourceforge/pmd/cli/FakeRuleset.xml"; + private static final String STRING_TO_REPLACE = "__should_be_replaced__"; + + @Rule + public TemporaryFolder tempDir = new TemporaryFolder(); + @Rule + public RestoreSystemProperties restoreSystemProperties = new RestoreSystemProperties(); + private Path srcDir; + + @Before + public void setup() throws IOException { + // set current directory to wd + Path root = tempRoot(); + System.setProperty("user.dir", root.toString()); + + // create a few files + srcDir = Files.createDirectories(root.resolve("src")); + writeString(srcDir.resolve("someSource.dummy"), "dummy text"); + } + + + @Test + public void testPreExistingReportFile() throws IOException { + Path reportFile = tempRoot().resolve("out/reportFile.txt"); + // now we create the file + Files.createDirectories(reportFile.getParent()); + writeString(reportFile, STRING_TO_REPLACE); + + assertTrue("Report file should exist", Files.exists(reportFile)); + + runPmdSuccessfully("-d", srcDir, "-R", DUMMY_RULESET, "-r", reportFile); + + assertNotEquals(readString(reportFile), STRING_TO_REPLACE); + } + + @Test + public void testNonExistentReportFile() { + Path reportFile = tempRoot().resolve("out/reportFile.txt"); + + assertFalse("Report file should not exist", Files.exists(reportFile)); + + runPmdSuccessfully("-d", srcDir, "-R", DUMMY_RULESET, "-r", reportFile); + + assertTrue("Report file should have been created", Files.exists(reportFile)); + } + + + + + + + // utilities + + + + private Path tempRoot() { + return tempDir.getRoot().toPath(); + } + + + private static void runPmdSuccessfully(Object... args) { + runPmd(0, args); + } + + private static String[] argsToString(Object... args) { + String[] result = new String[args.length]; + for (int i = 0; i < args.length; i++) { + result[i] = args[i].toString(); + } + return result; + } + + // available in Files on java 11+ + private static void writeString(Path path, String text) throws IOException { + ByteBuffer encoded = StandardCharsets.UTF_8.encode(text); + Files.write(path, encoded.array()); + } + + + // available in Files on java 11+ + private static String readString(Path path) throws IOException { + byte[] bytes = Files.readAllBytes(path); + ByteBuffer buf = ByteBuffer.wrap(bytes); + return StandardCharsets.UTF_8.decode(buf).toString(); + } + + private static void runPmd(int expectedExitCode, Object[] args) { + int actualExitCode = PMD.run(argsToString(args)); + assertEquals("Exit code", expectedExitCode, actualExitCode); + } + + +} diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java index 8ca15c97dc..edf70631e7 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/util/StringUtilTest.java @@ -4,6 +4,8 @@ package net.sourceforge.pmd.util; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import org.junit.Test; @@ -97,4 +99,12 @@ public class StringUtilTest { StringUtil.appendXmlEscaped(sb, test, true); assertEquals("é", sb.toString()); } + + @Test + public void testRemoveSurrounding() { + assertThat(StringUtil.removeSurrounding("", 'q'), equalTo("")); + assertThat(StringUtil.removeSurrounding("q", 'q'), equalTo("q")); + assertThat(StringUtil.removeSurrounding("qq", 'q'), equalTo("")); + assertThat(StringUtil.removeSurrounding("qqq", 'q'), equalTo("q")); + } } diff --git a/pmd-core/src/test/resources/net/sourceforge/pmd/cli/FakeRuleset.xml b/pmd-core/src/test/resources/net/sourceforge/pmd/cli/FakeRuleset.xml new file mode 100644 index 0000000000..7b3f1a8924 --- /dev/null +++ b/pmd-core/src/test/resources/net/sourceforge/pmd/cli/FakeRuleset.xml @@ -0,0 +1,32 @@ + + + + + Ruleset used by test RuleSetFactoryTest + + + + +Just for test + + 3 + + + + + + + +Just for test + + 3 + + + + + \ No newline at end of file diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml index 44c0ed3eb7..39a4eec1ff 100644 --- a/pmd-dist/pom.xml +++ b/pmd-dist/pom.xml @@ -138,11 +138,6 @@ pmd-java ${project.version} - - net.sourceforge.pmd - pmd-javascript - ${project.version} - net.sourceforge.pmd pmd-jsp @@ -249,6 +244,11 @@ pmd-apex ${project.version} + + net.sourceforge.pmd + pmd-javascript + ${project.version} + net.sourceforge.pmd pmd-scala_2.13 diff --git a/pmd-dist/src/main/resources/assemblies/pmd-bin.xml b/pmd-dist/src/main/resources/assemblies/pmd-bin.xml index 8b0c0134b2..18a8b9e94e 100644 --- a/pmd-dist/src/main/resources/assemblies/pmd-bin.xml +++ b/pmd-dist/src/main/resources/assemblies/pmd-bin.xml @@ -12,11 +12,7 @@ - bgastviewer.bat - cpd.bat - cpdgui.bat - designer.bat - pmd.bat + *.bat target/extra-resources/scripts bin diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/AllRulesIT.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/AllRulesIT.java index 8ba9e0533f..4f9a38ff0f 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/AllRulesIT.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/AllRulesIT.java @@ -22,8 +22,8 @@ public class AllRulesIT extends AbstractBinaryDistributionTest { @Parameters public static Iterable languagesToTest() { if (PMDExecutor.isJava7Test()) { - // note: apex, scala, and visualforce require java8 - return Arrays.asList("java", "javascript", "jsp", "modelica", + // note: apex, javascript, scala, and visualforce require java8 + return Arrays.asList("java", "jsp", "modelica", "plsql", "pom", "velocitytemplate", "xml", "xsl"); } // note: scala and wsdl have no rules diff --git a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java index d5bff3f134..a093206e1b 100644 --- a/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java +++ b/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java @@ -25,10 +25,10 @@ public class BinaryDistributionIT extends AbstractBinaryDistributionTest { private static final String SUPPORTED_LANGUAGES_PMD; static { - // note: apex, visualforce, and scala require java8 + // note: apex, javascript, visualforce, and scala require java8 if (PMDExecutor.isJava7Test()) { - SUPPORTED_LANGUAGES_CPD = "Supported languages: [cpp, cs, dart, ecmascript, fortran, go, groovy, java, jsp, kotlin, lua, matlab, modelica, objectivec, perl, php, plsql, python, ruby, swift, xml]"; - SUPPORTED_LANGUAGES_PMD = "ecmascript, java, jsp, modelica, plsql, pom, vm, wsdl, xml, xsl"; + SUPPORTED_LANGUAGES_CPD = "Supported languages: [cpp, cs, dart, fortran, go, groovy, java, jsp, kotlin, lua, matlab, modelica, objectivec, perl, php, plsql, python, ruby, swift, xml]"; + SUPPORTED_LANGUAGES_PMD = "java, jsp, modelica, plsql, pom, vm, wsdl, xml, xsl"; } else { SUPPORTED_LANGUAGES_CPD = "Supported languages: [apex, cpp, cs, dart, ecmascript, fortran, go, groovy, java, jsp, kotlin, lua, matlab, modelica, objectivec, perl, php, plsql, python, ruby, scala, swift, vf, xml]"; SUPPORTED_LANGUAGES_PMD = "apex, ecmascript, java, jsp, modelica, plsql, pom, scala, vf, vm, wsdl, xml, xsl"; @@ -48,6 +48,7 @@ public class BinaryDistributionIT extends AbstractBinaryDistributionTest { result.add(basedir + "bin/run.sh"); result.add(basedir + "bin/pmd.bat"); result.add(basedir + "bin/cpd.bat"); + result.add(basedir + "bin/ast-dump.bat"); result.add(basedir + "lib/pmd-core-" + PMDVersion.VERSION + ".jar"); result.add(basedir + "lib/pmd-java-" + PMDVersion.VERSION + ".jar"); return result; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/GenericLiteralCheckerRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/GenericLiteralCheckerRule.java index 8407ee22fc..e9c1be4cc6 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/GenericLiteralCheckerRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/GenericLiteralCheckerRule.java @@ -30,6 +30,7 @@ public class GenericLiteralCheckerRule extends AbstractJavaRule { public GenericLiteralCheckerRule() { definePropertyDescriptor(REGEX_PROPERTY); + addRuleChainVisit(ASTLiteral.class); } private void init() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/StringConcatenationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/StringConcatenationRule.java index 11686bc535..a08a2f1a53 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/StringConcatenationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/StringConcatenationRule.java @@ -11,6 +11,10 @@ import net.sourceforge.pmd.lang.java.ast.ASTForStatement; //FUTURE This is not referenced by any RuleSet? public class StringConcatenationRule extends AbstractJavaRule { + public StringConcatenationRule() { + addRuleChainVisit(ASTForStatement.class); + } + @Override public Object visit(ASTForStatement node, Object data) { Node forLoopStmt = null; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/SymbolTableTestRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/SymbolTableTestRule.java index ef26fb8598..530ac9509b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/SymbolTableTestRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/SymbolTableTestRule.java @@ -17,6 +17,10 @@ import net.sourceforge.pmd.lang.symboltable.NameOccurrence; @Deprecated public class SymbolTableTestRule extends AbstractJavaRule { + public SymbolTableTestRule() { + addRuleChainVisit(ASTFieldDeclaration.class); + } + @Override public Object visit(ASTFieldDeclaration node, Object data) { for (ASTVariableDeclaratorId declaration : node.findDescendantsOfType(ASTVariableDeclaratorId.class)) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/UselessAssignment.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/UselessAssignment.java index 61b7a1950b..c972f6b235 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/UselessAssignment.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/UselessAssignment.java @@ -21,6 +21,10 @@ public class UselessAssignment extends AbstractJavaRule implements Executable { private RuleContext rc; + public UselessAssignment() { + addRuleChainVisit(ASTMethodDeclaration.class); + } + @Override public Object visit(ASTMethodDeclaration node, Object data) { this.rc = (RuleContext) data; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AvoidReassigningParametersRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AvoidReassigningParametersRule.java index ec06c65580..4972bdd188 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AvoidReassigningParametersRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AvoidReassigningParametersRule.java @@ -40,9 +40,11 @@ public class AvoidReassigningParametersRule extends AbstractJavaRule { && jocc.getNameForWhichThisIsAQualifier() == null && !jocc.useThisOrSuper() && !decl.isVarargs() && (!decl.isArray() || jocc.getLocation().getParent().getParent().getNumChildren() == 1)) { - // not an array or no primary suffix to access the array - // values - addViolation(data, decl.getNode(), decl.getImage()); + // not an array or no primary suffix to access the array values + addViolation(data, occ.getLocation(), decl.getImage()); + + // only the first assignment should be reported + break; } } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LiteralsFirstInComparisonsRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LiteralsFirstInComparisonsRule.java index d89bcedf5e..c26a8473e8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LiteralsFirstInComparisonsRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/LiteralsFirstInComparisonsRule.java @@ -4,12 +4,8 @@ package net.sourceforge.pmd.lang.java.rule.bestpractices; -import java.util.List; - import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; import net.sourceforge.pmd.lang.java.ast.ASTArguments; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTConditionalAndExpression; import net.sourceforge.pmd.lang.java.ast.ASTConditionalOrExpression; import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression; @@ -21,9 +17,11 @@ import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; -import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator; +import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId; import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.lang.java.symboltable.VariableNameDeclaration; +import net.sourceforge.pmd.lang.symboltable.NameDeclaration; public class LiteralsFirstInComparisonsRule extends AbstractJavaRule { @@ -47,20 +45,22 @@ public class LiteralsFirstInComparisonsRule extends AbstractJavaRule { private boolean hasStringLiteralFirst(ASTPrimaryExpression expression) { ASTPrimaryPrefix primaryPrefix = expression.getFirstChildOfType(ASTPrimaryPrefix.class); - ASTLiteral firstLiteral = primaryPrefix.getFirstDescendantOfType(ASTLiteral.class); + ASTLiteral firstLiteral = primaryPrefix.getFirstChildOfType(ASTLiteral.class); return firstLiteral != null && firstLiteral.isStringLiteral(); } private boolean isNullableComparisonWithStringLiteral(ASTPrimaryExpression expression) { String opName = getOperationName(expression); ASTPrimarySuffix argsSuffix = getSuffixOfArguments(expression); - return opName != null && argsSuffix != null && isStringLiteralComparison(opName, argsSuffix) - && isNotWithinNullComparison(expression); + return opName != null && argsSuffix != null + && isStringLiteralComparison(opName, argsSuffix) + && isNotWithinNullComparison(expression); } private String getOperationName(ASTPrimaryExpression primaryExpression) { - return isMethodsChain(primaryExpression) ? getOperationNameBySuffix(primaryExpression) - : getOperationNameByPrefix(primaryExpression); + return isMethodsChain(primaryExpression) + ? getOperationNameBySuffix(primaryExpression) + : getOperationNameByPrefix(primaryExpression); } private boolean isMethodsChain(ASTPrimaryExpression primaryExpression) { @@ -90,12 +90,11 @@ public class LiteralsFirstInComparisonsRule extends AbstractJavaRule { } private ASTPrimarySuffix getPrimarySuffixAtIndexFromEnd(ASTPrimaryExpression primaryExpression, int indexFromEnd) { - List primarySuffixes = primaryExpression.findChildrenOfType(ASTPrimarySuffix.class); - if (!primarySuffixes.isEmpty()) { - int suffixIndex = primarySuffixes.size() - 1 - indexFromEnd; - return primarySuffixes.get(suffixIndex); + int index = primaryExpression.getNumChildren() - 1 - indexFromEnd; + if (index <= 0) { + return null; } - return null; + return (ASTPrimarySuffix) primaryExpression.getChild(index); } private boolean isStringLiteralComparison(String opName, ASTPrimarySuffix argsSuffix) { @@ -126,29 +125,27 @@ public class LiteralsFirstInComparisonsRule extends AbstractJavaRule { } private boolean isStringLiteralFirstArgumentOfSuffix(ASTPrimarySuffix primarySuffix) { - try { - JavaNode firstLiteralArg = getFirstLiteralArgument(primarySuffix); - JavaNode firstNameArg = getFirstNameArgument(primarySuffix); - return isStringLiteral(firstLiteralArg) || isConstantString(firstNameArg); - } catch (NullPointerException e) { + JavaNode argumentPrimaryPrefix = getArgumentPrimaryPrefix(primarySuffix); + if (argumentPrimaryPrefix == null) { return false; } - } - - private JavaNode getFirstLiteralArgument(ASTPrimarySuffix primarySuffix) { - return getArgumentPrimaryPrefix(primarySuffix).getFirstChildOfType(ASTLiteral.class); - } - - private JavaNode getFirstNameArgument(ASTPrimarySuffix primarySuffix) { - return getArgumentPrimaryPrefix(primarySuffix).getFirstChildOfType(ASTName.class); + JavaNode firstLiteralArg = argumentPrimaryPrefix.getFirstChildOfType(ASTLiteral.class); + JavaNode firstNameArg = argumentPrimaryPrefix.getFirstChildOfType(ASTName.class); + return isStringLiteral(firstLiteralArg) || isConstantString(firstNameArg); } private JavaNode getArgumentPrimaryPrefix(ASTPrimarySuffix primarySuffix) { - ASTArguments arguments = primarySuffix.getFirstChildOfType(ASTArguments.class); - ASTArgumentList argumentList = arguments.getFirstChildOfType(ASTArgumentList.class); - ASTExpression expression = argumentList.getFirstChildOfType(ASTExpression.class); + ASTExpression expression = primarySuffix.getFirstChildOfType(ASTArguments.class) + .getFirstChildOfType(ASTArgumentList.class) + .getFirstChildOfType(ASTExpression.class); + + assert expression != null : "We checked before that we had exactly one argument, so this cannot fail"; + ASTPrimaryExpression primaryExpression = expression.getFirstChildOfType(ASTPrimaryExpression.class); - return primaryExpression.getFirstChildOfType(ASTPrimaryPrefix.class); + if (primaryExpression != null) { + return primaryExpression.getChild(0); + } + return null; } private boolean isStringLiteral(JavaNode node) { @@ -162,17 +159,13 @@ public class LiteralsFirstInComparisonsRule extends AbstractJavaRule { private boolean isConstantString(JavaNode node) { if (node instanceof ASTName) { ASTName name = (ASTName) node; - ASTClassOrInterfaceBody classBody = name.getFirstParentOfType(ASTClassOrInterfaceBody.class); - ASTClassOrInterfaceBodyDeclaration classOrInterfaceBodyDeclaration = classBody.getFirstChildOfType(ASTClassOrInterfaceBodyDeclaration.class); - List fieldDeclarations = classOrInterfaceBodyDeclaration.findChildrenOfType(ASTFieldDeclaration.class); - for (ASTFieldDeclaration fieldDeclaration : fieldDeclarations) { - ASTVariableDeclarator declaration = fieldDeclaration.getFirstChildOfType(ASTVariableDeclarator.class); - if (declaration.getName().equals(name.getImage()) - && String.class.equals(declaration.getType()) - && fieldDeclaration.isFinal() - && fieldDeclaration.isStatic()) { - return true; - } + NameDeclaration resolved = name.getNameDeclaration(); + if (resolved instanceof VariableNameDeclaration + && resolved.getNode() instanceof ASTVariableDeclaratorId) { + ASTVariableDeclaratorId resolvedNode = (ASTVariableDeclaratorId) resolved.getNode(); + return resolvedNode.isFinal() + && resolvedNode.isField() + && resolvedNode.getFirstParentOfType(ASTFieldDeclaration.class).isStatic(); } } return false; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java index 1533e0db57..c6b294a8a4 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java @@ -13,15 +13,20 @@ import java.util.Map; import java.util.Set; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; +import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTConstructorDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTInitializer; +import net.sourceforge.pmd.lang.java.ast.ASTLiteral; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.Annotatable; import net.sourceforge.pmd.lang.java.rule.AbstractIgnoredAnnotationRule; import net.sourceforge.pmd.lang.java.symboltable.ClassScope; import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration; +import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.lang.symboltable.NameOccurrence; +import net.sourceforge.pmd.util.StringUtil; /** * This rule detects private methods, that are not used and can therefore be @@ -41,25 +46,45 @@ public class UnusedPrivateMethodRule extends AbstractIgnoredAnnotationRule { } /** - * Visit each method declaration. - * - * @param node - * the method declaration - * @param data - * data - rule context - * @return data + * Return a set of method names which are considered used. Only the + * no-arg overload is considered used. */ + private static Set methodsUsedByAnnotations(ASTClassOrInterfaceDeclaration klassDecl) { + Set result = Collections.emptySet(); + for (ASTAnyTypeBodyDeclaration declaration : klassDecl.getDeclarations()) { + for (ASTAnnotation annot : declaration.findChildrenOfType(ASTAnnotation.class)) { + if (TypeTestUtil.isA("org.junit.jupiter.params.provider.MethodSource", annot)) { + // MethodSource#value() -> String[], there may be several of those methods + // todo this is not robust, revisit in pmd 7 + for (ASTLiteral literal : annot.findDescendantsOfType(ASTLiteral.class)) { + if (literal.isStringLiteral()) { + if (result.isEmpty()) { + result = new HashSet<>(); // make writable + } + result.add(StringUtil.removeDoubleQuotes(literal.getImage())); + } + } + } + } + } + return result; + } + @Override public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { if (node.isInterface()) { return data; } + Set methodsUsedByAnnotations = methodsUsedByAnnotations(node); + Map> methods = node.getScope().getEnclosingScope(ClassScope.class) - .getMethodDeclarations(); + .getMethodDeclarations(); for (MethodNameDeclaration mnd : findUnique(methods)) { List occs = methods.get(mnd); - if (!privateAndNotExcluded(mnd) || hasIgnoredAnnotation((Annotatable) mnd.getNode().getParent())) { + if (!privateAndNotExcluded(mnd) + || hasIgnoredAnnotation((Annotatable) mnd.getNode().getParent()) + || mnd.getParameterCount() == 0 && methodsUsedByAnnotations.contains(mnd.getName())) { continue; } if (occs.isEmpty()) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldDeclarationsShouldBeAtStartOfClassRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldDeclarationsShouldBeAtStartOfClassRule.java index 0ec9709589..dd57068ae0 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldDeclarationsShouldBeAtStartOfClassRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/FieldDeclarationsShouldBeAtStartOfClassRule.java @@ -48,6 +48,7 @@ public class FieldDeclarationsShouldBeAtStartOfClassRule extends AbstractJavaRul definePropertyDescriptor(ignoreEnumDeclarations); definePropertyDescriptor(ignoreAnonymousClassDeclarations); definePropertyDescriptor(ignoreInterfaceDeclarations); + addRuleChainVisit(ASTFieldDeclaration.class); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/LocalVariableCouldBeFinalRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/LocalVariableCouldBeFinalRule.java index b7ce0cab4b..444c1760e3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/LocalVariableCouldBeFinalRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/LocalVariableCouldBeFinalRule.java @@ -24,6 +24,7 @@ public class LocalVariableCouldBeFinalRule extends AbstractOptimizationRule { public LocalVariableCouldBeFinalRule() { definePropertyDescriptor(IGNORE_FOR_EACH); + addRuleChainVisit(ASTLocalVariableDeclaration.class); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodArgumentCouldBeFinalRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodArgumentCouldBeFinalRule.java index 0d11dcf72d..351d93d9b1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodArgumentCouldBeFinalRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/MethodArgumentCouldBeFinalRule.java @@ -18,13 +18,18 @@ import net.sourceforge.pmd.lang.symboltable.Scope; public class MethodArgumentCouldBeFinalRule extends AbstractOptimizationRule { + public MethodArgumentCouldBeFinalRule() { + addRuleChainVisit(ASTConstructorDeclaration.class); + addRuleChainVisit(ASTMethodDeclaration.class); + } + @Override public Object visit(ASTMethodDeclaration meth, Object data) { if (meth.isNative() || meth.isAbstract()) { return data; } this.lookForViolation(meth.getScope(), data); - return super.visit(meth, data); + return data; } private void lookForViolation(Scope scope, Object data) { @@ -41,7 +46,7 @@ public class MethodArgumentCouldBeFinalRule extends AbstractOptimizationRule { @Override public Object visit(ASTConstructorDeclaration constructor, Object data) { this.lookForViolation(constructor.getScope(), data); - return super.visit(constructor, data); + return data; } } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/OnlyOneReturnRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/OnlyOneReturnRule.java index 3421f616ce..394c437783 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/OnlyOneReturnRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/OnlyOneReturnRule.java @@ -8,27 +8,18 @@ import java.util.Iterator; import java.util.List; import net.sourceforge.pmd.lang.ast.Node; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; public class OnlyOneReturnRule extends AbstractJavaRule { - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - return super.visit(node, data); + public OnlyOneReturnRule() { + addRuleChainVisit(ASTMethodDeclaration.class); } @Override public Object visit(ASTMethodDeclaration node, Object data) { - if (node.isAbstract()) { - return data; - } - List returnNodes = node.findDescendantsOfType(ASTReturnStatement.class); if (returnNodes.size() > 1) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryImportRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryImportRule.java index a311692615..67c7e95ea5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryImportRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryImportRule.java @@ -24,6 +24,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; import net.sourceforge.pmd.lang.java.ast.Comment; import net.sourceforge.pmd.lang.java.ast.FormalComment; +import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.ast.TypeNode; import net.sourceforge.pmd.lang.java.ast.internal.ImportWrapper; import net.sourceforge.pmd.lang.java.ast.internal.PrettyPrintingUtil; @@ -161,7 +162,7 @@ public class UnnecessaryImportRule extends AbstractJavaRule { * Remove the import wrapper that imports the name referenced by the * given node. */ - protected void check(Node referenceNode, RuleContext ruleCtx) { + protected void check(JavaNode referenceNode, RuleContext ruleCtx) { if (imports.isEmpty()) { return; } @@ -184,6 +185,20 @@ public class UnnecessaryImportRule extends AbstractJavaRule { } } + // check on-demand imports + it = imports.iterator(); + while (it.hasNext()) { + ImportWrapper i = it.next(); + if (!i.isStaticOnDemand() && i.isOnDemand()) { + String possibleClassName = i.getFullName() + "." + candName; + Class possibleClazz = referenceNode.getRoot().getClassTypeResolver() + .loadClassOrNull(possibleClassName); + if (possibleClazz != null) { + it.remove(); + } + } + } + // check static on-demand imports it = imports.iterator(); while (it.hasNext()) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryLocalBeforeReturnRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryLocalBeforeReturnRule.java index e9f43f3400..71a0e745f5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryLocalBeforeReturnRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/codestyle/UnnecessaryLocalBeforeReturnRule.java @@ -14,7 +14,6 @@ import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement; import net.sourceforge.pmd.lang.java.ast.ASTExpression; import net.sourceforge.pmd.lang.java.ast.ASTMemberSelector; -import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression; import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix; @@ -32,18 +31,9 @@ public class UnnecessaryLocalBeforeReturnRule extends AbstractJavaRule { private static final PropertyDescriptor STATEMENT_ORDER_MATTERS = booleanProperty("statementOrderMatters").defaultValue(true).desc("If set to false this rule no longer requires the variable declaration and return statement to be on consecutive lines. Any variable that is used solely in a return statement will be reported.").build(); - public UnnecessaryLocalBeforeReturnRule() { definePropertyDescriptor(STATEMENT_ORDER_MATTERS); - } - - @Override - public Object visit(ASTMethodDeclaration meth, Object data) { - // skip void/abstract/native method - if (meth.isVoid() || meth.isAbstract() || meth.isNative()) { - return data; - } - return super.visit(meth, data); + addRuleChainVisit(ASTReturnStatement.class); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidFieldNameMatchingTypeNameRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidFieldNameMatchingTypeNameRule.java index ca96b63ebb..85c19e99c8 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidFieldNameMatchingTypeNameRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/AvoidFieldNameMatchingTypeNameRule.java @@ -10,12 +10,8 @@ import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; public class AvoidFieldNameMatchingTypeNameRule extends AbstractJavaRule { - @Override - public Object visit(ASTClassOrInterfaceDeclaration node, Object data) { - if (node.isInterface()) { - return data; - } - return super.visit(node, data); + public AvoidFieldNameMatchingTypeNameRule() { + addRuleChainVisit(ASTFieldDeclaration.class); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/ConstructorCallsOverridableMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/ConstructorCallsOverridableMethodRule.java index 0589017b57..f45bfe4eb1 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/ConstructorCallsOverridableMethodRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/errorprone/ConstructorCallsOverridableMethodRule.java @@ -14,6 +14,7 @@ import java.util.Set; import java.util.TreeMap; import net.sourceforge.pmd.lang.ast.Node; +import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; import net.sourceforge.pmd.lang.java.ast.ASTArguments; import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral; @@ -860,6 +861,12 @@ public final class ConstructorCallsOverridableMethodRule extends AbstractJavaRul return data; } + @Override + public Object visit(ASTAnnotationTypeDeclaration node, Object data) { + // just skip Annotations + return data; + } + /** * This check must be evaluated independently for each class. Inner classes * get their own EvalPackage in order to perform independent evaluation. diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/MethodTypeResolution.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/MethodTypeResolution.java index 8ee0f5e347..432f42e5bc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/MethodTypeResolution.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/MethodTypeResolution.java @@ -37,6 +37,11 @@ import net.sourceforge.pmd.lang.java.typeresolution.typeinference.Variable; @Deprecated @InternalApi public final class MethodTypeResolution { + /** + * + */ + private static final String MESSAGE_INCOMPLETE_AUXCLASSPATH = "Possible incomplete auxclasspath: Error while processing methods"; + private MethodTypeResolution() {} private static final Logger LOG = Logger.getLogger(MethodTypeResolution.class.getName()); @@ -477,7 +482,7 @@ public final class MethodTypeResolution { } } catch (final LinkageError e) { // This is an incomplete classpath, report the missing class - LOG.log(Level.FINE, "Possible incomplete auxclasspath: Error while processing methods", e); + LOG.log(Level.FINE, MESSAGE_INCOMPLETE_AUXCLASSPATH, e); } // search it's supertype @@ -496,7 +501,7 @@ public final class MethodTypeResolution { } catch (TypeNotPresentException | LinkageError e) { // might be thrown by contextClass.getGenericSuperclass() // This is an incomplete classpath, report the missing class - LOG.log(Level.FINE, "Possible incomplete auxclasspath: Error while processing methods", e); + LOG.log(Level.FINE, MESSAGE_INCOMPLETE_AUXCLASSPATH, e); } } @@ -509,7 +514,7 @@ public final class MethodTypeResolution { } catch (TypeNotPresentException | LinkageError e) { // might be thrown by contextClass.getGenericInterface() // This is an incomplete classpath, report the missing class - LOG.log(Level.FINE, "Possible incomplete auxclasspath: Error while processing methods", e); + LOG.log(Level.FINE, MESSAGE_INCOMPLETE_AUXCLASSPATH, e); } return result; @@ -522,15 +527,22 @@ public final class MethodTypeResolution { return MethodType.build(method); } - JavaTypeDefinition returnType = context.resolveTypeDefinition(method.getGenericReturnType(), - method, typeArguments); - List argTypes = new ArrayList<>(); + try { + JavaTypeDefinition returnType = context.resolveTypeDefinition(method.getGenericReturnType(), + method, typeArguments); + List argTypes = new ArrayList<>(); - for (Type argType : method.getGenericParameterTypes()) { - argTypes.add(context.resolveTypeDefinition(argType, method, typeArguments)); + for (Type argType : method.getGenericParameterTypes()) { + argTypes.add(context.resolveTypeDefinition(argType, method, typeArguments)); + } + return MethodType.build(returnType, argTypes, method); + } catch (TypeNotPresentException | LinkageError e) { + // might be thrown by method.getGenericReturnType() and method.getGenericParameterTypes() + // This is an incomplete classpath, report the missing class + LOG.log(Level.FINE, MESSAGE_INCOMPLETE_AUXCLASSPATH, e); + + return MethodType.build(method); } - - return MethodType.build(returnType, argTypes, method); } @@ -682,6 +694,12 @@ public final class MethodTypeResolution { // example result: List.getAsSuper(Collection) becomes Collection JavaTypeDefinition argSuper = argument.getAsSuper(parameter.getType()); // argSuper can't be null because isAssignableFrom check above returned true + // it might be null however, if the auxclasspath was not complete... + if (argSuper == null) { + // that's not really correct, because the generic type are ignored... + // be we can't compare the types + return true; + } // right now we only check if generic arguments are the same // TODO: add support for wildcard types diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinitionSimple.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinitionSimple.java index 20beef712b..820038d271 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinitionSimple.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/typeresolution/typedefinition/JavaTypeDefinitionSimple.java @@ -182,38 +182,45 @@ import java.util.logging.Logger; return forClass(Object.class); } - if (type instanceof Class) { // Raw types take this branch as well - return forClass((Class) type); - } else if (type instanceof ParameterizedType) { - final ParameterizedType parameterizedType = (ParameterizedType) type; + try { + if (type instanceof Class) { // Raw types take this branch as well + return forClass((Class) type); + } else if (type instanceof ParameterizedType) { + final ParameterizedType parameterizedType = (ParameterizedType) type; - // recursively determine each type argument's type def. - final Type[] typeArguments = parameterizedType.getActualTypeArguments(); - final JavaTypeDefinition[] genericBounds = new JavaTypeDefinition[typeArguments.length]; - for (int i = 0; i < typeArguments.length; i++) { - genericBounds[i] = resolveTypeDefinition(typeArguments[i], method, methodTypeArgs); - } + // recursively determine each type argument's type def. + final Type[] typeArguments = parameterizedType.getActualTypeArguments(); + final JavaTypeDefinition[] genericBounds = new JavaTypeDefinition[typeArguments.length]; + for (int i = 0; i < typeArguments.length; i++) { + genericBounds[i] = resolveTypeDefinition(typeArguments[i], method, methodTypeArgs); + } - // TODO : is this cast safe? - return forClass((Class) parameterizedType.getRawType(), genericBounds); - } else if (type instanceof TypeVariable) { - return getGenericType(((TypeVariable) type).getName(), method, methodTypeArgs); - } else if (type instanceof WildcardType) { - final Type[] wildcardLowerBounds = ((WildcardType) type).getLowerBounds(); + // TODO : is this cast safe? + return forClass((Class) parameterizedType.getRawType(), genericBounds); + } else if (type instanceof TypeVariable) { + return getGenericType(((TypeVariable) type).getName(), method, methodTypeArgs); + } else if (type instanceof WildcardType) { + final Type[] wildcardLowerBounds = ((WildcardType) type).getLowerBounds(); - if (wildcardLowerBounds.length != 0) { // lower bound wildcard - return forClass(LOWER_WILDCARD, resolveTypeDefinition(wildcardLowerBounds[0], method, methodTypeArgs)); - } else { // upper bound wildcard - final Type[] wildcardUpperBounds = ((WildcardType) type).getUpperBounds(); - return forClass(UPPER_WILDCARD, resolveTypeDefinition(wildcardUpperBounds[0], method, methodTypeArgs)); - } - } else if (type instanceof GenericArrayType) { - JavaTypeDefinition component = resolveTypeDefinition(((GenericArrayType) type).getGenericComponentType(), method, methodTypeArgs); - // only if we could determine the actual type - if (component != null) { - // TODO: retain the generic types of the array component... - return forClass(Array.newInstance(component.getType(), 0).getClass()); + if (wildcardLowerBounds.length != 0) { // lower bound wildcard + return forClass(LOWER_WILDCARD, resolveTypeDefinition(wildcardLowerBounds[0], method, methodTypeArgs)); + } else { // upper bound wildcard + final Type[] wildcardUpperBounds = ((WildcardType) type).getUpperBounds(); + return forClass(UPPER_WILDCARD, resolveTypeDefinition(wildcardUpperBounds[0], method, methodTypeArgs)); + } + } else if (type instanceof GenericArrayType) { + JavaTypeDefinition component = resolveTypeDefinition(((GenericArrayType) type).getGenericComponentType(), method, methodTypeArgs); + // only if we could determine the actual type + if (component != null) { + // TODO: retain the generic types of the array component... + return forClass(Array.newInstance(component.getType(), 0).getClass()); + } } + } catch (TypeNotPresentException | LinkageError e) { + // might be thrown by parameterizedType.getActualTypeArguments(), type.getLowerBounds(), + // type.getUpperBounds(), type.getGenericComponentType() + // This is an incomplete classpath, report the missing class + LOG.log(Level.FINE, "Possible incomplete auxclasspath: Error while resolving generic types", e); } // TODO : Shall we throw here? diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeTestUtil.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeTestUtil.java index 3f8f437e9b..2099b8552b 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeTestUtil.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeTestUtil.java @@ -8,6 +8,7 @@ import java.lang.reflect.Modifier; import java.util.List; import net.sourceforge.pmd.internal.util.AssertionUtil; +import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTAnnotationTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration; @@ -15,6 +16,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType; import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTImplementsList; import net.sourceforge.pmd.lang.java.ast.ASTImportDeclaration; +import net.sourceforge.pmd.lang.java.ast.ASTName; import net.sourceforge.pmd.lang.java.ast.TypeNode; import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper; @@ -221,6 +223,12 @@ public final class TypeTestUtil { } private static boolean fallbackIsA(TypeNode n, String canonicalName, boolean considerSubtype) { + if (n instanceof ASTAnnotation) { + // the annotation node has no image itself + n = n.getFirstDescendantOfType(ASTName.class); + assert n != null; + } + if (n.getImage() != null && !n.getImage().contains(".") && canonicalName.contains(".")) { // simple name detected, check the imports to get the full name and use that for fallback List imports = n.getRoot().findChildrenOfType(ASTImportDeclaration.class); diff --git a/pmd-java/src/main/resources/category/java/bestpractices.xml b/pmd-java/src/main/resources/category/java/bestpractices.xml index e8c1f71d4c..f18ed66aea 100644 --- a/pmd-java/src/main/resources/category/java/bestpractices.xml +++ b/pmd-java/src/main/resources/category/java/bestpractices.xml @@ -301,14 +301,29 @@ public class Foo { class="net.sourceforge.pmd.lang.java.rule.bestpractices.AvoidReassigningParametersRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#avoidreassigningparameters"> -Reassigning values to incoming parameters is not recommended. Use temporary local variables instead. +Reassigning values to incoming parameters of a method or constructor is not recommended, as this can +make the code more difficult to understand. The code is often read with the assumption that parameter values +don't change and an assignment violates therefore the principle of least astonishment. This is especially a +problem if the parameter is documented e.g. in the method's javadoc and the new content differs from the original +documented content. + +Use temporary local variables instead. This allows you to assign a new name, which makes the code better +understandable. + +Note that this rule considers both methods and constructors. If there are multiple assignments for a formal +parameter, then only the first assignment is reported. 2 @@ -802,6 +817,71 @@ public class MyTest {
+ + + 3 + + + + + + + + + + + + + -All switch statements should include a default option to catch any unspecified values. + Switch statements should be exhaustive, to make their control flow + easier to follow. This can be achieved by adding a `default` case, or, + if the switch is on an enum type, by ensuring there is one switch branch + for each enum constant. 3 @@ -1305,14 +1388,14 @@ All switch statements should include a default option to catch any unspecified v diff --git a/pmd-java/src/main/resources/category/java/codestyle.xml b/pmd-java/src/main/resources/category/java/codestyle.xml index 5515d5ef04..226ea0acb2 100644 --- a/pmd-java/src/main/resources/category/java/codestyle.xml +++ b/pmd-java/src/main/resources/category/java/codestyle.xml @@ -550,6 +550,7 @@ while (true) { // preferred approach Use explicit scoping instead of accidental usage of default package private level. The rule allows methods and fields annotated with Guava's @VisibleForTesting and JUnit 5's annotations. + +This rule is deprecated since PMD 6.35.0. It assumes that any usage of package-access is accidental, +and by doing so, prohibits using a really fundamental and useful feature of the language. + +To satisfy the rule, you have to make the member public even if it doesn't need to, or make it protected, +which muddies your intent even more if you don't intend the class to be extended, and may be at odds with +other rules like {% rule "java/codestyle/AvoidProtectedFieldInFinalClass" %}. + +The rule {% rule "java/codestyle/CommentDefaultAccessModifier" %} should be used instead. This rule flags +the same thing, but has an escape hatch. 3 diff --git a/pmd-java/src/main/resources/category/java/design.xml b/pmd-java/src/main/resources/category/java/design.xml index 24cebc8967..a4dfdc31a8 100644 --- a/pmd-java/src/main/resources/category/java/design.xml +++ b/pmd-java/src/main/resources/category/java/design.xml @@ -512,10 +512,14 @@ into the former client classes. -It is somewhat confusing to have a field name matching the declaring class name. +It is somewhat confusing to have a field name matching the declaring type name. This probably means that type and/or field names should be chosen more carefully. 3 @@ -407,6 +407,9 @@ This probably means that type and/or field names should be chosen more carefully public class Foo extends Bar { int foo; // There is probably a better name that can be used } +public interface Operation { + int OPERATION = 1; // There is probably a better name that can be used +} ]]> @@ -1003,6 +1006,7 @@ public class Foo implements Cloneable { The method clone() should throw a CloneNotSupportedException. + +This rule is deprecated since PMD 6.35.0 without replacement. The rule has no real value as +`CloneNotSupportedException` is a checked exception and therefore you need to deal with it while +implementing the `clone()` method. You either need to declare the exception or catch it. If you catch it, +then subclasses can't throw it themselves explicitly. However, `Object.clone()` will still throw this +exception if the `Cloneable` interface is not implemented. 3 @@ -1100,24 +1110,38 @@ public class Bar { class="net.sourceforge.pmd.lang.rule.XPathRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#compareobjectswithequals"> -Use equals() to compare object references; avoid comparing them with ==. +Use `equals()` to compare object references; avoid comparing them with `==`. + +Since comparing objects with named constants is useful in some cases (eg, when +defining constants for sentinel values), the rule ignores comparisons against +fields with all-caps name (eg `this == SENTINEL`), which is a common naming +convention for constant fields. + +You may allow some types to be compared by reference by listing the exceptions +in the `typesThatCompareByReference` property. 3 + + java.lang.Enum,java.lang.Class + @@ -2953,9 +2977,9 @@ public class Singleton { class="net.sourceforge.pmd.lang.java.rule.errorprone.SingletonClassReturningNewInstanceRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_errorprone.html#singletonclassreturningnewinstance"> -Some classes contain overloaded getInstance. The problem with overloaded getInstance methods -is that the instance created using the overloaded method is not cached and so, -for each call and new objects will be created for every invocation. + A singleton class should only ever have one instance. Failure to check + whether an instance has already been created may result in multiple + instances being created. 2 @@ -2964,7 +2988,7 @@ class Singleton { private static Singleton instance = null; public static Singleton getInstance() { synchronized(Singleton.class) { - return new Singleton(); + return new Singleton(); // this should be assigned to the field } } } diff --git a/pmd-java/src/main/resources/rulesets/java/quickstart.xml b/pmd-java/src/main/resources/rulesets/java/quickstart.xml index b1b89a532b..cad8a8a2eb 100644 --- a/pmd-java/src/main/resources/rulesets/java/quickstart.xml +++ b/pmd-java/src/main/resources/rulesets/java/quickstart.xml @@ -27,6 +27,7 @@ + @@ -90,7 +91,7 @@ - + @@ -205,7 +206,7 @@ - + diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/cli/CLITest.java b/pmd-java/src/test/java/net/sourceforge/pmd/cli/CLITest.java index 3e82902345..2fc217381d 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/cli/CLITest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/cli/CLITest.java @@ -7,7 +7,6 @@ package net.sourceforge.pmd.cli; import static org.junit.Assert.assertTrue; import java.io.File; -import java.io.IOException; import java.util.regex.Pattern; import org.junit.Assert; @@ -39,7 +38,7 @@ public class CLITest extends BaseCLITest { } @Test - public void changeJavaVersion() throws IOException { + public void changeJavaVersion() { String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "category/java/design.xml", "-version", "1.5", "-language", "java", "-debug", }; String resultFilename = runTest(args, "chgJavaVersion"); @@ -54,14 +53,14 @@ public class CLITest extends BaseCLITest { } @Test - public void exitStatusWithViolations() throws IOException { + public void exitStatusWithViolations() { String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "category/java/errorprone.xml", }; String resultFilename = runTest(args, "exitStatusWithViolations", 4); assertTrue(FileUtil.findPatternInFile(new File(resultFilename), "Avoid empty if")); } @Test - public void exitStatusWithViolationsAndWithoutFailOnViolations() throws IOException { + public void exitStatusWithViolationsAndWithoutFailOnViolations() { String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "category/java/errorprone.xml", "-failOnViolation", "false", }; String resultFilename = runTest(args, "exitStatusWithViolationsAndWithoutFailOnViolations", 0); assertTrue(FileUtil.findPatternInFile(new File(resultFilename), "Avoid empty if")); @@ -71,7 +70,7 @@ public class CLITest extends BaseCLITest { * See https://sourceforge.net/p/pmd/bugs/1231/ */ @Test - public void testWrongRuleset() throws Exception { + public void testWrongRuleset() { String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "category/java/designn.xml", }; String filename = TEST_OUPUT_DIRECTORY + "testWrongRuleset.txt"; createTestOutputFile(filename); @@ -85,7 +84,7 @@ public class CLITest extends BaseCLITest { * See https://sourceforge.net/p/pmd/bugs/1231/ */ @Test - public void testWrongRulesetWithRulename() throws Exception { + public void testWrongRulesetWithRulename() { String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "category/java/designn.xml/UseCollectionIsEmpty", }; String filename = TEST_OUPUT_DIRECTORY + "testWrongRuleset.txt"; createTestOutputFile(filename); @@ -99,7 +98,7 @@ public class CLITest extends BaseCLITest { * See https://sourceforge.net/p/pmd/bugs/1231/ */ @Test - public void testWrongRulename() throws Exception { + public void testWrongRulename() { String[] args = { "-d", SOURCE_FOLDER, "-f", "text", "-R", "category/java/design.xml/ThisRuleDoesNotExist", }; String filename = TEST_OUPUT_DIRECTORY + "testWrongRuleset.txt"; createTestOutputFile(filename); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnit5TestShouldBePackagePrivateTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnit5TestShouldBePackagePrivateTest.java new file mode 100644 index 0000000000..5d56479c58 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/JUnit5TestShouldBePackagePrivateTest.java @@ -0,0 +1,11 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.bestpractices; + +import net.sourceforge.pmd.testframework.PmdRuleTst; + +public class JUnit5TestShouldBePackagePrivateTest extends PmdRuleTst { + // no additional unit tests +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryimport/package1/U.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryimport/package1/U.java new file mode 100644 index 0000000000..902d084b08 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryimport/package1/U.java @@ -0,0 +1,13 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codestyle.unnecessaryimport.package1; + +import net.sourceforge.pmd.lang.java.rule.codestyle.unnecessaryimport.package2.*; // SUPPRESS CHECKSTYLE needed for test case + +public class U { + private void g() { + String k = C.V; + } +} diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryimport/package2/C.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryimport/package2/C.java new file mode 100644 index 0000000000..19710af874 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/codestyle/unnecessaryimport/package2/C.java @@ -0,0 +1,11 @@ +/* + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ + +package net.sourceforge.pmd.lang.java.rule.codestyle.unnecessaryimport.package2; + +public class C { + private C() { } + + public static final String V = ""; +} diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningLoopVariables.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningLoopVariables.xml index b39cd59870..82887e91a2 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningLoopVariables.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningLoopVariables.xml @@ -727,4 +727,58 @@ public class Foo { } ]]> + + + Consider also default methods in interface + 1 + 5 + + + + + Consider also classes in interface + 1 + 6 + + + + + Consider also anonymous classes + 1 + 7 + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningParameters.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningParameters.xml index c639198e7e..5b8c6cb046 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningParameters.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AvoidReassigningParameters.xml @@ -4,9 +4,28 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd"> + + example + 1 + 3 + + + reassigned parameter, bad 1 + 3 instance variable and parameter have same name 1 + 4 throws a stacktrace 1 + 4 postfix increment in array dereference is bad 1 + 3 assignment to array 1 + 4 The rule should also detect parameter reassignment in constructors (at least to help young programmers still learning java basic) - 3 + 2 + 3,5 parameter name starting with "this" or "super" should still be flagged 2 + 3,4 + + + + #3254 AvoidReassigningParameters reports wrong line numbers + 1 + 3 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnit5TestShouldBePackagePrivate.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnit5TestShouldBePackagePrivate.xml new file mode 100644 index 0000000000..9fdea7c27d --- /dev/null +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/JUnit5TestShouldBePackagePrivate.xml @@ -0,0 +1,132 @@ + + + + + Public modifier is not necessary on a test method nor on the class + 2 + 3,5 + + + + + Package private modifiers are what is required + 0 + + + + + Private method modifiers should be reported by rule 'JUnit5TestNoPrivateModifier' and ignored by rule 'JUnit5TestShouldBePackagePrivate' + 0 + + + + + Private modifiers for inner classes should be reported by rule 'JUnit5TestNoPrivateModifier' and ignored by rule 'JUnit5TestShouldBePackagePrivate' + 0 + + + + + Public modifier is allowed on an abstract test classes + 0 + + + + + Public modifier is allowed on test interfaces + 0 + + + + + Public and protected modifiers on all JUnit5 test types should be rejected + 5 + 8,10,13,19,23 + + + + + Public JUnit4 tests are not flagged + 0 + + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/LiteralsFirstInComparisons.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/LiteralsFirstInComparisons.xml index 903bb45279..31a83b3547 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/LiteralsFirstInComparisons.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/LiteralsFirstInComparisons.xml @@ -370,4 +370,43 @@ public class Foo { } ]]> + + #3236 [java] LiteralsFirstInComparisons should consider constant fields (cont'd) + 5 + 6,8,17,24,26 + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml index 1443f420bd..2db3da30a9 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml @@ -1697,6 +1697,33 @@ public class Outer { Inner inner = new Inner(); inner.innerUsedByOuterMethod(); } +} + ]]> + + + #1175 False positive with Junit 5 MethodSource + 0 + basenameKeyArguments() { + return Stream.of( + Arguments.of("simple", "simple"), + Arguments.of("simple", "one/two/many/simple"), + Arguments.of("simple", "//////an/////awful/key////simple") + ); + } + + @ParameterizedTest + @MethodSource("basenameKeyArguments") + void basenameKeyTest(final String expected, final String testString) { + assertEquals(expected, NetworkTable.basenameKey(testString)); + } + } ]]> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldDeclarationsShouldBeAtStartOfClass.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldDeclarationsShouldBeAtStartOfClass.xml index ad7b93cd55..fabc2fd19f 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldDeclarationsShouldBeAtStartOfClass.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/FieldDeclarationsShouldBeAtStartOfClass.xml @@ -129,6 +129,7 @@ public class MyClass { #1244 FieldDeclarationsShouldBeAtStartOfClass and anonymous classes, fail false 1 + 9 + + + + False negative with anon classes (1) + false + 3 + 4,5,7 + + + + + False negative with anon classes (2) + true + 2 + 4,7 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/LocalVariableCouldBeFinal.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/LocalVariableCouldBeFinal.xml index 3a7429e4c6..cc40e3140c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/LocalVariableCouldBeFinal.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/LocalVariableCouldBeFinal.xml @@ -208,6 +208,74 @@ public class Foo { System.out.println(i); } } +} + ]]> + + + + #3266 False negative with default methods in interfaces + 1 + 3 + + + + + #3266 False negative with class inside interface + 1 + 4 + + + + + #3266 False negative with anonymous classes + 2 + 5,11 + + + + + #3266 False negative with lambdas + 1 + 4 + { + int a = 0; + }; + } } ]]> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MethodArgumentCouldBeFinal.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MethodArgumentCouldBeFinal.xml index 1b3691333f..a875239855 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MethodArgumentCouldBeFinal.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/MethodArgumentCouldBeFinal.xml @@ -154,6 +154,42 @@ public class Foo { public Foo(int a) { this.field = a; } +} + ]]> + + + + #3265 False negative with default methods in interface + 2 + 2,7 + + + + + #3265 False negative with classes in interfaces + 2 + 3,6 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/OnlyOneReturn.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/OnlyOneReturn.xml index 41aa08a7ee..850f32a2a3 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/OnlyOneReturn.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/OnlyOneReturn.xml @@ -114,6 +114,27 @@ public class OnlyOneReturn { .map(list -> list.toArray(empty)); }).orElse(Try.success(empty)); } +} + ]]> + + + + False negative with anonymous class #3274 + 2 + 6,7 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryImport.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryImport.xml index 56d86c23cf..f94c1ff429 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryImport.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryImport.xml @@ -897,4 +897,20 @@ class NPEImport {} } ]]> + + + [java] UnnecessaryImport false positive for on-demand imports #2655 + 0 + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryLocalBeforeReturn.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryLocalBeforeReturn.xml index c1e5f21a5f..83cbf37e29 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryLocalBeforeReturn.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/codestyle/xml/UnnecessaryLocalBeforeReturn.xml @@ -269,6 +269,41 @@ public class ObjectCreator { final Object o = new Object(); // captured by the method ref return o::toString; } +} + ]]> + + + + FN with lambdas #3275 + 1 + 5 + c = () -> { String s = "1"; return s; }; + } +} + ]]> + + + + FN with anonymous classes #3275 + 1 + 8 + c = new Callable<>() { + public String call() { + String s = "1"; + return s; + } + }; + } } ]]> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/DataClass.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/DataClass.xml index f921a09b64..dffd36994c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/DataClass.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/design/xml/DataClass.xml @@ -220,4 +220,28 @@ public class Foo { } ]]> + + Example from the documentation + 1 + + The class 'DataClass' is suspected to be a Data Class (WOC=0.000%, NOPA=3, NOAM=1, WMC=1) + + + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/AvoidFieldNameMatchingTypeName.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/AvoidFieldNameMatchingTypeName.xml index 3be3e6d7dc..92dcef5758 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/AvoidFieldNameMatchingTypeName.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/AvoidFieldNameMatchingTypeName.xml @@ -54,6 +54,23 @@ public class Foo { + + + + false negative with fields in interfaces and nested classes + 2 + 4,7 + { return null; }; + + class Inner { + int inner; + } } ]]> diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/CompareObjectsWithEquals.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/CompareObjectsWithEquals.xml index 813301e972..71ece07277 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/CompareObjectsWithEquals.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/CompareObjectsWithEquals.xml @@ -112,7 +112,7 @@ package net.sourceforge.pmd.lang.java.rule.errorprone.compareobjectswithequals; public class CompareObjectsWithEqualsSample { void array(int[] a, String[] b) { - if (a[1] == b[1]) {} // int == String - this comparison doesn't make sense + if (a[1] == b[1]) {} // int == String - this comparison doesn't make sense (and doesn't compile...) } void array2(int[] c, int[] d) { if (c[1] == d[1]) {} @@ -365,4 +365,77 @@ public class EnumTest { ]]> + + static constant #3205 + 0 + + + + + static constant in other class #3205 + 0 + + + + constant field on some object #3205 + 0 + + + + constant field on some object, more complicated expr #3205 + 0 + + + + Property typesThatCompareByReference #3110 + java.lang.String + 0 + + + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ConstructorCallsOverridableMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ConstructorCallsOverridableMethod.xml index 204bc03c22..915a3d6326 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ConstructorCallsOverridableMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/ConstructorCallsOverridableMethod.xml @@ -282,6 +282,25 @@ public class Foo { } public void bar(boolean b) {} +} + ]]> + + + + IndexOutOfBoundsException with annotation + 0 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml index 4f95dab5b5..94c29dc23a 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/errorprone/xml/InvalidLogMessageFormat.xml @@ -968,4 +968,34 @@ class TestInvalidLogMessageFormat { } ]]> + + #2642 [java] InvalidLogMessageFormat throws IndexOutOfBoundsException with SLF4J and a StringBuilder variable set using var + 0 + + diff --git a/pmd-javascript/pom.xml b/pmd-javascript/pom.xml index 589a819970..534a496f49 100644 --- a/pmd-javascript/pom.xml +++ b/pmd-javascript/pom.xml @@ -11,6 +11,10 @@ ../ + + 8 + + @@ -78,6 +82,7 @@ org.mozilla rhino + 1.7.13 commons-io diff --git a/pmd-javascript/src/test/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParserTest.java b/pmd-javascript/src/test/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParserTest.java index b4ee5913cf..f6fe15ce3f 100644 --- a/pmd-javascript/src/test/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParserTest.java +++ b/pmd-javascript/src/test/java/net/sourceforge/pmd/lang/ecmascript/ast/EcmascriptParserTest.java @@ -6,6 +6,7 @@ package net.sourceforge.pmd.lang.ecmascript.ast; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.Reader; @@ -181,4 +182,13 @@ public class EcmascriptParserTest extends EcmascriptParserTestBase { ASTAssignment infix = rootNode.getFirstDescendantOfType(ASTAssignment.class); assertEquals("^=", infix.getImage()); } + + /** + * [javascript] Failing with OutOfMemoryError parsing a Javascript file #2081 + */ + @Test(timeout = 5000L) + public void shouldNotFailWithOutOfMemory() { + ASTAstRoot rootNode = js.parse("(``\n);"); + assertNotNull(rootNode); + } } diff --git a/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/ecmascript/ast/testdata/jquery-selector.txt b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/ecmascript/ast/testdata/jquery-selector.txt index 92588d6387..5ddb5321df 100644 --- a/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/ecmascript/ast/testdata/jquery-selector.txt +++ b/pmd-javascript/src/test/resources/net/sourceforge/pmd/lang/ecmascript/ast/testdata/jquery-selector.txt @@ -1,4 +1,5 @@ +- AstRoot + +- Comment +- EmptyStatement +- EmptyStatement +- EmptyStatement @@ -9,6 +10,7 @@ +- EmptyStatement +- EmptyStatement +- EmptyStatement + +- Comment +- EmptyStatement +- EmptyStatement +- EmptyStatement @@ -338,6 +340,7 @@ | | +- IfStatement | | | +- Name | | | +- Scope + | | | +- Comment | | | +- ReturnStatement | | | +- Name | | +- ReturnStatement @@ -451,6 +454,7 @@ | | +- InfixExpression | | +- Name | | +- ArrayLiteral + | +- Comment | +- IfStatement | | +- InfixExpression | | | +- InfixExpression @@ -491,6 +495,8 @@ | | +- IfStatement | | +- Name | | +- Scope + | | +- Comment + | | +- Comment | | +- IfStatement | | | +- InfixExpression | | | | +- InfixExpression @@ -505,6 +511,7 @@ | | | | | +- Name | | | | +- Name | | | +- Scope + | | | +- Comment | | | +- IfStatement | | | +- ParenthesizedExpression | | | | +- Assignment @@ -513,59 +520,62 @@ | | | | +- Name | | | | +- NumberLiteral | | | +- Scope + | | | | +- Comment | | | | +- IfStatement - | | | | +- InfixExpression - | | | | | +- Name - | | | | | +- NumberLiteral - | | | | +- Scope - | | | | | +- IfStatement - | | | | | | +- ParenthesizedExpression - | | | | | | | +- Assignment - | | | | | | | +- Name - | | | | | | | +- FunctionCall - | | | | | | | +- PropertyGet - | | | | | | | | +- Name - | | | | | | | | +- Name - | | | | | | | +- Name - | | | | | | +- Scope - | | | | | | +- ExpressionStatement - | | | | | | +- FunctionCall - | | | | | | +- PropertyGet - | | | | | | | +- Name - | | | | | | | +- Name - | | | | | | +- Name - | | | | | | +- Name - | | | | | +- ReturnStatement - | | | | | +- Name - | | | | +- Scope - | | | | +- IfStatement - | | | | +- InfixExpression - | | | | | +- Name - | | | | | +- InfixExpression - | | | | | +- ParenthesizedExpression - | | | | | | +- Assignment - | | | | | | +- Name - | | | | | | +- FunctionCall - | | | | | | +- PropertyGet - | | | | | | | +- Name - | | | | | | | +- Name - | | | | | | +- Name - | | | | | +- FunctionCall - | | | | | +- PropertyGet - | | | | | | +- Name - | | | | | | +- Name - | | | | | +- Name - | | | | | +- Name - | | | | +- Scope - | | | | +- ExpressionStatement - | | | | | +- FunctionCall - | | | | | +- PropertyGet - | | | | | | +- Name - | | | | | | +- Name - | | | | | +- Name - | | | | | +- Name - | | | | +- ReturnStatement - | | | | +- Name + | | | | | +- InfixExpression + | | | | | | +- Name + | | | | | | +- NumberLiteral + | | | | | +- Scope + | | | | | | +- IfStatement + | | | | | | | +- ParenthesizedExpression + | | | | | | | | +- Assignment + | | | | | | | | +- Name + | | | | | | | | +- FunctionCall + | | | | | | | | +- PropertyGet + | | | | | | | | | +- Name + | | | | | | | | | +- Name + | | | | | | | | +- Name + | | | | | | | +- Scope + | | | | | | | +- ExpressionStatement + | | | | | | | +- FunctionCall + | | | | | | | +- PropertyGet + | | | | | | | | +- Name + | | | | | | | | +- Name + | | | | | | | +- Name + | | | | | | | +- Name + | | | | | | +- ReturnStatement + | | | | | | | +- Name + | | | | | | +- Comment + | | | | | +- Scope + | | | | | +- IfStatement + | | | | | +- InfixExpression + | | | | | | +- Name + | | | | | | +- InfixExpression + | | | | | | +- ParenthesizedExpression + | | | | | | | +- Assignment + | | | | | | | +- Name + | | | | | | | +- FunctionCall + | | | | | | | +- PropertyGet + | | | | | | | | +- Name + | | | | | | | | +- Name + | | | | | | | +- Name + | | | | | | +- FunctionCall + | | | | | | +- PropertyGet + | | | | | | | +- Name + | | | | | | | +- Name + | | | | | | +- Name + | | | | | | +- Name + | | | | | +- Scope + | | | | | +- ExpressionStatement + | | | | | | +- FunctionCall + | | | | | | +- PropertyGet + | | | | | | | +- Name + | | | | | | | +- Name + | | | | | | +- Name + | | | | | | +- Name + | | | | | +- ReturnStatement + | | | | | +- Name + | | | | +- Comment | | | +- IfStatement | | | +- ElementGet | | | | +- Name @@ -583,7 +593,8 @@ | | | | | | +- Name | | | | | +- Name | | | | +- ReturnStatement - | | | | +- Name + | | | | | +- Name + | | | | +- Comment | | | +- IfStatement | | | +- InfixExpression | | | | +- ParenthesizedExpression @@ -636,6 +647,13 @@ | | | +- Assignment | | | +- Name | | | +- Name + | | +- Comment + | | +- Comment + | | +- Comment + | | +- Comment + | | +- Comment + | | +- Comment + | | +- Comment | | +- IfStatement | | | +- InfixExpression | | | | +- InfixExpression @@ -654,6 +672,7 @@ | | | | | +- Name | | | | +- Name | | | +- Scope + | | | +- Comment | | | +- ExpressionStatement | | | | +- Assignment | | | | +- Name @@ -670,6 +689,8 @@ | | | | | +- Name | | | | | +- Name | | | | +- Name + | | | +- Comment + | | | +- Comment | | | +- IfStatement | | | | +- InfixExpression | | | | | +- InfixExpression @@ -680,6 +701,7 @@ | | | | | +- Name | | | | | +- Name | | | | +- Scope + | | | | +- Comment | | | | +- IfStatement | | | | +- ParenthesizedExpression | | | | | +- Assignment @@ -800,6 +822,7 @@ | +- Name | +- Name | +- Name + +- Comment +- FunctionNode | +- Name | +- Block @@ -812,6 +835,7 @@ | | +- Name | | +- Name | | +- Block + | | +- Comment | | +- IfStatement | | | +- InfixExpression | | | | +- FunctionCall @@ -825,6 +849,7 @@ | | | | +- Name | | | | +- Name | | | +- Scope + | | | +- Comment | | | +- ExpressionStatement | | | +- UnaryExpression | | | +- ElementGet @@ -844,6 +869,7 @@ | | +- Name | +- ReturnStatement | +- Name + +- Comment +- FunctionNode | +- Name | +- Name @@ -856,6 +882,7 @@ | | +- KeywordLiteral | +- ReturnStatement | +- Name + +- Comment +- FunctionNode | +- Name | +- Name @@ -875,6 +902,7 @@ | | +- Name | | +- Name | +- Name + +- Comment +- FunctionNode | +- Name | +- Name @@ -900,19 +928,31 @@ | | +- Name | | +- Name | +- Name + +- Comment +- FunctionNode | +- Name | +- Name | +- Block + | +- Comment | +- ReturnStatement | +- FunctionNode | +- Name | +- Block + | +- Comment + | +- Comment + | +- Comment | +- IfStatement | | +- InfixExpression | | | +- StringLiteral | | | +- Name | | +- Scope + | | | +- Comment + | | | +- Comment + | | | +- Comment + | | | +- Comment + | | | +- Comment + | | | +- Comment + | | | +- Comment | | | +- IfStatement | | | | +- InfixExpression | | | | | +- PropertyGet @@ -924,6 +964,7 @@ | | | | | | +- Name | | | | | +- KeywordLiteral | | | | +- Scope + | | | | +- Comment | | | | +- IfStatement | | | | | +- InfixExpression | | | | | | +- StringLiteral @@ -971,11 +1012,14 @@ | | | | | +- Name | | | | +- Name | | | +- ReturnStatement - | | | +- InfixExpression - | | | +- PropertyGet - | | | | +- Name - | | | | +- Name - | | | +- Name + | | | | +- InfixExpression + | | | | +- PropertyGet + | | | | | +- Name + | | | | | +- Name + | | | | +- Name + | | | +- Comment + | | | +- Comment + | | | +- Comment | | +- IfStatement | | +- InfixExpression | | | +- StringLiteral @@ -989,6 +1033,7 @@ | | +- Name | +- ReturnStatement | +- KeywordLiteral + +- Comment +- FunctionNode | +- Name | +- Name @@ -1028,6 +1073,7 @@ | | +- PropertyGet | | +- Name | | +- Name + | +- Comment | +- WhileLoop | +- UnaryExpression | | +- Name @@ -1056,6 +1102,7 @@ | +- ElementGet | +- Name | +- Name + +- Comment +- FunctionNode | +- Name | +- Name @@ -1071,6 +1118,7 @@ | | | +- Name | | +- StringLiteral | +- Name + +- Comment +- FunctionNode | +- Name | +- Name @@ -1088,6 +1136,11 @@ | | | | +- Name | | | +- Name | | +- Name + | +- Comment + | +- Comment + | +- Comment + | +- Comment + | +- Comment | +- IfStatement | | +- InfixExpression | | | +- InfixExpression @@ -1119,6 +1172,12 @@ | | | +- Name | | | +- Name | | +- Name + | +- Comment + | +- Comment + | +- Comment + | +- Comment + | +- Comment + | +- Comment | +- IfStatement | +- InfixExpression | | +- InfixExpression @@ -1137,6 +1196,7 @@ | | | +- Name | | +- Name | +- Scope + | +- Comment | +- ExpressionStatement | +- FunctionCall | +- PropertyGet @@ -1288,11 +1348,12 @@ | | | | +- StringLiteral | | | +- Scope | | | | +- ReturnStatement - | | | | +- FunctionCall - | | | | +- PropertyGet - | | | | | +- Name - | | | | | +- Name - | | | | +- Name + | | | | | +- FunctionCall + | | | | | +- PropertyGet + | | | | | | +- Name + | | | | | | +- Name + | | | | | +- Name + | | | | +- Comment | | | +- Scope | | | +- ReturnStatement | | | +- FunctionCall @@ -1376,6 +1437,7 @@ | | | | | +- Name | | | | +- Name | | | | +- Name + | | | +- Comment | | | +- ExpressionStatement | | | | +- Assignment | | | | +- ElementGet @@ -1431,6 +1493,7 @@ | | | +- FunctionNode | | | +- Name | | | +- Block + | | | +- Comment | | | +- ExpressionStatement | | | | +- Assignment | | | | +- ElementGet @@ -1454,6 +1517,7 @@ | | | | | | +- NumberLiteral | | | | | +- StringLiteral | | | | +- Scope + | | | | | +- Comment | | | | | +- IfStatement | | | | | | +- UnaryExpression | | | | | | | +- ElementGet @@ -1502,26 +1566,27 @@ | | | | | | | +- NumberLiteral | | | | | | +- StringLiteral | | | | | +- ExpressionStatement - | | | | | +- Assignment - | | | | | +- ElementGet - | | | | | | +- Name - | | | | | | +- NumberLiteral - | | | | | +- UnaryExpression - | | | | | +- ParenthesizedExpression - | | | | | +- InfixExpression - | | | | | +- ParenthesizedExpression - | | | | | | +- InfixExpression - | | | | | | +- ElementGet - | | | | | | | +- Name - | | | | | | | +- NumberLiteral - | | | | | | +- ElementGet - | | | | | | +- Name - | | | | | | +- NumberLiteral - | | | | | +- InfixExpression - | | | | | +- ElementGet - | | | | | | +- Name - | | | | | | +- NumberLiteral - | | | | | +- StringLiteral + | | | | | | +- Assignment + | | | | | | +- ElementGet + | | | | | | | +- Name + | | | | | | | +- NumberLiteral + | | | | | | +- UnaryExpression + | | | | | | +- ParenthesizedExpression + | | | | | | +- InfixExpression + | | | | | | +- ParenthesizedExpression + | | | | | | | +- InfixExpression + | | | | | | | +- ElementGet + | | | | | | | | +- Name + | | | | | | | | +- NumberLiteral + | | | | | | | +- ElementGet + | | | | | | | +- Name + | | | | | | | +- NumberLiteral + | | | | | | +- InfixExpression + | | | | | | +- ElementGet + | | | | | | | +- Name + | | | | | | | +- NumberLiteral + | | | | | | +- StringLiteral + | | | | | +- Comment | | | | +- IfStatement | | | | +- ElementGet | | | | | +- Name @@ -1572,19 +1637,20 @@ | | | | +- NumberLiteral | | | +- Scope | | | | +- ExpressionStatement - | | | | +- Assignment - | | | | +- ElementGet - | | | | | +- Name - | | | | | +- NumberLiteral - | | | | +- InfixExpression - | | | | +- ElementGet - | | | | | +- Name - | | | | | +- NumberLiteral - | | | | +- InfixExpression - | | | | +- ElementGet - | | | | | +- Name - | | | | | +- NumberLiteral - | | | | +- StringLiteral + | | | | | +- Assignment + | | | | | +- ElementGet + | | | | | | +- Name + | | | | | | +- NumberLiteral + | | | | | +- InfixExpression + | | | | | +- ElementGet + | | | | | | +- Name + | | | | | | +- NumberLiteral + | | | | | +- InfixExpression + | | | | | +- ElementGet + | | | | | | +- Name + | | | | | | +- NumberLiteral + | | | | | +- StringLiteral + | | | | +- Comment | | | +- IfStatement | | | +- InfixExpression | | | | +- Name @@ -1620,6 +1686,7 @@ | | | | +- Name | | | | +- Name | | | +- Scope + | | | +- Comment | | | +- ExpressionStatement | | | | +- Assignment | | | | +- ElementGet @@ -2046,6 +2113,7 @@ | | | +- IfStatement | | | +- Name | | | +- Scope + | | | +- Comment | | | +- IfStatement | | | | +- Name | | | | +- Scope @@ -2079,6 +2147,7 @@ | | | | | | +- Scope | | | | | | +- ReturnStatement | | | | | | +- KeywordLiteral + | | | | | +- Comment | | | | | +- ExpressionStatement | | | | | +- Assignment | | | | | +- Name @@ -2106,11 +2175,13 @@ | | | | +- PropertyGet | | | | +- Name | | | | +- Name + | | | +- Comment | | | +- IfStatement | | | | +- InfixExpression | | | | | +- Name | | | | | +- Name | | | | +- Scope + | | | | | +- Comment | | | | | +- ExpressionStatement | | | | | | +- Assignment | | | | | | +- Name @@ -2187,6 +2258,7 @@ | | | | | | +- Name | | | | | | +- Name | | | | | +- Scope + | | | | | +- Comment | | | | | +- IfStatement | | | | | +- InfixExpression | | | | | | +- InfixExpression @@ -2212,6 +2284,7 @@ | | | | | | +- Name | | | | | +- BreakStatement | | | | +- Scope + | | | | +- Comment | | | | +- IfStatement | | | | | +- Name | | | | | +- Scope @@ -2257,6 +2330,7 @@ | | | | | +- Name | | | | | +- KeywordLiteral | | | | +- Scope + | | | | +- Comment | | | | +- WhileLoop | | | | +- ParenthesizedExpression | | | | | +- Assignment @@ -2299,6 +2373,7 @@ | | | | | +- UnaryExpression | | | | | +- Name | | | | +- Scope + | | | | +- Comment | | | | +- IfStatement | | | | | +- Name | | | | | +- Scope @@ -2329,6 +2404,7 @@ | | | | | +- Name | | | | +- Scope | | | | +- BreakStatement + | | | +- Comment | | | +- ExpressionStatement | | | | +- Assignment | | | | +- Name @@ -2356,6 +2432,10 @@ | | +- Name | | +- Name | | +- Block + | | +- Comment + | | +- Comment + | | +- Comment + | | +- Comment | | +- VariableDeclaration | | | +- VariableInitializer | | | | +- Name @@ -2381,6 +2461,9 @@ | | | +- InfixExpression | | | +- StringLiteral | | | +- Name + | | +- Comment + | | +- Comment + | | +- Comment | | +- IfStatement | | | +- ElementGet | | | | +- Name @@ -2487,6 +2570,9 @@ | | +- FunctionNode | | +- Name | | +- Block + | | +- Comment + | | +- Comment + | | +- Comment | | +- VariableDeclaration | | | +- VariableInitializer | | | | +- Name @@ -2533,6 +2619,7 @@ | | | | +- PropertyGet | | | | +- Name | | | | +- Name + | | | +- Comment | | | +- WhileLoop | | | +- UnaryExpression | | | | +- Name @@ -2575,6 +2662,7 @@ | | | +- KeywordLiteral | | | +- Name | | | +- Name + | | +- Comment | | +- ExpressionStatement | | | +- Assignment | | | +- ElementGet @@ -2652,6 +2740,7 @@ | | +- FunctionNode | | +- Name | | +- Block + | | +- Comment | | +- IfStatement | | | +- UnaryExpression | | | | +- FunctionCall @@ -2830,6 +2919,8 @@ | | +- FunctionNode | | +- Name | | +- Block + | | +- Comment + | | +- Comment | | +- ReturnStatement | | +- InfixExpression | | +- ParenthesizedExpression @@ -2859,11 +2950,16 @@ | | +- FunctionNode | | +- Name | | +- Block + | | +- Comment + | | +- Comment + | | +- Comment + | | +- Comment | | +- IfStatement | | | +- PropertyGet | | | | +- Name | | | | +- Name | | | +- Scope + | | | +- Comment | | | +- ExpressionStatement | | | +- PropertyGet | | | +- PropertyGet @@ -2881,6 +2977,10 @@ | | +- FunctionNode | | +- Name | | +- Block + | | +- Comment + | | +- Comment + | | +- Comment + | | +- Comment | | +- ForLoop | | | +- Assignment | | | | +- Name @@ -3182,6 +3282,7 @@ | | +- Name | | +- Name | +- Name + +- Comment +- ForInLoop | +- Name | +- ObjectLiteral @@ -3231,6 +3332,7 @@ | +- FunctionCall | +- Name | +- Name + +- Comment +- FunctionNode | +- Name | +- Block @@ -3309,6 +3411,7 @@ | +- WhileLoop | | +- Name | | +- Scope + | | +- Comment | | +- IfStatement | | | +- InfixExpression | | | | +- UnaryExpression @@ -3325,6 +3428,7 @@ | | | +- IfStatement | | | | +- Name | | | | +- Scope + | | | | +- Comment | | | | +- ExpressionStatement | | | | +- Assignment | | | | +- Name @@ -3352,6 +3456,7 @@ | | | +- Assignment | | | +- Name | | | +- KeywordLiteral + | | +- Comment | | +- IfStatement | | | +- ParenthesizedExpression | | | | +- Assignment @@ -3468,6 +3573,9 @@ | | | +- Name | | +- Scope | | +- BreakStatement + | +- Comment + | +- Comment + | +- Comment | +- IfStatement | | +- Name | | +- Scope @@ -3606,6 +3714,7 @@ | | +- ArrayLiteral | | +- Name | | +- Name + | +- Comment | +- IfStatement | | +- Name | | +- Scope @@ -3702,6 +3811,7 @@ | | | | +- NumberLiteral | | | +- Name | | +- Scope + | | | +- Comment | | | +- ReturnStatement | | | +- ParenthesizedExpression | | | +- Assignment @@ -3712,12 +3822,14 @@ | | | +- Name | | | +- NumberLiteral | | +- Scope + | | +- Comment | | +- ExpressionStatement | | | +- Assignment | | | +- ElementGet | | | | +- Name | | | | +- Name | | | +- Name + | | +- Comment | | +- IfStatement | | +- ParenthesizedExpression | | | +- Assignment @@ -3985,6 +4097,8 @@ | +- IfStatement | | +- Name | | +- Scope + | | | +- Comment + | | | +- Comment | | | +- ExpressionStatement | | | | +- Assignment | | | | +- Name @@ -4000,6 +4114,7 @@ | | | | | +- Name | | | | +- ArrayLiteral | | | | +- Name + | | | +- Comment | | | +- ExpressionStatement | | | +- FunctionCall | | | +- Name @@ -4012,6 +4127,7 @@ | | +- Assignment | | +- Name | | +- Name + | +- Comment | +- IfStatement | | +- Name | | +- Scope @@ -4029,6 +4145,7 @@ | | | +- ArrayLiteral | | | +- Name | | | +- Name + | | +- Comment | | +- ExpressionStatement | | | +- Assignment | | | +- Name @@ -4074,6 +4191,7 @@ | | +- IfStatement | | | +- Name | | | +- Scope + | | | +- Comment | | | +- ExpressionStatement | | | | +- Assignment | | | | +- Name @@ -4096,6 +4214,7 @@ | | | | | +- Name | | | | | +- Name | | | | +- Scope + | | | | +- Comment | | | | +- ExpressionStatement | | | | +- FunctionCall | | | | +- PropertyGet @@ -4316,6 +4435,7 @@ | | | +- Name | | | +- Name | | | +- Name + | | +- Comment | | +- ExpressionStatement | | | +- Assignment | | | +- Name @@ -4376,11 +4496,13 @@ | | | | +- Name | | | | +- Name | | | +- Name + | | +- Comment | | +- IfStatement | | | +- ElementGet | | | | +- Name | | | | +- Name | | | +- Scope + | | | +- Comment | | | +- ExpressionStatement | | | | +- Assignment | | | | +- Name @@ -4583,6 +4705,10 @@ | | +- IfStatement | | | +- Name | | | +- Scope + | | | +- Comment + | | | +- Comment + | | | +- Comment + | | | +- Comment | | | +- ExpressionStatement | | | +- Assignment | | | +- Name @@ -4615,6 +4741,10 @@ | | | | | +- Assignment | | | | | +- Name | | | | | +- NumberLiteral + | | | | +- Comment + | | | | +- Comment + | | | | +- Comment + | | | | +- Comment | | | | +- IfStatement | | | | | +- InfixExpression | | | | | | +- UnaryExpression @@ -4670,6 +4800,7 @@ | | | +- IfStatement | | | +- Name | | | +- Scope + | | | +- Comment | | | +- IfStatement | | | | +- ParenthesizedExpression | | | | | +- Assignment @@ -4691,10 +4822,19 @@ | | | | +- Name | | | | +- Name | | | +- Name + | | +- Comment + | | +- Comment | | +- ExpressionStatement | | | +- Assignment | | | +- Name | | | +- Name + | | +- Comment + | | +- Comment + | | +- Comment + | | +- Comment + | | +- Comment + | | +- Comment + | | +- Comment | | +- IfStatement | | | +- InfixExpression | | | | +- Name @@ -4725,6 +4865,7 @@ | | | +- IfStatement | | | | +- Name | | | | +- Scope + | | | | +- Comment | | | | +- IfStatement | | | | | +- InfixExpression | | | | | | +- Name @@ -4768,6 +4909,7 @@ | | | | | +- Name | | | | +- Name | | | | +- Name + | | | +- Comment | | | +- IfStatement | | | +- InfixExpression | | | | +- Name @@ -4840,6 +4982,7 @@ | | +- UnaryExpression | | | +- Name | | +- Scope + | | +- Comment | | +- IfStatement | | | +- UnaryExpression | | | | +- Name @@ -4886,6 +5029,7 @@ | | | | +- Name | | | | +- Name | | | +- Name + | | +- Comment | | +- ExpressionStatement | | | +- Assignment | | | +- Name @@ -4896,6 +5040,7 @@ | | | +- Name | | | +- Name | | | +- Name + | | +- Comment | | +- ExpressionStatement | | +- Assignment | | +- PropertyGet @@ -4904,6 +5049,7 @@ | | +- Name | +- ReturnStatement | +- Name + +- Comment +- FunctionNode | +- Name | +- Name @@ -4951,6 +5097,8 @@ | | +- InfixExpression | | +- Name | | +- ArrayLiteral + | +- Comment + | +- Comment | +- IfStatement | | +- InfixExpression | | | +- PropertyGet @@ -4958,6 +5106,7 @@ | | | | +- Name | | | +- NumberLiteral | | +- Scope + | | +- Comment | | +- ExpressionStatement | | | +- Assignment | | | +- Name @@ -5038,7 +5187,8 @@ | | | | | +- Name | | | | +- Scope | | | | | +- ReturnStatement - | | | | | +- Name + | | | | | | +- Name + | | | | | +- Comment | | | | +- IfStatement | | | | +- Name | | | | +- Scope @@ -5088,6 +5238,7 @@ | | | +- ElementGet | | | +- Name | | | +- Name + | | +- Comment | | +- IfStatement | | | +- ElementGet | | | | +- PropertyGet @@ -5111,6 +5262,7 @@ | | | | +- Name | | | +- Name | | +- Scope + | | +- Comment | | +- IfStatement | | +- ParenthesizedExpression | | | +- Assignment @@ -5145,6 +5297,7 @@ | | | | +- Name | | | +- Name | | +- Scope + | | +- Comment | | +- ExpressionStatement | | | +- FunctionCall | | | +- PropertyGet @@ -5208,6 +5361,7 @@ | | +- Name | +- ReturnStatement | +- Name + +- Comment +- ExpressionStatement | +- FunctionCall | +- Name diff --git a/pom.xml b/pom.xml index 068c80b77c..fd6ae15cbf 100644 --- a/pom.xml +++ b/pom.xml @@ -92,8 +92,8 @@ 5.0 3.0.0-M5 - 8.30 - 3.1.1 + 8.42 + 3.1.2 3.14.0 1.10.9 3.2.0 @@ -105,7 +105,7 @@ -Xmx512m -Dfile.encoding=${project.build.sourceEncoding} - 11 + 12 6.27.0 @@ -687,11 +687,6 @@ 9.1.0.8 dom - - org.mozilla - rhino - 1.7.7.2 - net.java.dev.javacc javacc @@ -1066,7 +1061,6 @@ pmd-groovy pmd-lua pmd-java - pmd-javascript pmd-jsp pmd-kotlin pmd-matlab @@ -1086,6 +1080,7 @@ pmd-apex-jorje pmd-apex pmd-java8 + pmd-javascript pmd-doc pmd-lang-test pmd-scala