diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..845c53e5 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,27 @@ +version: 2 +updates: +- package-ecosystem: maven + directory: "/" + schedule: + interval: daily + time: "04:00" + open-pull-requests-limit: 10 + ignore: + - dependency-name: org.sonarsource.parent:parent + versions: + - "55" + - 57.0.19 + - dependency-name: net.sourceforge.pmd:pmd-java + versions: + - 6.32.0 + - 6.33.0 + - dependency-name: org.sonarsource.java:java-frontend + versions: + - 6.11.0.24617 + - 6.14.0.25463 + - dependency-name: org.sonarsource.orchestrator:sonar-orchestrator + versions: + - 3.35.0.2707 + - dependency-name: org.sonarsource.sonarqube:sonar-plugin-api + versions: + - 8.6.1.40680 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..48136fc9 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,112 @@ +name: Build and test + +on: + push: + paths-ignore: + - '.github/**' + - '**/*.md' + tags-ignore: + - '**' + branches: [ master ] + pull_request: + branches: [ master ] + workflow_dispatch: + inputs: + skipTests: + description: "Skip unit tests?" + required: true + default: false + type: boolean + deploySnapshot: + description: "Deploy snapshot to Maven Central?" + required: true + default: false + type: boolean + runIntegrationTests: + description: "Run integration tests?" + required: true + default: false + type: boolean + +defaults: + run: + shell: bash + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 20 + env: + # Respect manual input for skipping unit tests (no effect for push/PR where inputs are empty) + SKIP_TESTS: ${{ github.event.inputs.skipTests }} + steps: + - uses: actions/checkout@v5 + + - name: Set Release version env variable + run: | + echo "TAG_NAME=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV + + - name: Set branch name env variable + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + BRANCH_NAME="${{ github.head_ref }}" + else + BRANCH_NAME="${GITHUB_REF#refs/heads/}" + fi + + if [ "$BRANCH_NAME" = "master" ]; then + echo "ARTIFACT_SUFFIX=" >> $GITHUB_ENV + else + # Sanitize branch name by replacing invalid characters with dashes + SANITIZED_BRANCH=$(echo "$BRANCH_NAME" | sed 's/[\/\\:*?"<>|]/-/g') + echo "ARTIFACT_SUFFIX=-$SANITIZED_BRANCH" >> $GITHUB_ENV + fi + + # only build SNAPSHOTS, use release for tagged releases + - name: Check if tag contains SNAPSHOT + if: contains(env.TAG_NAME, 'SNAPSHOT') != true + run: | + echo "Tag '$TAG_NAME' does not contain 'SNAPSHOT', failing build." + exit 1 + + - name: Set up JDK 17 + uses: actions/setup-java@v5 + with: + distribution: 'zulu' + java-version: 17 + cache: 'maven' + server-id: central + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + gpg-passphrase: MAVEN_GPG_PASSPHRASE + gpg-private-key: ${{ secrets.GPG_SIGNING_KEY }} + + - name: Build package with maven + run: | + ./mvnw --batch-mode $(if [ "$SKIP_TESTS" = "true" ]; then echo "-DskipTests"; fi) clean package + + - name: Run integration tests (manual trigger only) + if: github.event_name == 'workflow_dispatch' && github.event.inputs.runIntegrationTests == 'true' + run: | + ./mvnw --batch-mode -pl integration-test -am clean verify + + - name: Deploy SNAPSHOT to maven central + if: (github.event_name == 'push' && github.ref == 'refs/heads/master') || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploySnapshot == 'true') + env: + MAVEN_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_SIGNING_PASSWORD }} + run: | + ./mvnw --batch-mode $(if [ "$SKIP_TESTS" = "true" ]; then echo "-DskipTests"; fi) clean deploy + + - name: Upload sonar-pmd-plugin jar + uses: actions/upload-artifact@v4 + with: + name: sonar-pmd-plugin-${{ env.TAG_NAME }}${{ env.ARTIFACT_SUFFIX }} + path: sonar-pmd-plugin/target/sonar-pmd-plugin-*.jar + + - name: Upload sonar-pmd-lib jar + uses: actions/upload-artifact@v4 + with: + name: sonar-pmd-lib-${{ env.TAG_NAME }}${{ env.ARTIFACT_SUFFIX }} + path: sonar-pmd-lib/target/sonar-pmd-lib-*.jar diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..13cac662 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,49 @@ +name: Release to Maven Central +run-name: Build ${{ github.ref_name }} by @${{ github.actor }} + +on: + release: + types: [ published ] + workflow_dispatch: + +defaults: + run: + shell: bash + +jobs: + release: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v5 + + - name: Set Release version env variable + run: | + echo "TAG_NAME=${{ github.event.release.tag_name }}" >> $GITHUB_ENV + + # if no tag exists, this is expected to fail + - name: Switch to git tag for release + run: | + git fetch --all --tags -f + git checkout tags/${{ env.TAG_NAME }} -b ${{ env.TAG_NAME }}-tmp-branch + + - name: Set up JDK 17 + uses: actions/setup-java@v5 + with: + distribution: 'zulu' + java-version: 17 + cache: 'maven' + server-id: central + server-username: MAVEN_USERNAME + server-password: MAVEN_PASSWORD + gpg-passphrase: MAVEN_GPG_PASSPHRASE + gpg-private-key: ${{ secrets.GPG_SIGNING_KEY }} + + - name: Deploy + env: + MAVEN_USERNAME: ${{ secrets.SONATYPE_USERNAME }} + MAVEN_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }} + MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_SIGNING_PASSWORD }} + run: | + ./mvnw --batch-mode -Drevision=${{ env.TAG_NAME }} -P release clean deploy + diff --git a/.gitignore b/.gitignore index a95e9ab7..b5dac6a1 100644 --- a/.gitignore +++ b/.gitignore @@ -27,3 +27,5 @@ Thumbs.db # Folder config file Desktop.ini .java-version + +.flattened-pom.xml diff --git a/.mvn/maven.config b/.mvn/maven.config new file mode 100644 index 00000000..438c5313 --- /dev/null +++ b/.mvn/maven.config @@ -0,0 +1 @@ +-Drevision=4.2.0-SNAPSHOT diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..48a56c99 --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,19 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +wrapperVersion=3.3.2 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 3e8bed38..00000000 --- a/.travis.yml +++ /dev/null @@ -1,34 +0,0 @@ -language: java -sudo: false - -addons: - sonarcloud: - organization: "jensgerdes-github" - token: - secure: "U299FqcJAMNfblrZF8R/ivqRk7KNdSOdcyWI4h5dgOLlQHj+HHrF2GJB2fOVeaB53snOkCycM/ZQgqTLlS1PU2NUca3TroNXj6jpNK1Erb/TXqFMKK+rmsN+hcxudDYGnQFIVnWy4lsg72jlK3Qvktt0XyfuYjMqQbsp3zwhlxw=" - -jdk: -- openjdk11 - -install: true -script: ./travis.sh -env: -- TEST=ci -- TEST=plugin SQ_VERSION=LATEST_RELEASE[6.7] SJ_VERSION=LATEST_RELEASE[5.0] -- TEST=plugin SQ_VERSION=LATEST_RELEASE[7.2] SJ_VERSION=LATEST_RELEASE[5] -- TEST=plugin SQ_VERSION=LATEST_RELEASE[7.8] SJ_VERSION=LATEST_RELEASE[5] -- TEST=plugin SQ_VERSION=LATEST_RELEASE[7.9] SJ_VERSION=DEV -- TEST=plugin SQ_VERSION=LATEST_RELEASE[8.1] SJ_VERSION=DEV -- TEST=plugin SQ_VERSION=DEV SJ_VERSION=DEV -- TEST=javadoc - -cache: - directories: - - '$HOME/.m2/repository' - - '$HOME/.sonar' - - '$HOME/jvm' - - '$HOME/maven' - -notifications: - email: - - jens@gerdes.digital diff --git a/CHANGELOG.md b/CHANGELOG.md index c4c7dd44..e3144614 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,159 @@ # Changelog -## [3.2.2-SNAPSHOT](https://github.com/jensgerdes/sonar-pmd/tree/master) (2019-04-17) -[Full Changelog](https://github.com/jensgerdes/sonar-pmd/compare/3.2.1...master) +[//]: # (## [4.3.0-SNAPSHOT](https://github.com/jborgers/sonar-pmd/tree/4.3.0-SNAPSHOT) (2025-xx-xx)) -None, yet. +[//]: # () +[//]: # ([Full Changelog](https://github.com/jborgers/sonar-pmd/compare/4.2.0..master)) + +[//]: # () +[//]: # (**Implemented highlights**) + +## [4.2.0](https://github.com/jborgers/sonar-pmd/tree/4.2.0) (2025-10-13) + +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/4.1.0..4.2.0) + +**Implemented highlights** +* Java 25 support +* Now PMD Java and Kotlin rules are available from 7.17.0 (292, up from 282), see details [pmd_release_notes_4.2.0.md](docs/pmd_release_notes_4.2.0.md) +* Activate Kotlin sensor +* Add params in sonar rules xml based on Java Rule properties +* Fix Analysis scope for main and test sources +* Adjust severity level for code-style category + +## [4.1.0](https://github.com/jborgers/sonar-pmd/tree/4.1.0) (2025-07-18) +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/4.0.3..4.1.0) + +**Implemented highlights** +* Now all current PMD Java rules are available (282, up from 206), see details [pmd_release_notes_4.1.0.md](docs/pmd_release_notes_4.1.0.md) +* Generate Sonar rules xml for the plugin directly from the PMD 7.15.0 rules xml: makes all Java rules available and up-to-date automatically +* Updated and non-deprecated the "PMD XPath Template Rule" (pmd:XPathRule) to create custom Java rules with powerful PMD7 XPath expressions +* Generate nicely formatted html descriptions from the PMD rule description markup +* Added `pmd` tag and category tag for each rule +* Added `has-sonar-alternative` tag for rules with known Sonar alternative (instead of making rules with alternatives `Deprecated`) +* Simplified release process by automation +* Maven release via Sonatype Central Portal + +## [4.0.3](https://github.com/jborgers/sonar-pmd/tree/4.0.3) (2025-06-06) + +Versions update release. + +**Implemented highlights** +* Include PMD 7.14.0 +* Updated minor dependencies +* Fix pom.xml revision tags in release + +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/4.0.2..4.0.3) + +**Implemented highlights** +* Remove the custom profile importer/exporter to support SonarQube Server 25.4 [#504](https://github.com/jborgers/sonar-pmd/issues/504) +* Add unused assignment rule [#505](https://github.com/jborgers/sonar-pmd/pull/505) +* Include PMD 7.13.0 + +## [4.0.2](https://github.com/jborgers/sonar-pmd/tree/4.0.2) (2025-06-06) + +Bugfix release to work with latest SonarQube releases. See [#508](https://github.com/jborgers/sonar-pmd/issues/508) and [#509](https://github.com/jborgers/sonar-pmd/issues/509). + +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/4.0.1..4.0.2) + +**Implemented highlights** +* Remove the custom profile importer/exporter to support SonarQube Server 25.4 [#504](https://github.com/jborgers/sonar-pmd/issues/504) +* Add unused assignment rule [#505](https://github.com/jborgers/sonar-pmd/pull/505) +* Include PMD 7.13.0 + +## [4.0.1](https://github.com/jborgers/sonar-pmd/tree/4.0.1) (2025-03-03) +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/4.0.0..4.0.1) + +**Implemented highlights** +* Fix supported java versions from 21 up to 24-preview [#499](https://github.com/jborgers/sonar-pmd/pull/499) +* Removed all junit tests, they have been moved or removed in PMD7 [#502](https://github.com/jborgers/sonar-pmd/pull/502) + +**Limitations** +* Not all PMD 7 rules are made available in Sonar, yet, see [#495](https://github.com/jborgers/sonar-pmd/issues/495), [#498](https://github.com/jborgers/sonar-pmd/issues/498) + +**Contributors** +* [Markus](https://github.com/meisenla) + +## [4.0.0](https://github.com/jborgers/sonar-pmd/tree/4.0.0) (2025-02-24) +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/3.5.1..4.0.0) + +**Implemented highlights:** +- Supports PMD 7 which is incompatible with PMD 6: the reason for a major release +- Supports latest SonarQube [9.9.4 - 10.8+] +- Supports running on Java 11 on analysis side for SQ 9.9.4 - 10.2.x +- Supports running on Java 17 for all supported versions +- Needed for child plugins with custom rules written in PMD 7, such as [sonar-pmd-jpinpoint 2.0.0](https://github.com/jborgers/sonar-pmd-jpinpoint/releases/tag/2.0.0) + +## [3.5.1](https://github.com/jborgers/sonar-pmd/tree/3.5.1) (2024-05-07) +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/3.5.0..3.5.1) + +**Implemented highlights:** +- Supports latest SonarQube [9.9.4 - 10.5+] +- Supports running on Java 11 on analysis side for SQ 9.9.4 - 10.2.x +- Supports running on Java 17 for all supported versions +- Updated Sonar Plugin API+impl for SonarQube 9.9.4+ +- Upgraded various dependencies + +- ## [3.5.0](https://github.com/jborgers/sonar-pmd/tree/3.5.0) (2024-04-23) +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/3.4.0...3.5.0) + +**Contributors:** +- [jborgers](https://github.com/jborgers) +- [renewolfert](https://github.com/renewolfert) + +**Implemented highlights:** +- Updated PMD (6.55.0) (last PMD-6) #422 +- Support analyzing up to Java 20-preview (close to 21) #422 +- Java 21+ falls back to 20-preview with warning (no error) #422 +- Updated Sonar Plugin API+impl (9.8.0.63668) (SonarQube 9.8+) +- Upgraded various dependencies +- Needs Java 17, the class file version is 61 + +## [3.4.0](https://github.com/jborgers/sonar-pmd/tree/3.4.0) (2022-05-11) +[Full Changelog](https://github.com/jborgers/sonar-pmd/compare/3.3.1...3.4.0) + +**Contributors:** +- [jborgers](https://github.com/jborgers) +- [stokpop](https://github.com/stokpop) +- [jensgerdes](https://github.com/jensgerdes) (Many thanks for his great maintenance and decision to transfer) + +**Implemented highlights:** +- Updated PMD (6.45.0) #319 +- Support for Java 18 (including 17) #319 +- Updated Sonar Plugin API (9.4.0.54424) #309 +- Removed explicit dependency on Java plugin for new SonarQube Marketplace setup #303 +- Upgraded various dependencies +- Transferred maintenance to [jborgers](https://github.com/jborgers) and [stokpop](https://github.com/stokpop) + +## [3.3.1](https://github.com/jensgerdes/sonar-pmd/tree/3.3.1) (2021-01-29) +[Full Changelog](https://github.com/jensgerdes/sonar-pmd/compare/3.3.0...3.3.1) + +**Contributors:** +- [jborgers](https://github.com/jborgers) + +**Closed issues:** +- Fixed Windows incompatibility introduced in 3.3.0 [\#244](https://github.com/jensgerdes/sonar-pmd/issues/244) + +## [3.3.0](https://github.com/jensgerdes/sonar-pmd/tree/3.3.0) (2021-01-11) +[Full Changelog](https://github.com/jensgerdes/sonar-pmd/compare/3.2.1...3.3.0) + +**Contributors:** +- [jborgers](https://github.com/jborgers) +- [robinverduijn](https://github.com/robinverduijn) + +**Implemented enhancements:** +- Updated PMD (6.30.0) +- Support for Java 15 +- Updated Sonar-Java API (6.0.1) + +**Closed issues:** +- Fixed deprecated PMD API Usage [\#239](https://github.com/jensgerdes/sonar-pmd/issues/239) +- Fixed CVE-2018-10237 [\#230](https://github.com/jensgerdes/sonar-pmd/issues/230) +- Fixed incorrect rule description [\#78](https://github.com/jensgerdes/sonar-pmd/issues/78) + +**Merged pull requests:** +- Move to pmd-6.29 and solve api incompatibility [\#228](https://github.com/jensgerdes/sonar-pmd/pull/228) ([jborgers](https://github.com/jborgers)) +- Update pmd-java dependency to 6.22.0 [\#167](https://github.com/jensgerdes/sonar-pmd/pull/167) ([robinverduijn](https://github.com/robinverduijn)) +- Use correct parent classloader to fix Java 9 style modules [\#168](https://github.com/jensgerdes/sonar-pmd/pull/168) ([robinverduijn](https://github.com/robinverduijn)) ## [3.2.1](https://github.com/jensgerdes/sonar-pmd/tree/3.2.1) (2019-04-15) [Full Changelog](https://github.com/jensgerdes/sonar-pmd/compare/3.2.0...3.2.1) diff --git a/README.md b/README.md index 31c62aa1..82650d47 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,114 @@ -# SonarQube PMD Plugin [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.sonarsource.pmd/sonar-pmd-plugin/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.sonarsource.pmd/sonar-pmd-plugin) [![Build Status](https://api.travis-ci.org/jensgerdes/sonar-pmd.svg?branch=master)](https://travis-ci.org/jensgerdes/sonar-pmd) [![SonarStatus](https://sonarcloud.io/api/project_badges/measure?project=org.sonarsource.pmd%3Asonar-pmd-plugin&metric=alert_status)](https://sonarcloud.io/dashboard?id=org.sonarsource.pmd%3Asonar-pmd-plugin) [![SonarStatus](https://sonarcloud.io/api/project_badges/measure?project=org.sonarsource.pmd%3Asonar-pmd-plugin&metric=coverage)](https://sonarcloud.io/dashboard?id=org.sonarsource.pmd%3Asonar-pmd-plugin) -Sonar-PMD is a plugin that provides coding rules from [PMD](https://pmd.github.io/). +# SonarQube PMD Plugin -For a list of all rules and their status, see: [RULES.md](https://github.com/jensgerdes/sonar-pmd/blob/master/docs/RULES.md) +[![Sonatype Central](https://maven-badges.sml.io/sonatype-central/org.sonarsource.pmd/sonar-pmd-plugin/badge.svg)](https://maven-badges.sml.io/sonatype-central/org.sonarsource.pmd/sonar-pmd-plugin) +[![Maven Central](https://maven-badges.sml.io/maven-central/org.sonarsource.pmd/sonar-pmd-plugin/badge.svg)](https://maven-badges.sml.io/maven-central/org.sonarsource.pmd/sonar-pmd-plugin) +![Build Status](https://github.com/jborgers/sonar-pmd/actions/workflows/build.yml/badge.svg) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=jborgers_sonar-pmd&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=jborgers_sonar-pmd) + +Sonar-PMD is a plugin that provides coding rules from [PMD](https://pmd.github.io/) for use in SonarQube. + +Starting April 2022, the project has found a new home. We, [jborgers](https://github.com/jborgers) and [stokpop](https://github.com/stokpop), +aim to provide an active project and well-maintained sonar-pmd plugin. It is now sponsored by [Rabobank](https://www.rabobank.com/). ## Installation -The plugin is available in the SonarQube marketplace and should preferably be installed from within SonarQube (Administration --> Marketplace --> Search _pmd_). +The plugin should be available in the SonarQube marketplace and is preferably installed from within SonarQube (Administration → Marketplace → Search _pmd_). -Alternatively, download the [latest JAR file](https://github.com/jensgerdes/sonar-pmd/releases/latest), put it into the plugin directory (`./extensions/plugins`) and restart SonarQube. +Alternatively, download the [latest JAR file](https://github.com/jborgers/sonar-pmd/releases/latest), put it into the plugin directory (`./extensions/downloads`) and restart SonarQube. ## Usage Usage should be straight forward: 1. Activate some PMD rules in your quality profile. 2. Run an analysis. -### Troubleshooting +### PMD version +Sonar PMD plugin version 4.0+ supports PMD 7 which is incompatible with PMD 6: the reason for a major release. +Use version 4.0+ for child plugins with custom rules written in PMD 7, such as [sonar-pmd-jpinpoint 2.0.0](https://github.com/jborgers/sonar-pmd-jpinpoint/releases/tag/2.0.0). + +### Java version Sonar-PMD analyzes the given source code with the Java source version defined in your Gradle or Maven project. -In case you are not using one of these build tools, PMD uses the default Java version - which is **1.6**. +In case you are not using one of these build tools, or if that does not match the version you are using, set the `sonar.java.source` property to tell PMD which version of Java your source code complies to. + +Possible values: 8 to 25 and 25-preview + +## Table of supported versions +| Sonar-PMD Plugin | 3.5.0 | 3.5.1 | 4.0.0 | 4.0.3 | 4.1.0 | 4.2.0 | +|------------------------|-----------------|-----------------|---------|------------|-------------|-------------------------------------------------------------------------| +| PMD | 6.55.0 | 6.55.0 | 7.10.0 | 7.14.0 | 7.15.0 | [7.17.0](https://github.com/pmd/pmd/releases/tag/pmd_releases%2F7.17.0) | +| Max. Java Version | 20-preview (*1) | 20-preview (*1) | 20 (*2) | 24-preview | 24-preview | 25-preview | +| Min. SonarQube Version | 9.8 | 9.9.4 | 9.9.4 | 9.9.4 | 9.9.6 | 9.9.6 | +| Max. SonarQube Version | 10.4 | 10.5+ | 10.8+ | 25.6+ | 25.6+ | 25.9+ | + +(*1) Note: Supports all tested Java 21 features; on parsing errors, warns instead of breaks. +(*2) Note: Does not support Java 20-preview nor Java 21. + +## Limited Java PMD rule support before 4.1.0 +PMD rules created since PMD 5.5.0 in 2016 were missing in release 4.0.3 and before. + +Additionally, the sonar-pmd plugin marked the PMD rules which have a known adopted alternative in Sonar as `Deprecated`. +Furthermore, PMD rules which were deprecated by PMD itself had the `Deprecated` mark as well, which was confusing. + +## Full Java PMD rule support starting with 4.1.0 +With version 4.1.0 we introduce easy incorporation of new PMD rules into this plugin and thereby support the full up-to-date set of PMD rules in Sonar. + +From now on, only rules that are deprecated in PMD are also marked `Deprecated` in Sonar. Rules that have alternative rules in Sonar are tagged with +`has-sonar-alternative`, so they can be easily selected in SonarQube. The documentation will include the link to known alternative Sonar rule. -If that does not match the version you are using, set the `sonar.java.source` property to tell PMD which version of Java your source code complies to. +Limitations: +1. Referred alternative Java Sonar rules are limited to rules from before 2016, newer Java Sonar rules are not referred to yet. +If you find missing alternative rules please create a Github issue. +2. The estimated amount of time to fix issues is only available for rules from before 2016. +3. Properties of the rules cannot be changed via SonarQube, currently only defaults can be used. -Possible values: -- 1.4 -- 1.5 or 5 -- 1.6 or 6 -- 1.7 or 7 -- 1.8 or 8 -- 9 -- 10 -- 11 +## Java PMD rules summary -## Description / Features -PMD Plugin|2.0|2.1|2.2|2.3|2.4.1|2.5|2.6|3.0.0|3.1.x|3.2.x --------|---|---|---|---|---|---|---|---|---|--- -PMD|4.3|4.3|5.1.1|5.2.1|5.3.1|5.4.0|5.4.2|5.4.2|6.9.0|6.10.0 -Max. supported Java Version | | | | | | 1.7 | 1.8 | 1.8 | 11 | -Min. SonarQube Version | | | | | | 4.5.4 | 4.5.4 | 6.6 | 6.6 | +- Total rules in old version (4.1.0): 282 +- Total rules in new version (4.2.0): 292 +- Rules added: 10 +- Rules removed: 0 +- Rules unchanged: 233 +- Rules updated: 49 +- Rules renamed: 10 -A majority of the PMD rules have been rewritten in the Java plugin. Rewritten rules are marked "Deprecated" in the PMD plugin, but a [concise summary of replaced rules](http://dist.sonarsource.com/reports/coverage/pmd.html) is available. +See details: [pmd_release_notes_4.2.0.md](docs/pmd_release_notes_4.2.0.md) -## Rules on test -PMD tool provides some rules that can check the code of JUnit tests. Please note that these rules (and only these rules) will be applied only on the test files of your project. +## Support for other languages +Support for Apex PMD rules is work in progress. + +## Main vs Test sources and analysis scope +SonarQube distinguishes between main source files and test source files. +Sonar-PMD assigns a scope to each PMD rule so it runs only where it makes sense. + +How scope is set automatically: +- Default: ALL (rule runs on both main and test sources). +- If a rule name contains "Test" or "JUnit" (case-insensitive), it is treated as a test rule and scoped to TEST automatically. +- Test rules get the `tests` Sonar tag conform existing Sonar test scoped rules. + +How to configure or override the scope in the PMD rules XML: +1. Force a rule to run only on tests: add the tag `tests`. +1. Force a rule to run only on main sources: add the tag `main-sources`. +1. Force a rule run on ALL sources: add both tags `tests` and `main-sources`. + +Note that the latter two options will override the rule name matching the test pattern. Also, the `tests` tag will not be shown. + +Notes: +- The PMD tag `main-sources` is used for scope control and is not shown in the rule tags list in SonarQube. ## License -Sonar-PMD is licensed under the [GNU Lesser General Public License, Version 3.0](https://github.com/jensgerdes/sonar-pmd/blob/master/LICENSE.md). +Sonar-PMD is licensed under the [GNU Lesser General Public License, Version 3.0](https://github.com/jborgers/sonar-pmd/blob/master/LICENSE.md). Parts of the rule descriptions displayed in SonarQube have been extracted from [PMD](https://pmd.github.io/) and are licensed under a [BSD-style license](https://github.com/pmd/pmd/blob/master/LICENSE). +## Build and test the plugin +To build the plugin and run the integration tests (use java 17 to build the plugin): + + ./mvnw clean verify + +## Generate PMD rules XML (Java and Kotlin) +To regenerate the `rules-java.xml` and `rules-kotlin.xml` from PMD 7 using the provided Groovy script, run from the project root: + + ./mvnw clean generate-resources -Pgenerate-pmd-rules -pl sonar-pmd-plugin -am + +Notes: +- The `-am` (also-make) flag ensures dependent modules (e.g., `sonar-pmd-lib`) are built in the reactor even when building only `sonar-pmd-plugin` with `-pl`. +- If `sonar-pmd-lib` fails to build so new changes are not reflected in the rules, try running `mvn clean package` in the `sonar-pmd-lib` module. + diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 00000000..9fc3108f --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,64 @@ +# Release Process + +This document describes the process for creating a new release of the SonarQube PMD plugin. + +## Prerequisites + +Before starting the release process: + +1. Ensure all commits have been pushed +2. Verify the build passes with the `build.yml` GitHub Actions workflow +3. In Github, close all issues and pull requests related to the new release x.y.z. + +## Preparation + +### Update PMD Rules and Generate Release Notes + +For updating PMD rules and generating release notes, refer to the [scripts documentation](scripts/README.md). + +In Github create a Draft release, or a pre-release. + +## Release Steps + +1. Update documentation: + - Create release notes in `CHANGELOG.md` (update `..master` to `..x.y.z`) + - Copy the commented out SNAPSHOT section to new SNAPSHOT release x.y.z+1-SNAPSHOT + - Uncomment the current SNAPSHOT release to non-SNAPSHOT upcoming release x.y.z + - Fill in the "Implemented highlights" + - Update `README.md` if needed + - Commit an push changes + +2. Publish the release in Github: + - Fill the to-be-created version + - Generate the release notes, sync with "Implemented highlights" from `CHANGELOG.md` + - Press Publish button + + This will trigger the release workflow, which injects the git tag via maven `-Drevision=`. + +3. Post-release tasks: + - Manually release the staging repository in [Sonatype](https://oss.sonatype.org/#welcome) for Maven Central + - Make release available in Sonar marketplace and post a message for the shiny new release (see below) + +## Prepare for Next Development Cycle + +1. Update version information: + - Change the `revision` property to `x.y.z+1-SNAPSHOT` in `.mvn/maven.config` + - Commit and push with the message "Prepare release x.y.z+1-SNAPSHOT" + +2. Update GitHub: + - Close milestone `x.y.z` + - Create new milestone `x.y.z+1` + +## Troubleshooting + +If the release fails and needs to be "restarted": +1. Drop the staging repository +2. Delete the tag locally: `git tag -d x.y.z` (or delete in IntelliJ) +3. Delete the tag remotely: `git push origin :refs/tags/x.y.z` (or use context menu in Intellij) +4. Might need to also delete the tag in Github +5. Fix the issue, commit, push, and restart the release process + +## Publishing to Marketplace + +- Follow the [Deploying to the Marketplace](https://community.sonarsource.com/t/deploying-to-the-marketplace/35236) guide +- Reference our [first forum post](https://community.sonarsource.com/t/new-release-sonar-pmd-plugin-3-4-0/63091) as an example diff --git a/docs/RULES.md b/docs/RULES.md deleted file mode 100644 index 08f257c7..00000000 --- a/docs/RULES.md +++ /dev/null @@ -1,306 +0,0 @@ -# PMD Rules - -The purpose of this document is to support resolving [#110](https://github.com/jensgerdes/sonar-pmd/issues/110). -For that purpose, we track the current rule status: -* Is the description up to date? -* Is the rule deprecated - meaning is there a built-in rule that replaces the PMD rule? -* If so, what is the alternative? - -The PMD rules are divided into two sub categories: -* PMD Rules -* PMD Unit Test Rules - - -## PMD Rules - -Rule name | Deprecated? | Alternative | Description up-to-date | Checked on -----------|-------------|-------------|------------------------|----------- -[AbstractClassWithoutAbstractMethod](./rules/AbstractClassWithoutAbstractMethod.md) | :ballot_box_with_check: | [S1694](https://rules.sonarsource.com/java/RSPEC-1694) | :white_check_mark: | 2019-04-23 -[AbstractClassWithoutAnyMethod](./rules/AbstractClassWithoutAnyMethod.md) | :ballot_box_with_check: | [S1694](https://rules.sonarsource.com/java/RSPEC-1694) | :white_check_mark: | 2019-04-23 -[AbstractNaming](./rules/AbstractNaming.md) | :ballot_box_with_check: | [S00118](https://rules.sonarsource.com/java/RSPEC-118) | :white_check_mark: | 2019-04-23 -[AccessorClassGeneration](./rules/AccessorClassGeneration.md) | :x: | :heavy_minus_sign: | :white_check_mark: | 2019-04-23 -[AddEmptyString](./rules/AddEmptyString.md) | :x: | :heavy_minus_sign: | :white_check_mark: | 2019-04-23 -[AppendCharacterWithChar](./rules/AppendCharacterWithChar.md) | :x: | :heavy_minus_sign: | :white_check_mark: | 2019-04-23 -[ArrayIsStoredDirectly](./rules/ArrayIsStoredDirectly.md) | :ballot_box_with_check: | [S2384](https://rules.sonarsource.com/java/RSPEC-2384) | :white_check_mark: | 2019-04-23 -[AssignmentInOperand](./rules/AssignmentInOperand.md) | :ballot_box_with_check: | `squid:AssignmentInSubExpressionCheck` | :white_check_mark: | 2019-04-23 -[AssignmentToNonFinalStatic](./rules/AssignmentToNonFinalStatic.md) | :x: | :heavy_minus_sign: | :white_check_mark: | 2019-04-23 -[AtLeastOneConstructor](./rules/AtLeastOneConstructor.md) | :ballot_box_with_check: | [S1118](https://rules.sonarsource.com/java/RSPEC-1118), [S1258](https://rules.sonarsource.com/java/RSPEC-1258) | :white_check_mark: | 2019-04-23 -[AvoidAccessibilityAlteration](./rules/AvoidAccessibilityAlteration.md) | :x: | :heavy_minus_sign: | :white_check_mark: | 2019-04-25 -[AvoidArrayLoops](./rules/AvoidArrayLoops.md) | :x: | :heavy_minus_sign: | :white_check_mark: | 2019-04-25 -[AvoidAssertAsIdentifier](./rules/AvoidAssertAsIdentifier.md) | :ballot_box_with_check: | [S1190](https://rules.sonarsource.com/java/RSPEC-1190) | :white_check_mark: | 2019-04-25 -[AvoidBranchingStatementAsLastInLoop](./rules/AvoidBranchingStatementAsLastInLoop.md) | :x: | :heavy_minus_sign: | :white_check_mark: | 2019-04-25 -[AvoidCallingFinalize](./rules/AvoidCallingFinalize.md) | :ballot_box_with_check: | `squid:ObjectFinalizeCheck` | :white_check_mark: | 2019-04-25 -[AvoidCatchingGenericException](./rules/AvoidCatchingGenericException.md) | :ballot_box_with_check: | [S2221](https://rules.sonarsource.com/java/RSPEC-2221) | :white_check_mark: | 2019-04-25 -[AvoidCatchingNPE](./rules/AvoidCatchingNPE.md) | :ballot_box_with_check: | [S1696](https://rules.sonarsource.com/java/RSPEC-1696) | :white_check_mark: | 2019-04-25 -[AvoidCatchingThrowable](./rules/AvoidCatchingThrowable.md) | :ballot_box_with_check: | [S1181](https://rules.sonarsource.com/java/RSPEC-1181) | :white_check_mark: | 2019-04-25 -[AvoidConstantsInterface](./rules/AvoidConstantsInterface.md) | :ballot_box_with_check: | [S1214](https://rules.sonarsource.com/java/RSPEC-1214) | :white_check_mark: | 2019-04-25 -[AvoidDecimalLiteralsInBigDecimalConstructor](./rules/AvoidDecimalLiteralsInBigDecimalConstructor.md) | :ballot_box_with_check: | [S2111](https://rules.sonarsource.com/java/RSPEC-2111) | :white_check_mark: | 2019-04-25 -[AvoidDeeplyNestedIfStmts](./rules/AvoidDeeplyNestedIfStmts.md) | :ballot_box_with_check: | [S134](https://rules.sonarsource.com/java/RSPEC-134) | :white_check_mark: | 2019-04-25 -[AvoidDollarSigns](./rules/AvoidDollarSigns.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidDuplicateLiterals](./rules/AvoidDuplicateLiterals.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidEnumAsIdentifier](./rules/AvoidEnumAsIdentifier.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidFieldNameMatchingMethodName](./rules/AvoidFieldNameMatchingMethodName.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidFieldNameMatchingTypeName](./rules/AvoidFieldNameMatchingTypeName.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidFinalLocalVariable](./rules/AvoidFinalLocalVariable.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidInstanceofChecksInCatchClause](./rules/AvoidInstanceofChecksInCatchClause.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidInstantiatingObjectsInLoops](./rules/AvoidInstantiatingObjectsInLoops.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidLiteralsInIfCondition](./rules/AvoidLiteralsInIfCondition.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidLosingExceptionInformation](./rules/AvoidLosingExceptionInformation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidMultipleUnaryOperators](./rules/AvoidMultipleUnaryOperators.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidPrefixingMethodParameters](./rules/AvoidPrefixingMethodParameters.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidPrintStackTrace](./rules/AvoidPrintStackTrace.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidProtectedFieldInFinalClass](./rules/AvoidProtectedFieldInFinalClass.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidProtectedMethodInFinalClassNotExtending](./rules/AvoidProtectedMethodInFinalClassNotExtending.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidReassigningParameters](./rules/AvoidReassigningParameters.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidRethrowingException](./rules/AvoidRethrowingException.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidStringBufferField](./rules/AvoidStringBufferField.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidSynchronizedAtMethodLevel](./rules/AvoidSynchronizedAtMethodLevel.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidThreadGroup](./rules/AvoidThreadGroup.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidThrowingNewInstanceOfSameException](./rules/AvoidThrowingNewInstanceOfSameException.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidThrowingNullPointerException](./rules/AvoidThrowingNullPointerException.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidThrowingRawExceptionTypes](./rules/AvoidThrowingRawExceptionTypes.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidUsingHardCodedIP](./rules/AvoidUsingHardCodedIP.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidUsingNativeCode](./rules/AvoidUsingNativeCode.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidUsingOctalValues](./rules/AvoidUsingOctalValues.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidUsingShortType](./rules/AvoidUsingShortType.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[AvoidUsingVolatile](./rules/AvoidUsingVolatile.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[BadComparison](./rules/BadComparison.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[BeanMembersShouldSerialize](./rules/BeanMembersShouldSerialize.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -Big[IntegerInstantiation](./rules/IntegerInstantiation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[BooleanGetMethodName](./rules/BooleanGetMethodName.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[BooleanInstantiation](./rules/BooleanInstantiation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[BrokenNullCheck](./rules/BrokenNullCheck.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ByteInstantiation](./rules/ByteInstantiation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CallSuperFirst](./rules/CallSuperFirst.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CallSuperInConstructor](./rules/CallSuperInConstructor.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CallSuperLast](./rules/CallSuperLast.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CheckResultSet](./rules/CheckResultSet.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CheckSkipResult](./rules/CheckSkipResult.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ClassCastExceptionWithToArray](./rules/ClassCastExceptionWithToArray.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ClassNamingConventions](./rules/ClassNamingConventions.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ClassWithOnlyPrivateConstructorsShouldBeFinal](./rules/ClassWithOnlyPrivateConstructorsShouldBeFinal.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CloneMethodMustBePublic](./rules/CloneMethodMustBePublic.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CloneMethodMustImplementCloneable](./rules/CloneMethodMustImplementCloneable.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CloneMethodMustImplementCloneableWithTypeResolution](./rules/CloneMethodMustImplementCloneableWithTypeResolution.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CloneMethodReturnTypeMustMatchClassName](./rules/CloneMethodReturnTypeMustMatchClassName.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CloneThrowsCloneNotSupportedException](./rules/CloneThrowsCloneNotSupportedException.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CloseResource](./rules/CloseResource.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CollapsibleIfStatements](./rules/CollapsibleIfStatements.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CommentContent](./rules/CommentContent.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CommentDefaultAccessModifier](./rules/CommentDefaultAccessModifier.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CommentRequired](./rules/CommentRequired.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CommentSize](./rules/CommentSize.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CompareObjectsWithEquals](./rules/CompareObjectsWithEquals.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ConfusingTernary](./rules/ConfusingTernary.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ConsecutiveAppendsShouldReuse](./rules/ConsecutiveAppendsShouldReuse.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ConsecutiveLiteralAppends](./rules/ConsecutiveLiteralAppends.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ConstructorCallsOverridableMethod](./rules/ConstructorCallsOverridableMethod.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CouplingBetweenObjects](./rules/CouplingBetweenObjects.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[CyclomaticComplexity](./rules/CyclomaticComplexity.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DataflowAnomalyAnalysis](./rules/DataflowAnomalyAnalysis.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DefaultLabelNotLastInSwitchStmt](./rules/DefaultLabelNotLastInSwitchStmt.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DefaultPackage](./rules/DefaultPackage.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DoNotCallGarbageCollectionExplicitly](./rules/DoNotCallGarbageCollectionExplicitly.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DoNotCallSystemExit](./rules/DoNotCallSystemExit.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DoNotExtendJavaLangError](./rules/DoNotExtendJavaLangError.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DoNotHardCodeSDCard](./rules/DoNotHardCodeSDCard.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DoNotThrowExceptionInFinally](./rules/DoNotThrowExceptionInFinally.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DoNotUseThreads](./rules/DoNotUseThreads.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DontCallThreadRun](./rules/DontCallThreadRun.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DontImportJavaLang](./rules/DontImportJavaLang.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DontImportSun](./rules/DontImportSun.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DontUseFloatTypeForLoopIndices](./rules/DontUseFloatTypeForLoopIndices.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DoubleCheckedLocking](./rules/DoubleCheckedLocking.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[DuplicateImports](./rules/DuplicateImports.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptyCatchBlock](./rules/EmptyCatchBlock.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptyFinalizer](./rules/EmptyFinalizer.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptyFinallyBlock](./rules/EmptyFinallyBlock.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptyIfStmt](./rules/EmptyIfStmt.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptyInitializer](./rules/EmptyInitializer.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptyMethodInAbstractClassShouldBeAbstract](./rules/EmptyMethodInAbstractClassShouldBeAbstract.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptyStatementBlock](./rules/EmptyStatementBlock.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptyStatementNotInLoop](./rules/EmptyStatementNotInLoop.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptyStaticInitializer](./rules/EmptyStaticInitializer.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptySwitchStatements](./rules/EmptySwitchStatements.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptySynchronizedBlock](./rules/EmptySynchronizedBlock.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptyTryBlock](./rules/EmptyTryBlock.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EmptyWhileStmt](./rules/EmptyWhileStmt.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[EqualsNull](./rules/EqualsNull.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ExceptionAsFlowControl](./rules/ExceptionAsFlowControl.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ExcessiveClassLength](./rules/ExcessiveClassLength.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ExcessiveImports](./rules/ExcessiveImports.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ExcessiveMethodLength](./rules/ExcessiveMethodLength.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ExcessiveParameterList](./rules/ExcessiveParameterList.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ExcessivePublicCount](./rules/ExcessivePublicCount.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ExtendsObject](./rules/ExtendsObject.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[FieldDeclarationsShouldBeAtStartOfClass](./rules/FieldDeclarationsShouldBeAtStartOfClass.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[FinalFieldCouldBeStatic](./rules/FinalFieldCouldBeStatic.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[FinalizeDoesNotCallSuperFinalize](./rules/FinalizeDoesNotCallSuperFinalize.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[FinalizeOnlyCallsSuperFinalize](./rules/FinalizeOnlyCallsSuperFinalize.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[FinalizeOverloaded](./rules/FinalizeOverloaded.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[FinalizeShouldBeProtected](./rules/FinalizeShouldBeProtected.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ForLoopShouldBeWhileLoop](./rules/ForLoopShouldBeWhileLoop.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ForLoopsMustUseBraces](./rules/ForLoopsMustUseBraces.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[GenericsNaming](./rules/GenericsNaming.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[GodClass](./rules/GodClass.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[GuardDebugLogging](./rules/GuardDebugLogging.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[GuardLogStatement](./rules/GuardLogStatement.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[GuardLogStatementJavaUtil](./rules/GuardLogStatementJavaUtil.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[IdempotentOperations](./rules/IdempotentOperations.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[IfElseStmtsMustUseBraces](./rules/IfElseStmtsMustUseBraces.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[IfStmtsMustUseBraces](./rules/IfStmtsMustUseBraces.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ImmutableField](./rules/ImmutableField.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ImportFromSamePackage](./rules/ImportFromSamePackage.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[InefficientEmptyStringCheck](./rules/InefficientEmptyStringCheck.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[InefficientStringBuffering](./rules/InefficientStringBuffering.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[InstantiationToGetClass](./rules/InstantiationToGetClass.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[InsufficientStringBufferDeclaration](./rules/InsufficientStringBufferDeclaration.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -IntegerInstantiation | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[JumbledIncrementer](./rules/JumbledIncrementer.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[LawOfDemeter](./rules/LawOfDemeter.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[LocalHomeNamingConvention](./rules/LocalHomeNamingConvention.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[LocalInterfaceSessionNamingConvention](./rules/LocalInterfaceSessionNamingConvention.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[LocalVariableCouldBeFinal](./rules/LocalVariableCouldBeFinal.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[LoggerIsNotStaticFinal](./rules/LoggerIsNotStaticFinal.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[LogicInversion](./rules/LogicInversion.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[LongInstantiation](./rules/LongInstantiation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[LongVariable](./rules/LongVariable.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[LooseCoupling](./rules/LooseCoupling.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[LooseCouplingWithTypeResolution](./rules/LooseCouplingWithTypeResolution.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[LoosePackageCoupling](./rules/LoosePackageCoupling.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[MDBAndSessionBeanNamingConvention](./rules/MDBAndSessionBeanNamingConvention.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[MethodArgumentCouldBeFinal](./rules/MethodArgumentCouldBeFinal.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[MethodNamingConventions](./rules/MethodNamingConventions.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[MethodReturnsInternalArray](./rules/MethodReturnsInternalArray.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[MethodWithSameNameAsEnclosingClass](./rules/MethodWithSameNameAsEnclosingClass.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[MisleadingVariableName](./rules/MisleadingVariableName.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[MisplacedNullCheck](./rules/MisplacedNullCheck.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[MissingBreakInSwitch](./rules/MissingBreakInSwitch.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[MissingSerialVersionUID](./rules/MissingSerialVersionUID.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[MissingStaticMethodInNonInstantiatableClass](./rules/MissingStaticMethodInNonInstantiatableClass.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ModifiedCyclomaticComplexity](./rules/ModifiedCyclomaticComplexity.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[MoreThanOneLogger](./rules/MoreThanOneLogger.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[NPathComplexity](./rules/NPathComplexity.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[NcssConstructorCount](./rules/NcssConstructorCount.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[NcssMethodCount](./rules/NcssMethodCount.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[NcssTypeCount](./rules/NcssTypeCount.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[NoPackage](./rules/NoPackage.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[NonCaseLabelInSwitchStatement](./rules/NonCaseLabelInSwitchStatement.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[NonStaticInitializer](./rules/NonStaticInitializer.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[NonThreadSafeSingleton](./rules/NonThreadSafeSingleton.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[NullAssignment](./rules/NullAssignment.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[OneDeclarationPerLine](./rules/OneDeclarationPerLine.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[OnlyOneReturn](./rules/OnlyOneReturn.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[OptimizableToArrayCall](./rules/OptimizableToArrayCall.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[OverrideBothEqualsAndHashcode](./rules/OverrideBothEqualsAndHashcode.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[PackageCase](./rules/PackageCase.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[PositionLiteralsFirstInCaseInsensitiveComparisons](./rules/PositionLiteralsFirstInCaseInsensitiveComparisons.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[PositionLiteralsFirstInComparisons](./rules/PositionLiteralsFirstInComparisons.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[PrematureDeclaration](./rules/PrematureDeclaration.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[PreserveStackTrace](./rules/PreserveStackTrace.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ProperCloneImplementation](./rules/ProperCloneImplementation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ProperLogger](./rules/ProperLogger.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[RedundantFieldInitializer](./rules/RedundantFieldInitializer.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[RemoteInterfaceNamingConvention](./rules/RemoteInterfaceNamingConvention.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[RemoteSessionInterfaceNamingConvention](./rules/RemoteSessionInterfaceNamingConvention.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ReplaceEnumerationWithIterator](./rules/ReplaceEnumerationWithIterator.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ReplaceHashtableWithMap](./rules/ReplaceHashtableWithMap.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ReplaceVectorWithList](./rules/ReplaceVectorWithList.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ReturnEmptyArrayRatherThanNull](./rules/ReturnEmptyArrayRatherThanNull.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ReturnFromFinallyBlock](./rules/ReturnFromFinallyBlock.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ShortClassName](./rules/ShortClassName.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ShortInstantiation](./rules/ShortInstantiation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ShortMethodName](./rules/ShortMethodName.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[ShortVariable](./rules/ShortVariable.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SignatureDeclareThrowsException](./rules/SignatureDeclareThrowsException.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SignatureDeclareThrowsExceptionWithTypeResolution](./rules/SignatureDeclareThrowsExceptionWithTypeResolution.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SimpleDateFormatNeedsLocale](./rules/SimpleDateFormatNeedsLocale.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SimplifiedTernary](./rules/SimplifiedTernary.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SimplifyBooleanExpressions](./rules/SimplifyBooleanExpressions.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SimplifyBooleanReturns](./rules/SimplifyBooleanReturns.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SimplifyConditional](./rules/SimplifyConditional.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SimplifyStartsWith](./rules/SimplifyStartsWith.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SingleMethodSingleton](./rules/SingleMethodSingleton.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SingletonClassReturningNewInstance](./rules/SingletonClassReturningNewInstance.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SingularField](./rules/SingularField.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[StaticEJBFieldShouldBeFinal](./rules/StaticEJBFieldShouldBeFinal.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[StdCyclomaticComplexity](./rules/StdCyclomaticComplexity.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[StringBufferInstantiationWithChar](./rules/StringBufferInstantiationWithChar.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[StringInstantiation](./rules/StringInstantiation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[StringToString](./rules/StringToString.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SuspiciousConstantFieldName](./rules/SuspiciousConstantFieldName.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SuspiciousEqualsMethodName](./rules/SuspiciousEqualsMethodName.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SuspiciousHashcodeMethodName](./rules/SuspiciousHashcodeMethodName.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SuspiciousOctalEscape](./rules/SuspiciousOctalEscape.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SwitchDensity](./rules/SwitchDensity.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SwitchStmtsShouldHaveDefault](./rules/SwitchStmtsShouldHaveDefault.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SystemPrintln](./rules/SystemPrintln.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[TooFewBranchesForASwitchStatement](./rules/TooFewBranchesForASwitchStatement.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[TooManyFields](./rules/TooManyFields.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[TooManyMethods](./rules/TooManyMethods.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[TooManyStaticImports](./rules/TooManyStaticImports.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UncommentedEmptyConstructor](./rules/UncommentedEmptyConstructor.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UncommentedEmptyMethodBody](./rules/UncommentedEmptyMethodBody.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnconditionalIfStatement](./rules/UnconditionalIfStatement.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnnecessaryCaseChange](./rules/UnnecessaryCaseChange.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnnecessaryConstructor](./rules/UnnecessaryConstructor.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnnecessaryConversionTemporary](./rules/UnnecessaryConversionTemporary.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnnecessaryFinalModifier](./rules/UnnecessaryFinalModifier.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnnecessaryFullyQualifiedName](./rules/UnnecessaryFullyQualifiedName.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnnecessaryLocalBeforeReturn](./rules/UnnecessaryLocalBeforeReturn.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnnecessaryParentheses](./rules/UnnecessaryParentheses.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnnecessaryReturn](./rules/UnnecessaryReturn.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnnecessaryWrapperObjectCreation](./rules/UnnecessaryWrapperObjectCreation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnsynchronizedStaticDateFormatter](./rules/UnsynchronizedStaticDateFormatter.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnusedFormalParameter](./rules/UnusedFormalParameter.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnusedImports](./rules/UnusedImports.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnusedImportsWithTypeResolution](./rules/UnusedImportsWithTypeResolution.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnusedLocalVariable](./rules/UnusedLocalVariable.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnusedModifier](./rules/UnusedModifier.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnusedNullCheckInEquals](./rules/UnusedNullCheckInEquals.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnusedPrivateField](./rules/UnusedPrivateField.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnusedPrivateMethod](./rules/UnusedPrivateMethod.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseArrayListInsteadOfVector](./rules/UseArrayListInsteadOfVector.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseArraysAsList](./rules/UseArraysAsList.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseCollectionIsEmpty](./rules/UseCollectionIsEmpty.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseConcurrentHashMap](./rules/UseConcurrentHashMap.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseCorrectExceptionLogging](./rules/UseCorrectExceptionLogging.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseEqualsToCompareStrings](./rules/UseEqualsToCompareStrings.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseIndexOfChar](./rules/UseIndexOfChar.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseLocaleWithCaseConversions](./rules/UseLocaleWithCaseConversions.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseNotifyAllInsteadOfNotify](./rules/UseNotifyAllInsteadOfNotify.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseObjectForClearerAPI](./rules/UseObjectForClearerAPI.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseProperClassLoader](./rules/UseProperClassLoader.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseStringBufferForStringAppends](./rules/UseStringBufferForStringAppends.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseStringBufferLength](./rules/UseStringBufferLength.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseUtilityClass](./rules/UseUtilityClass.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseVarargs](./rules/UseVarargs.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UselessOperationOnImmutable](./rules/UselessOperationOnImmutable.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UselessOverridingMethod](./rules/UselessOverridingMethod.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UselessParentheses](./rules/UselessParentheses.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UselessQualifiedThis](./rules/UselessQualifiedThis.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UselessStringValueOf](./rules/UselessStringValueOf.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[VariableNamingConventions](./rules/VariableNamingConventions.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[WhileLoopsMustUseBraces](./rules/WhileLoopsMustUseBraces.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[XPathRule](./rules/XPathRule.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: - -## PMD Unit Test Rules -Rule name | Deprecated? | Alternative | Description up-to-date | Checked on -----------|-------------|-------------|------------------------|----------- -[JUnit4SuitesShouldUseSuiteAnnotation](./rules/JUnit4SuitesShouldUseSuiteAnnotation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[JUnit4TestShouldUseAfterAnnotation](./rules/JUnit4TestShouldUseAfterAnnotation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[JUnit4TestShouldUseBeforeAnnotation](./rules/JUnit4TestShouldUseBeforeAnnotation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[JUnit4TestShouldUseTestAnnotation](./rules/JUnit4TestShouldUseTestAnnotation.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[JUnitAssertionsShouldIncludeMessage](./rules/JUnitAssertionsShouldIncludeMessage.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[JUnitSpelling](./rules/JUnitSpelling.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[JUnitStaticSuite](./rules/JUnitStaticSuite.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[JUnitTestContainsTooManyAsserts](./rules/JUnitTestContainsTooManyAsserts.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[JUnitTestsShouldIncludeAssert](./rules/JUnitTestsShouldIncludeAssert.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[JUnitUseExpected](./rules/JUnitUseExpected.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[SimplifyBooleanAssertion](./rules/SimplifyBooleanAssertion.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[TestClassWithoutTestCases](./rules/TestClassWithoutTestCases.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UnnecessaryBooleanAssertion](./rules/UnnecessaryBooleanAssertion.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseAssertEqualsInsteadOfAssertTrue](./rules/UseAssertEqualsInsteadOfAssertTrue.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseAssertNullInsteadOfAssertTrue](./rules/UseAssertNullInsteadOfAssertTrue.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseAssertSameInsteadOfAssertTrue](./rules/UseAssertSameInsteadOfAssertTrue.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: -[UseAssertTrueInsteadOfAssertEquals](./rules/UseAssertTrueInsteadOfAssertEquals.md) | :question: | :heavy_minus_sign: | :question: | :heavy_minus_sign: diff --git a/docs/create_rules.groovy b/docs/create_rules.groovy deleted file mode 100644 index 804f6aaa..00000000 --- a/docs/create_rules.groovy +++ /dev/null @@ -1,74 +0,0 @@ -import groovy.io.FileType - -println '====================================' -println 'Creating markdown rule documentation' -println '====================================' - - -def ruleSourcePath = '../sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules' -def ruleTargetPath = './rules' - -def createDeprecationWarning = { - rules -> - - if (!rules.isEmpty()) { - def parsedRules = rules.collect { - def ruleNumber = it.substring(1) - (ruleNumber.isInteger()) ? - "[${it}](https://rules.sonarsource.com/java/RSPEC-${ruleNumber.toInteger()})" : "`squid:${it}`" - } - - return "> :warning: This rule is **deprecated** in favour of ${parsedRules.join(', ')}." - } - "" -} - -def extractRulesFromContent = { - content -> - def pattern = /(rule):(squid):(\w+)/ - def group = (content =~ /$pattern/) - - return group.collect { - it[3] - } -} - -def removeDeprecationMessage = { - content -> - def regex = /(?ms)

(\s*)This rule is deprecated, use \{rule:squid:(\w+)\} (.*)instead.(\s*)<\/p>/ - - if (content =~ regex) { - return content.replaceFirst(regex, "") - } - - return content -} - -def createMarkdownPagesForCategory = { - category -> - def currentDir = new File("${ruleSourcePath}/${category}") - currentDir.eachFile FileType.FILES, { - String rulename = it.name.tokenize('.')[0] - - println " * Processing Rule ${rulename}" - - String htmlContent = it.text - String deprecationWarning = createDeprecationWarning(extractRulesFromContent(htmlContent)) - htmlContent = removeDeprecationMessage(htmlContent).trim() - String ruleContent = """# ${rulename} -**Category:** `${category}`
-**Rule Key:** `${category}:${rulename}`
-${deprecationWarning} - ------ - -${htmlContent} -""" - def file = new File("${ruleTargetPath}/${rulename}.md").newWriter() - file << ruleContent - file.close() - } -} - -createMarkdownPagesForCategory('pmd') -createMarkdownPagesForCategory('pmd-unit-tests') \ No newline at end of file diff --git a/docs/pmd_release_notes_4.1.0.md b/docs/pmd_release_notes_4.1.0.md new file mode 100644 index 00000000..373a287b --- /dev/null +++ b/docs/pmd_release_notes_4.1.0.md @@ -0,0 +1,339 @@ +# PMD Rules Release Notes for version 4.1.0 +_Do not edit this generated file._ + +## Summary +- Total rules in old version (4.0.3): 206 +- Total rules in new version (4.1.0): 282 +- Rules added: 80 +- Rules removed: 4 +- Rules unchanged: 46 +- Rules updated: 155 +- Rules renamed: 11 + +## Added Rules +The following rules have been added in the new version: + +| Rule Key | Name | Severity | Category | +|----------|------|----------|----------| +| AccessorMethodGeneration | Accessor method generation | Medium | bestpractices | +| AvoidCalendarDateCreation | Avoid calendar date creation | Medium | performance | +| AvoidFileStream | Avoid file stream | Blocker | performance | +| AvoidMessageDigestField | Avoid message digest field | Medium | bestpractices | +| AvoidReassigningCatchVariables | Avoid reassigning catch variables | Medium | bestpractices | +| AvoidReassigningLoopVariables | Avoid reassigning loop variables | Medium | bestpractices | +| AvoidSynchronizedStatement | Avoid synchronized statement | Medium | multithreading | +| AvoidUncheckedExceptionsInSignatures | Avoid unchecked exceptions in signatures | Medium | design | +| CloneMethodMustImplementCloneable | Clone method must implement cloneable | Medium | errorprone | +| CognitiveComplexity | Cognitive complexity | Medium | design | +| ComparisonWithNaN | Comparison with na n | Medium | errorprone | +| ConfusingArgumentToVarargsMethod | Confusing argument to varargs method | Medium | errorprone | +| ConstantsInInterface | Constants in interface | Medium | bestpractices | +| ControlStatementBraces | Control statement braces | Medium | codestyle | +| DataClass | Data class | Medium | design | +| DefaultLabelNotLastInSwitch | Default label not last in switch | Medium | bestpractices | +| DetachedTestCase | Detached test case | Medium | errorprone | +| DoNotExtendJavaLangThrowable | Do not extend java lang throwable | Medium | errorprone | +| DoNotTerminateVM | Do not terminate VM | Medium | errorprone | +| DoubleBraceInitialization | Double brace initialization | Medium | bestpractices | +| EmptyControlStatement | Empty control statement | Medium | codestyle | +| ExhaustiveSwitchHasDefault | Exhaustive switch has default | Medium | bestpractices | +| FieldNamingConventions | Field naming conventions | Blocker | codestyle | +| FinalParameterInAbstractMethod | Final parameter in abstract method | Blocker | codestyle | +| ForLoopCanBeForeach | For loop can be foreach | Medium | bestpractices | +| ForLoopVariableCount | For loop variable count | Medium | bestpractices | +| FormalParameterNamingConventions | Formal parameter naming conventions | Blocker | codestyle | +| HardCodedCryptoKey | Hard coded crypto key | Medium | security | +| IdenticalCatchBranches | Identical catch branches | Medium | codestyle | +| ImplicitFunctionalInterface | Implicit functional interface | High | bestpractices | +| ImplicitSwitchFallThrough | Implicit switch fall through | Medium | errorprone | +| InsecureCryptoIv | Insecure crypto iv | Medium | security | +| InvalidJavaBean | Invalid java bean | Medium | design | +| InvalidLogMessageFormat | Invalid log message format | Info | errorprone | +| JUnit4SuitesShouldUseSuiteAnnotation | JUnit4 suites should use suite annotation | Medium | bestpractices | +| JUnit5TestShouldBePackagePrivate | JUnit5 test should be package private | Medium | bestpractices | +| JUnitSpelling | JUnit spelling | Medium | errorprone | +| JUnitStaticSuite | JUnit static suite | Medium | errorprone | +| JUnitUseExpected | JUnit use expected | Medium | bestpractices | +| LambdaCanBeMethodReference | Lambda can be method reference | Medium | codestyle | +| LinguisticNaming | Linguistic naming | Medium | codestyle | +| LiteralsFirstInComparisons | Literals first in comparisons | Medium | bestpractices | +| LocalVariableNamingConventions | Local variable naming conventions | Blocker | codestyle | +| LooseCoupling | Loose coupling | Medium | bestpractices | +| MissingOverride | Missing override | Medium | bestpractices | +| MutableStaticState | Mutable static state | Medium | design | +| NcssCount | Ncss count | Medium | design | +| NonCaseLabelInSwitch | Non case label in switch | Medium | errorprone | +| NonExhaustiveSwitch | Non exhaustive switch | Medium | bestpractices | +| NonSerializableClass | Non serializable class | Medium | errorprone | +| PrimitiveWrapperInstantiation | Primitive wrapper instantiation | Medium | bestpractices | +| ReturnEmptyCollectionRatherThanNull | Return empty collection rather than null | Blocker | errorprone | +| SimplifiableTestAssertion | Simplifiable test assertion | Medium | bestpractices | +| TestClassWithoutTestCases | Test class without test cases | Medium | errorprone | +| TooFewBranchesForSwitch | Too few branches for switch | Medium | performance | +| UnitTestAssertionsShouldIncludeMessage | Unit test assertions should include message | Medium | bestpractices | +| UnitTestContainsTooManyAsserts | Unit test contains too many asserts | Medium | bestpractices | +| UnitTestShouldIncludeAssert | Unit test should include assert | Medium | bestpractices | +| UnitTestShouldUseAfterAnnotation | Unit test should use after annotation | Medium | bestpractices | +| UnitTestShouldUseBeforeAnnotation | Unit test should use before annotation | Medium | bestpractices | +| UnitTestShouldUseTestAnnotation | Unit test should use test annotation | Medium | bestpractices | +| UnnecessaryAnnotationValueElement | Unnecessary annotation value element | Medium | codestyle | +| UnnecessaryBooleanAssertion | Unnecessary boolean assertion | Medium | errorprone | +| UnnecessaryBoxing | Unnecessary boxing | Medium | codestyle | +| UnnecessaryCast | Unnecessary cast | Medium | codestyle | +| UnnecessaryImport | Unnecessary import | Low | codestyle | +| UnnecessaryModifier | Unnecessary modifier | Medium | codestyle | +| UnnecessarySemicolon | Unnecessary semicolon | Medium | codestyle | +| UnnecessaryVarargsArrayCreation | Unnecessary varargs array creation | Medium | bestpractices | +| UnnecessaryWarningSuppression | Unnecessary warning suppression | Medium | bestpractices | +| UnsynchronizedStaticFormatter | Unsynchronized static formatter | Medium | multithreading | +| UseDiamondOperator | Use diamond operator | Medium | codestyle | +| UseEnumCollections | Use enum collections | Medium | bestpractices | +| UseExplicitTypes | Use explicit types | Medium | codestyle | +| UseIOStreamsWithApacheCommonsFileItem | Use IOStreams with apache commons file item | Medium | performance | +| UseShortArrayInitializer | Use short array initializer | Medium | codestyle | +| UseStandardCharsets | Use standard charsets | Medium | bestpractices | +| UseTryWithResources | Use try with resources | Medium | bestpractices | +| UseUnderscoresInNumericLiterals | Use underscores in numeric literals | Medium | codestyle | +| WhileLoopWithLiteralBoolean | While loop with literal boolean | Medium | bestpractices | + +## Updated Rules +The following rules have been updated in the new version: + +| Rule Key | Name | Old Priority | New Severity | Old Status | New Status | Alternatives | Category | +|----------|------|--------------|--------------|------------|------------|--------------|----------| +| AbstractClassWithoutAbstractMethod | Abstract class without abstract method | | Medium | Deprecated | Active | [java:S1694](https://rules.sonarsource.com/java/RSPEC-1694) | bestpractices | +| AbstractClassWithoutAnyMethod | Abstract class without any method | Medium | Blocker | Deprecated | Active | [java:S1694](https://rules.sonarsource.com/java/RSPEC-1694) | design | +| AppendCharacterWithChar | Append character with char | Low | Medium | | Active | | performance | +| ArrayIsStoredDirectly | Array is stored directly | High | Medium | Deprecated | Active | [java:S2384](https://rules.sonarsource.com/java/RSPEC-2384) | bestpractices | +| AssignmentInOperand | Assignment in operand | | Medium | Deprecated | Active | [java:S1121](https://rules.sonarsource.com/java/RSPEC-1121) | errorprone | +| AtLeastOneConstructor | At least one constructor | | Medium | Deprecated | Active | [java:S1118](https://rules.sonarsource.com/java/RSPEC-1118), [java:S1258](https://rules.sonarsource.com/java/RSPEC-1258) | codestyle | +| AvoidAssertAsIdentifier | Avoid assert as identifier | Medium | High | Deprecated | Active | [java:S1190](https://rules.sonarsource.com/java/RSPEC-1190) | errorprone | +| AvoidBranchingStatementAsLastInLoop | Avoid branching statement as last in loop | Medium | High | | Active | | errorprone | +| AvoidCallingFinalize | Avoid calling finalize | | Medium | Deprecated | Active | | errorprone | +| AvoidCatchingGenericException | Avoid catching generic exception | | Medium | Deprecated | Active | [java:S2221](https://rules.sonarsource.com/java/RSPEC-2221) | design | +| AvoidCatchingNPE | Avoid catching NPE | | Medium | Deprecated | Active | [java:S1696](https://rules.sonarsource.com/java/RSPEC-1696) | errorprone | +| AvoidCatchingThrowable | Avoid catching throwable | High | Medium | Deprecated | Active | [java:S1181](https://rules.sonarsource.com/java/RSPEC-1181) | errorprone | +| AvoidDecimalLiteralsInBigDecimalConstructor | Avoid decimal literals in big decimal constructor | | Medium | Deprecated | Active | [java:S2111](https://rules.sonarsource.com/java/RSPEC-2111) | errorprone | +| AvoidDeeplyNestedIfStmts | Avoid deeply nested if stmts | | Medium | Deprecated | Active | [java:S134](https://rules.sonarsource.com/java/RSPEC-134) | design | +| AvoidDollarSigns | Avoid dollar signs | Low | Medium | Deprecated | Active | [java:S114](https://rules.sonarsource.com/java/RSPEC-114), [java:S115](https://rules.sonarsource.com/java/RSPEC-115), [java:S116](https://rules.sonarsource.com/java/RSPEC-116), [java:S117](https://rules.sonarsource.com/java/RSPEC-117) | codestyle | +| AvoidDuplicateLiterals | Avoid duplicate literals | | Medium | Deprecated | Active | [java:S1192](https://rules.sonarsource.com/java/RSPEC-1192) | errorprone | +| AvoidEnumAsIdentifier | Avoid enum as identifier | Medium | High | Deprecated | Active | [java:S1190](https://rules.sonarsource.com/java/RSPEC-1190) | errorprone | +| AvoidFieldNameMatchingMethodName | Avoid field name matching method name | | Medium | Deprecated | Active | [java:S1845](https://rules.sonarsource.com/java/RSPEC-1845) | errorprone | +| AvoidFieldNameMatchingTypeName | Avoid field name matching type name | | Medium | Deprecated | Active | [java:S1700](https://rules.sonarsource.com/java/RSPEC-1700) | errorprone | +| AvoidInstanceofChecksInCatchClause | Avoid instanceof checks in catch clause | Low | Medium | Deprecated | Active | [java:S1193](https://rules.sonarsource.com/java/RSPEC-1193) | errorprone | +| AvoidInstantiatingObjectsInLoops | Avoid instantiating objects in loops | Low | Medium | | Active | | performance | +| AvoidLiteralsInIfCondition | Avoid literals in if condition | | Medium | Deprecated | Active | [java:S109](https://rules.sonarsource.com/java/RSPEC-109) | errorprone | +| AvoidLosingExceptionInformation | Avoid losing exception information | Medium | High | Deprecated | Active | [java:S1166](https://rules.sonarsource.com/java/RSPEC-1166) | errorprone | +| AvoidMultipleUnaryOperators | Avoid multiple unary operators | Medium | High | Deprecated | Active | [java:S881](https://rules.sonarsource.com/java/RSPEC-881) | errorprone | +| AvoidPrintStackTrace | Avoid print stack trace | | Medium | Deprecated | Active | [java:S1148](https://rules.sonarsource.com/java/RSPEC-1148) | bestpractices | +| AvoidProtectedFieldInFinalClass | Avoid protected field in final class | | Medium | Deprecated | Active | [java:S2156](https://rules.sonarsource.com/java/RSPEC-2156) | codestyle | +| AvoidProtectedMethodInFinalClassNotExtending | Avoid protected method in final class not extending | | Medium | Deprecated | Active | [java:S2156](https://rules.sonarsource.com/java/RSPEC-2156) | codestyle | +| AvoidReassigningParameters | Avoid reassigning parameters | Medium | High | Deprecated | Active | [java:S1226](https://rules.sonarsource.com/java/RSPEC-1226) | bestpractices | +| AvoidRethrowingException | Avoid rethrowing exception | | Medium | Deprecated | Active | [java:S1166](https://rules.sonarsource.com/java/RSPEC-1166) | design | +| AvoidStringBufferField | Avoid string buffer field | | Medium | Deprecated | Active | [java:S1149](https://rules.sonarsource.com/java/RSPEC-1149) | bestpractices | +| AvoidThreadGroup | Avoid thread group | High | Medium | | Active | | multithreading | +| AvoidThrowingNewInstanceOfSameException | Avoid throwing new instance of same exception | | Medium | Deprecated | Active | [java:S1166](https://rules.sonarsource.com/java/RSPEC-1166) | design | +| AvoidThrowingNullPointerException | Avoid throwing null pointer exception | Medium | Blocker | Deprecated | Active | [java:S1695](https://rules.sonarsource.com/java/RSPEC-1695) | design | +| AvoidThrowingRawExceptionTypes | Avoid throwing raw exception types | Medium | Blocker | Deprecated | Active | [java:S112](https://rules.sonarsource.com/java/RSPEC-112) | design | +| AvoidUsingHardCodedIP | Avoid using hard coded IP | | Medium | Deprecated | Active | [java:S1313](https://rules.sonarsource.com/java/RSPEC-1313) | bestpractices | +| AvoidUsingNativeCode | Avoid using native code | Medium | High | | Active | | codestyle | +| AvoidUsingOctalValues | Avoid using octal values | | Medium | Deprecated | Active | [java:S1314](https://rules.sonarsource.com/java/RSPEC-1314) | errorprone | +| AvoidUsingVolatile | Avoid using volatile | Medium | High | | Active | | multithreading | +| BooleanGetMethodName | Boolean get method name | Medium | Low | | Active | | codestyle | +| BrokenNullCheck | Broken null check | | High | Deprecated | Active | [java:S1697](https://rules.sonarsource.com/java/RSPEC-1697) | errorprone | +| CallSuperInConstructor | Call super in constructor | Low | Medium | | Active | | codestyle | +| CheckSkipResult | Check skip result | Low | Medium | Deprecated | Active | [java:S2674](https://rules.sonarsource.com/java/RSPEC-2674) | errorprone | +| ClassNamingConventions | Class naming conventions | Medium | Blocker | Deprecated | Active | [java:S101](https://rules.sonarsource.com/java/RSPEC-101), [java:S114](https://rules.sonarsource.com/java/RSPEC-114) | codestyle | +| ClassWithOnlyPrivateConstructorsShouldBeFinal | Class with only private constructors should be final | Medium | Blocker | Deprecated | Active | [java:S2974](https://rules.sonarsource.com/java/RSPEC-2974) | design | +| CloseResource | Close resource | High | Medium | Deprecated | Active | [java:S2095](https://rules.sonarsource.com/java/RSPEC-2095) | errorprone | +| CollapsibleIfStatements | Collapsible if statements | Low | Medium | Deprecated | Active | [java:S1066](https://rules.sonarsource.com/java/RSPEC-1066) | design | +| CommentContent | Comment content | Low | Medium | | Active | | documentation | +| CommentRequired | Comment required | Low | Medium | | Active | | documentation | +| CommentSize | Comment size | Low | Medium | | Active | | documentation | +| CompareObjectsWithEquals | Compare objects with equals | | Medium | Deprecated | Active | [java:S1698](https://rules.sonarsource.com/java/RSPEC-1698) | errorprone | +| ConsecutiveLiteralAppends | Consecutive literal appends | Low | Medium | | Active | | performance | +| ConstructorCallsOverridableMethod | Constructor calls overridable method | Medium | Blocker | Deprecated | Active | [java:S1699](https://rules.sonarsource.com/java/RSPEC-1699) | errorprone | +| CouplingBetweenObjects | Coupling between objects | | Medium | Deprecated | Active | [java:S1200](https://rules.sonarsource.com/java/RSPEC-1200) | design | +| CyclomaticComplexity | Cyclomatic complexity | | Medium | Deprecated | Active | [java:S1541](https://rules.sonarsource.com/java/RSPEC-1541) | design | +| DoNotCallGarbageCollectionExplicitly | Do not call garbage collection explicitly | | High | Deprecated | Active | [java:S1215](https://rules.sonarsource.com/java/RSPEC-1215) | errorprone | +| DoNotExtendJavaLangError | Do not extend java lang error | | Medium | Deprecated | Active | [java:S1194](https://rules.sonarsource.com/java/RSPEC-1194) | design | +| DoNotThrowExceptionInFinally | Do not throw exception in finally | Medium | Low | Deprecated | Active | [java:S1163](https://rules.sonarsource.com/java/RSPEC-1163) | errorprone | +| DontCallThreadRun | Dont call thread run | Medium | Low | Deprecated | Active | [java:S1217](https://rules.sonarsource.com/java/RSPEC-1217) | multithreading | +| DontImportSun | Dont import sun | | Low | Deprecated | Active | [java:S1191](https://rules.sonarsource.com/java/RSPEC-1191) | errorprone | +| DoubleCheckedLocking | Double checked locking | Medium | Blocker | | Active | | multithreading | +| EmptyCatchBlock | Empty catch block | High | Medium | Deprecated | Active | [java:S108](https://rules.sonarsource.com/java/RSPEC-108) | errorprone | +| EmptyFinalizer | Empty finalizer | | Medium | Deprecated | Active | [java:S1186](https://rules.sonarsource.com/java/RSPEC-1186) | errorprone | +| EmptyMethodInAbstractClassShouldBeAbstract | Empty method in abstract class should be abstract | Medium | Blocker | | Active | | codestyle | +| EqualsNull | Equals null | High | Blocker | Deprecated | Active | [java:S2159](https://rules.sonarsource.com/java/RSPEC-2159) | errorprone | +| ExceptionAsFlowControl | Exception as flow control | | Medium | Deprecated | Active | [java:S1141](https://rules.sonarsource.com/java/RSPEC-1141) | design | +| ExcessiveImports | Excessive imports | | Medium | Deprecated | Active | [java:S1200](https://rules.sonarsource.com/java/RSPEC-1200) | design | +| ExcessiveParameterList | Excessive parameter list | | Medium | Deprecated | Active | [java:S107](https://rules.sonarsource.com/java/RSPEC-107) | design | +| ExcessivePublicCount | Excessive public count | | Medium | Deprecated | Active | [java:S1448](https://rules.sonarsource.com/java/RSPEC-1448) | design | +| ExtendsObject | Extends object | | Low | Deprecated | Active | [java:S1939](https://rules.sonarsource.com/java/RSPEC-1939) | codestyle | +| FieldDeclarationsShouldBeAtStartOfClass | Field declarations should be at start of class | Low | Medium | Deprecated | Active | [java:S1213](https://rules.sonarsource.com/java/RSPEC-1213) | codestyle | +| FinalFieldCouldBeStatic | Final field could be static | Low | Medium | Deprecated | Active | [java:S1170](https://rules.sonarsource.com/java/RSPEC-1170) | design | +| FinalizeDoesNotCallSuperFinalize | Finalize does not call super finalize | | Medium | Deprecated | Active | | errorprone | +| FinalizeOnlyCallsSuperFinalize | Finalize only calls super finalize | | Medium | Deprecated | Active | [java:S1185](https://rules.sonarsource.com/java/RSPEC-1185) | errorprone | +| FinalizeOverloaded | Finalize overloaded | | Medium | Deprecated | Active | [java:S1175](https://rules.sonarsource.com/java/RSPEC-1175) | errorprone | +| FinalizeShouldBeProtected | Finalize should be protected | | Medium | Deprecated | Active | [java:S1174](https://rules.sonarsource.com/java/RSPEC-1174) | errorprone | +| ForLoopShouldBeWhileLoop | For loop should be while loop | Low | Medium | Deprecated | Active | [java:S1264](https://rules.sonarsource.com/java/RSPEC-1264) | codestyle | +| GenericsNaming | Generics naming | Medium | Low | Deprecated | Active | [java:S119](https://rules.sonarsource.com/java/RSPEC-119) | codestyle | +| IdempotentOperations | Idempotent operations | | Medium | Deprecated | Active | [java:S1656](https://rules.sonarsource.com/java/RSPEC-1656) | errorprone | +| InstantiationToGetClass | Instantiation to get class | Medium | Low | Deprecated | Active | [java:S2133](https://rules.sonarsource.com/java/RSPEC-2133) | errorprone | +| JumbledIncrementer | Jumbled incrementer | | Medium | Deprecated | Active | [java:S1994](https://rules.sonarsource.com/java/RSPEC-1994) | errorprone | +| LocalHomeNamingConvention | Local home naming convention | Medium | Low | | Active | | codestyle | +| LocalInterfaceSessionNamingConvention | Local interface session naming convention | Medium | Low | | Active | | codestyle | +| LocalVariableCouldBeFinal | Local variable could be final | Low | Medium | | Active | | codestyle | +| LogicInversion | Logic inversion | Low | Medium | Deprecated | Active | [java:S1940](https://rules.sonarsource.com/java/RSPEC-1940) | design | +| LongVariable | Long variable | | Medium | Deprecated | Active | [java:S117](https://rules.sonarsource.com/java/RSPEC-117) | codestyle | +| LoosePackageCoupling | Loose package coupling | | Medium | Deprecated | Active | | design | +| MDBAndSessionBeanNamingConvention | MDBAnd session bean naming convention | Medium | Low | | Active | | codestyle | +| MethodArgumentCouldBeFinal | Method argument could be final | Low | Medium | Deprecated | Active | [java:S1226](https://rules.sonarsource.com/java/RSPEC-1226) | codestyle | +| MethodNamingConventions | Method naming conventions | Medium | Blocker | Deprecated | Active | [java:S100](https://rules.sonarsource.com/java/RSPEC-100) | codestyle | +| MethodReturnsInternalArray | Method returns internal array | High | Medium | Deprecated | Active | [java:S2384](https://rules.sonarsource.com/java/RSPEC-2384) | bestpractices | +| MethodWithSameNameAsEnclosingClass | Method with same name as enclosing class | | Medium | Deprecated | Active | [java:S1223](https://rules.sonarsource.com/java/RSPEC-1223) | errorprone | +| MisplacedNullCheck | Misplaced null check | High | Medium | Deprecated | Active | [java:S1697](https://rules.sonarsource.com/java/RSPEC-1697), [java:S2259](https://rules.sonarsource.com/java/RSPEC-2259) | errorprone | +| MissingSerialVersionUID | Missing serial version UID | | Medium | Deprecated | Active | [java:S2057](https://rules.sonarsource.com/java/RSPEC-2057) | errorprone | +| MoreThanOneLogger | More than one logger | Medium | High | Deprecated | Active | [java:S1312](https://rules.sonarsource.com/java/RSPEC-1312) | errorprone | +| NoPackage | No package | | Medium | Deprecated | Active | [java:S1220](https://rules.sonarsource.com/java/RSPEC-1220) | codestyle | +| NonStaticInitializer | Non static initializer | | Medium | Deprecated | Active | [java:S1171](https://rules.sonarsource.com/java/RSPEC-1171) | errorprone | +| NonThreadSafeSingleton | Non thread safe singleton | | Medium | Deprecated | Active | [java:S2444](https://rules.sonarsource.com/java/RSPEC-2444) | multithreading | +| OneDeclarationPerLine | One declaration per line | Medium | Low | Deprecated | Active | [java:S122](https://rules.sonarsource.com/java/RSPEC-122) | bestpractices | +| OnlyOneReturn | Only one return | Low | Medium | Deprecated | Active | [java:S1142](https://rules.sonarsource.com/java/RSPEC-1142) | codestyle | +| OverrideBothEqualsAndHashcode | Override both equals and hashcode | Blocker | Medium | Deprecated | Active | [java:S1206](https://rules.sonarsource.com/java/RSPEC-1206) | errorprone | +| PackageCase | Package case | | Medium | Deprecated | Active | [java:S120](https://rules.sonarsource.com/java/RSPEC-120) | codestyle | +| PrematureDeclaration | Premature declaration | | Medium | Deprecated | Active | [java:S1941](https://rules.sonarsource.com/java/RSPEC-1941) | codestyle | +| PreserveStackTrace | Preserve stack trace | | Medium | Deprecated | Active | [java:S1166](https://rules.sonarsource.com/java/RSPEC-1166) | bestpractices | +| ProperCloneImplementation | Proper clone implementation | | High | Deprecated | Active | [java:S1182](https://rules.sonarsource.com/java/RSPEC-1182) | errorprone | +| ProperLogger | Proper logger | | Medium | Deprecated | Active | [java:S1312](https://rules.sonarsource.com/java/RSPEC-1312) | errorprone | +| RemoteInterfaceNamingConvention | Remote interface naming convention | Medium | Low | | Active | | codestyle | +| RemoteSessionInterfaceNamingConvention | Remote session interface naming convention | Medium | Low | | Active | | codestyle | +| ReplaceEnumerationWithIterator | Replace enumeration with iterator | | Medium | Deprecated | Active | [java:S1150](https://rules.sonarsource.com/java/RSPEC-1150) | bestpractices | +| ReplaceHashtableWithMap | Replace hashtable with map | | Medium | Deprecated | Active | [java:S1149](https://rules.sonarsource.com/java/RSPEC-1149) | bestpractices | +| ReplaceVectorWithList | Replace vector with list | | Medium | Deprecated | Active | [java:S1149](https://rules.sonarsource.com/java/RSPEC-1149) | bestpractices | +| ReturnFromFinallyBlock | Return from finally block | | Medium | Deprecated | Active | [java:S1143](https://rules.sonarsource.com/java/RSPEC-1143) | errorprone | +| ShortClassName | Short class name | | Low | Deprecated | Active | [java:S101](https://rules.sonarsource.com/java/RSPEC-101) | codestyle | +| ShortMethodName | Short method name | | Medium | Deprecated | Active | [java:S100](https://rules.sonarsource.com/java/RSPEC-100) | codestyle | +| ShortVariable | Short variable | | Medium | Deprecated | Active | [java:S117](https://rules.sonarsource.com/java/RSPEC-117) | codestyle | +| SignatureDeclareThrowsException | Signature declare throws exception | | Medium | Deprecated | Active | [java:S112](https://rules.sonarsource.com/java/RSPEC-112) | design | +| SimplifyBooleanExpressions | Simplify boolean expressions | | Medium | Deprecated | Active | [java:S1125](https://rules.sonarsource.com/java/RSPEC-1125) | design | +| SimplifyBooleanReturns | Simplify boolean returns | Low | Medium | Deprecated | Active | [java:S1126](https://rules.sonarsource.com/java/RSPEC-1126) | design | +| SingletonClassReturningNewInstance | Singleton class returning new instance | Medium | High | | Active | | errorprone | +| SingularField | Singular field | Low | Medium | | Active | | design | +| StringBufferInstantiationWithChar | String buffer instantiation with char | Medium | Low | Deprecated | Active | [java:S1317](https://rules.sonarsource.com/java/RSPEC-1317) | errorprone | +| StringInstantiation | String instantiation | Medium | High | | Active | | performance | +| StringToString | String to string | | Medium | Deprecated | Active | [java:S1858](https://rules.sonarsource.com/java/RSPEC-1858) | performance | +| SuspiciousEqualsMethodName | Suspicious equals method name | | High | Deprecated | Active | [java:S1201](https://rules.sonarsource.com/java/RSPEC-1201) | errorprone | +| SuspiciousHashcodeMethodName | Suspicious hashcode method name | | Medium | Deprecated | Active | [java:S1221](https://rules.sonarsource.com/java/RSPEC-1221) | errorprone | +| SwitchDensity | Switch density | | Medium | Deprecated | Active | [java:S1151](https://rules.sonarsource.com/java/RSPEC-1151) | design | +| SystemPrintln | System println | Medium | High | Deprecated | Active | [java:S106](https://rules.sonarsource.com/java/RSPEC-106) | bestpractices | +| TooManyMethods | Too many methods | | Medium | Deprecated | Active | [java:S1448](https://rules.sonarsource.com/java/RSPEC-1448) | design | +| UncommentedEmptyConstructor | Uncommented empty constructor | | Medium | Deprecated | Active | [java:S2094](https://rules.sonarsource.com/java/RSPEC-2094) | documentation | +| UncommentedEmptyMethodBody | Uncommented empty method body | | Medium | Deprecated | Active | [java:S1186](https://rules.sonarsource.com/java/RSPEC-1186) | documentation | +| UnconditionalIfStatement | Unconditional if statement | High | Medium | Deprecated | Active | [java:S2583](https://rules.sonarsource.com/java/RSPEC-2583) | errorprone | +| UnnecessaryCaseChange | Unnecessary case change | Low | Medium | Deprecated | Active | [java:S1157](https://rules.sonarsource.com/java/RSPEC-1157) | errorprone | +| UnnecessaryConstructor | Unnecessary constructor | | Medium | Deprecated | Active | [java:S1186](https://rules.sonarsource.com/java/RSPEC-1186) | codestyle | +| UnnecessaryConversionTemporary | Unnecessary conversion temporary | | Medium | Deprecated | Active | [java:S1158](https://rules.sonarsource.com/java/RSPEC-1158) | errorprone | +| UnnecessaryFullyQualifiedName | Unnecessary fully qualified name | Medium | Low | | Active | | codestyle | +| UnnecessaryLocalBeforeReturn | Unnecessary local before return | | Medium | Deprecated | Active | [java:S1488](https://rules.sonarsource.com/java/RSPEC-1488) | codestyle | +| UnnecessaryReturn | Unnecessary return | Low | Medium | | Active | | codestyle | +| UnusedFormalParameter | Unused formal parameter | | Medium | Deprecated | Active | [java:S1172](https://rules.sonarsource.com/java/RSPEC-1172) | bestpractices | +| UnusedLocalVariable | Unused local variable | | Medium | Deprecated | Active | [java:S1481](https://rules.sonarsource.com/java/RSPEC-1481) | bestpractices | +| UnusedPrivateField | Unused private field | | Medium | Deprecated | Active | [java:S1068](https://rules.sonarsource.com/java/RSPEC-1068) | bestpractices | +| UnusedPrivateMethod | Unused private method | | Medium | Deprecated | Active | | bestpractices | +| UseArrayListInsteadOfVector | Use array list instead of vector | | Medium | Deprecated | Active | [java:S1149](https://rules.sonarsource.com/java/RSPEC-1149) | performance | +| UseCollectionIsEmpty | Use collection is empty | Low | Medium | Deprecated | Active | [java:S1155](https://rules.sonarsource.com/java/RSPEC-1155) | bestpractices | +| UseCorrectExceptionLogging | Use correct exception logging | | Medium | Deprecated | Active | [java:S1166](https://rules.sonarsource.com/java/RSPEC-1166) | errorprone | +| UseEqualsToCompareStrings | Use equals to compare strings | | Medium | Deprecated | Active | [java:S1698](https://rules.sonarsource.com/java/RSPEC-1698) | errorprone | +| UseNotifyAllInsteadOfNotify | Use notify all instead of notify | | Medium | Deprecated | Active | [java:S2446](https://rules.sonarsource.com/java/RSPEC-2446) | multithreading | +| UseObjectForClearerAPI | Use object for clearer API | Low | Medium | Deprecated | Active | [java:S107](https://rules.sonarsource.com/java/RSPEC-107) | design | +| UseProperClassLoader | Use proper class loader | High | Medium | | Active | | errorprone | +| UseStringBufferLength | Use string buffer length | Low | Medium | | Active | | performance | +| UseUtilityClass | Use utility class | | Medium | Deprecated | Active | [java:S1118](https://rules.sonarsource.com/java/RSPEC-1118) | design | +| UseVarargs | Use varargs | Medium | Low | | Active | | bestpractices | +| UselessOperationOnImmutable | Useless operation on immutable | High | Medium | | Active | | errorprone | +| UselessOverridingMethod | Useless overriding method | | Medium | Deprecated | Active | [java:S1185](https://rules.sonarsource.com/java/RSPEC-1185) | design | +| UselessParentheses | Useless parentheses | Info | Low | Deprecated | Active | [java:S1110](https://rules.sonarsource.com/java/RSPEC-1110) | codestyle | +| UselessStringValueOf | Useless string value of | Low | Medium | Deprecated | Active | [java:S1153](https://rules.sonarsource.com/java/RSPEC-1153) | performance | +| XPathRule | XPath rule | Medium | | Deprecated | Active | | | + +## Unchanged Rules +The following rules exist in both versions with no changes: + +| Rule Key | Name | Severity | Status | Alternatives | Category | +|----------|------|----------|--------|--------------|----------| +| AccessorClassGeneration | Accessor class generation | Medium | Active | | bestpractices | +| AddEmptyString | Add empty string | Medium | Active | | performance | +| AssignmentToNonFinalStatic | Assignment to non final static | Medium | Active | | errorprone | +| AvoidAccessibilityAlteration | Avoid accessibility alteration | Medium | Active | | errorprone | +| AvoidArrayLoops | Avoid array loops | Medium | Active | | performance | +| AvoidSynchronizedAtMethodLevel | Avoid synchronized at method level | Medium | Active | | multithreading | +| BigIntegerInstantiation | Big integer instantiation | Medium | Active | | performance | +| CallSuperFirst | Call super first | Medium | Active | | errorprone | +| CallSuperLast | Call super last | Medium | Active | | errorprone | +| CheckResultSet | Check result set | Medium | Active | | bestpractices | +| ClassCastExceptionWithToArray | Class cast exception with to array | Medium | Active | | errorprone | +| CloneMethodMustBePublic | Clone method must be public | Medium | Active | | errorprone | +| CloneMethodReturnTypeMustMatchClassName | Clone method return type must match class name | Medium | Active | | errorprone | +| CommentDefaultAccessModifier | Comment default access modifier | Medium | Active | | codestyle | +| ConfusingTernary | Confusing ternary | Medium | Active | | codestyle | +| ConsecutiveAppendsShouldReuse | Consecutive appends should reuse | Medium | Active | | performance | +| DoNotHardCodeSDCard | Do not hard code SDCard | Medium | Active | | errorprone | +| DoNotUseThreads | Do not use threads | Medium | Active | | multithreading | +| DontUseFloatTypeForLoopIndices | Dont use float type for loop indices | Medium | Active | | errorprone | +| GodClass | God class | Medium | Active | | design | +| ImmutableField | Immutable field | Medium | Active | | design | +| InefficientEmptyStringCheck | Inefficient empty string check | Medium | Active | | performance | +| InefficientStringBuffering | Inefficient string buffering | Medium | Active | | performance | +| InsufficientStringBufferDeclaration | Insufficient string buffer declaration | Medium | Active | | performance | +| LawOfDemeter | Law of demeter | Medium | Active | | design | +| MissingStaticMethodInNonInstantiatableClass | Missing static method in non instantiatable class | Medium | Active | | errorprone | +| NPathComplexity | NPath complexity | Medium | Active | | design | +| NullAssignment | Null assignment | Medium | Active | | errorprone | +| OptimizableToArrayCall | Optimizable to array call | Medium | Active | | performance | +| RedundantFieldInitializer | Redundant field initializer | Medium | Active | | performance | +| SimpleDateFormatNeedsLocale | Simple date format needs locale | Medium | Active | | errorprone | +| SimplifiedTernary | Simplified ternary | Medium | Active | | design | +| SimplifyConditional | Simplify conditional | Medium | Active | | design | +| SingleMethodSingleton | Single method singleton | High | Active | | errorprone | +| StaticEJBFieldShouldBeFinal | Static EJBField should be final | Medium | Active | | errorprone | +| SuspiciousOctalEscape | Suspicious octal escape | Medium | Active | | errorprone | +| TooManyFields | Too many fields | Medium | Active | | design | +| TooManyStaticImports | Too many static imports | Medium | Active | | codestyle | +| UnusedAssignment | Unused assignment | Medium | Active | | bestpractices | +| UnusedNullCheckInEquals | Unused null check in equals | Medium | Active | | errorprone | +| UseArraysAsList | Use arrays as list | Medium | Active | | performance | +| UseConcurrentHashMap | Use concurrent hash map | Medium | Active | | multithreading | +| UseIndexOfChar | Use index of char | Medium | Active | | performance | +| UseLocaleWithCaseConversions | Use locale with case conversions | Medium | Active | | errorprone | +| UseStringBufferForStringAppends | Use string buffer for string appends | Medium | Active | | performance | +| UselessQualifiedThis | Useless qualified this | Medium | Active | | codestyle | + +## Renamed Rules +The following rules have new names: + +| Rule name | New rule name | Category | +|-----------|---------------|----------| +| DefaultLabelNotLastInSwitchStmt | DefaultLabelNotLastInSwitch | bestpractices | +| GuardLogStatementJavaUtil | GuardLogStatement | bestpractices | +| JUnit4TestShouldUseAfterAnnotation | UnitTestShouldUseAfterAnnotation | bestpractices | +| JUnit4TestShouldUseBeforeAnnotation | UnitTestShouldUseBeforeAnnotation | bestpractices | +| JUnit4TestShouldUseTestAnnotation | UnitTestShouldUseTestAnnotation | bestpractices | +| JUnitAssertionsShouldIncludeMessage | UnitTestAssertionsShouldIncludeMessage | bestpractices | +| JUnitTestContainsTooManyAsserts | UnitTestContainsTooManyAsserts | bestpractices | +| JUnitTestsShouldIncludeAssert | UnitTestShouldIncludeAssert | bestpractices | +| NonCaseLabelInSwitchStatement | NonCaseLabelInSwitch | errorprone | +| SwitchStmtsShouldHaveDefault | NonExhaustiveSwitch | bestpractices | +| TooFewBranchesForASwitchStatement | TooFewBranchesForSwitch | performance | + +## Removed Rules +The following rules have been removed in the new version: + +| Rule Key | Priority | Status | Category | +|----------|----------|--------|----------| +| AvoidConstantsInterface | Medium | Deprecated | bestpractices | +| CloneMethodMustImplementCloneableWithTypeResolution | Medium | Deprecated | errorprone | +| LooseCouplingWithTypeResolution | Medium | Deprecated | bestpractices | +| UnnecessaryParentheses | Low | Deprecated | codestyle | + +Report generated on Wed Jul 16 16:21:38 CEST 2025 diff --git a/docs/pmd_release_notes_4.2.0.md b/docs/pmd_release_notes_4.2.0.md new file mode 100644 index 00000000..ecd87b27 --- /dev/null +++ b/docs/pmd_release_notes_4.2.0.md @@ -0,0 +1,342 @@ +# PMD Rules Release Notes for version 4.2.0 +_Do not edit this generated file._ + +## Summary +- Total rules in old version (4.1.0): 282 +- Total rules in new version (4.2.0): 292 +- Rules added: 10 +- Rules removed: 0 +- Rules unchanged: 233 +- Rules updated: 49 +- Rules renamed: 10 + +## Added Rules +The following rules have been added in the new version: + +| Rule Key | Name | Severity | Category | +|----------|------|----------|----------| +| CollectionTypeMismatch | Collection type mismatch | Medium | errorprone | +| DanglingJavadoc | Dangling javadoc | Medium | documentation | +| ModifierOrder | Modifier order | Medium | codestyle | +| OverrideBothEqualsAndHashCodeOnComparable | Override both equals and hash code on comparable | Medium | errorprone | +| RelianceOnDefaultCharset | Reliance on default charset | Medium | bestpractices | +| ReplaceJavaUtilCalendar | Replace java util calendar | Medium | errorprone | +| ReplaceJavaUtilDate | Replace java util date | Medium | errorprone | +| TypeParameterNamingConventions | Type parameter naming conventions | Low | codestyle | +| UselessPureMethodCall | Useless pure method call | Medium | errorprone | +| VariableCanBeInlined | Variable can be inlined | Low | codestyle | + +## Updated Rules +The following rules have been updated in the new version: + +| Rule Key | Name | Old Severity | New Severity | Old Status | New Status | Alternatives | Category | +|----------|------|--------------|--------------|------------|------------|--------------|----------| +| AtLeastOneConstructor | At least one constructor | Medium | Low | | Active | | codestyle | +| AvoidDollarSigns | Avoid dollar signs | Medium | Low | | Active | | codestyle | +| AvoidLosingExceptionInformation | Avoid losing exception information | | | Active | Deprecated | | errorprone | +| AvoidProtectedFieldInFinalClass | Avoid protected field in final class | Medium | Low | | Active | | codestyle | +| AvoidProtectedMethodInFinalClassNotExtending | Avoid protected method in final class not extending | Medium | Low | | Active | | codestyle | +| AvoidUsingNativeCode | Avoid using native code | High | Medium | | Active | | codestyle | +| CallSuperInConstructor | Call super in constructor | Medium | Low | | Active | | codestyle | +| ClassNamingConventions | Class naming conventions | Blocker | Medium | | Active | | codestyle | +| CommentDefaultAccessModifier | Comment default access modifier | Medium | Low | | Active | | codestyle | +| ConfusingTernary | Confusing ternary | Medium | Low | | Active | | codestyle | +| ControlStatementBraces | Control statement braces | Medium | Low | | Active | | codestyle | +| EmptyControlStatement | Empty control statement | Medium | Low | | Active | | codestyle | +| EmptyMethodInAbstractClassShouldBeAbstract | Empty method in abstract class should be abstract | Blocker | Medium | | Active | | codestyle | +| FieldDeclarationsShouldBeAtStartOfClass | Field declarations should be at start of class | Medium | Low | | Active | | codestyle | +| FieldNamingConventions | Field naming conventions | Blocker | Medium | | Active | | codestyle | +| FinalParameterInAbstractMethod | Final parameter in abstract method | Blocker | Medium | | Active | | codestyle | +| ForLoopShouldBeWhileLoop | For loop should be while loop | Medium | Low | | Active | | codestyle | +| FormalParameterNamingConventions | Formal parameter naming conventions | Blocker | Medium | | Active | | codestyle | +| GenericsNaming | Generics naming | | | Active | Deprecated | | codestyle | +| IdenticalCatchBranches | Identical catch branches | Medium | Low | | Active | | codestyle | +| InvalidLogMessageFormat | Invalid log message format | Info | Low | | Active | | errorprone | +| LambdaCanBeMethodReference | Lambda can be method reference | Medium | Low | | Active | | codestyle | +| LinguisticNaming | Linguistic naming | Medium | Low | | Active | | codestyle | +| LocalVariableCouldBeFinal | Local variable could be final | Medium | Low | | Active | | codestyle | +| LocalVariableNamingConventions | Local variable naming conventions | Blocker | Medium | | Active | | codestyle | +| LongVariable | Long variable | Medium | Low | | Active | | codestyle | +| MethodArgumentCouldBeFinal | Method argument could be final | Medium | Low | | Active | | codestyle | +| MethodNamingConventions | Method naming conventions | Blocker | Medium | | Active | | codestyle | +| NoPackage | No package | Medium | Low | | Active | | codestyle | +| OnlyOneReturn | Only one return | Medium | Low | | Active | | codestyle | +| PackageCase | Package case | Medium | Low | | Active | | codestyle | +| PrematureDeclaration | Premature declaration | Medium | Low | | Active | | codestyle | +| ShortMethodName | Short method name | Medium | Low | | Active | | codestyle | +| ShortVariable | Short variable | Medium | Low | | Active | | codestyle | +| TooManyStaticImports | Too many static imports | Medium | Low | | Active | | codestyle | +| UnnecessaryAnnotationValueElement | Unnecessary annotation value element | Medium | Low | | Active | | codestyle | +| UnnecessaryBoxing | Unnecessary boxing | Medium | Low | | Active | | codestyle | +| UnnecessaryCast | Unnecessary cast | Medium | Low | | Active | | codestyle | +| UnnecessaryConstructor | Unnecessary constructor | Medium | Low | | Active | | codestyle | +| UnnecessaryLocalBeforeReturn | Unnecessary local before return | Medium | Low | Active | Deprecated | | codestyle | +| UnnecessaryModifier | Unnecessary modifier | Medium | Low | | Active | | codestyle | +| UnnecessaryReturn | Unnecessary return | Medium | Low | | Active | | codestyle | +| UnnecessarySemicolon | Unnecessary semicolon | Medium | Low | | Active | | codestyle | +| UseDiamondOperator | Use diamond operator | Medium | Low | | Active | | codestyle | +| UseExplicitTypes | Use explicit types | Medium | Low | | Active | | codestyle | +| UseShortArrayInitializer | Use short Array initializer | Medium | Low | | Active | | codestyle | +| UseUnderscoresInNumericLiterals | Use underscores in numeric literals | Medium | Low | | Active | | codestyle | +| UselessOperationOnImmutable | Useless operation on immutable | | | Active | Deprecated | | errorprone | +| UselessQualifiedThis | Useless qualified this | Medium | Low | | Active | | codestyle | + +## Unchanged Rules +The following rules exist in both versions with no changes: + +| Rule Key | Name | Severity | Status | Alternatives | Category | +|----------|------|----------|--------|--------------|----------| +| AbstractClassWithoutAbstractMethod | Abstract class without abstract method | Medium | Active | | bestpractices | +| AbstractClassWithoutAnyMethod | Abstract class without any method | Blocker | Active | | design | +| AccessorClassGeneration | Accessor class generation | Medium | Active | | bestpractices | +| AccessorMethodGeneration | Accessor method generation | Medium | Active | | bestpractices | +| AddEmptyString | Add empty string | Medium | Active | | performance | +| AppendCharacterWithChar | Append character with char | Medium | Active | | performance | +| ArrayIsStoredDirectly | Array is stored directly | Medium | Active | | bestpractices | +| AssignmentInOperand | Assignment in operand | Medium | Active | | errorprone | +| AssignmentToNonFinalStatic | Assignment to non final static | Medium | Active | | errorprone | +| AvoidAccessibilityAlteration | Avoid accessibility alteration | Medium | Active | | errorprone | +| AvoidArrayLoops | Avoid array loops | Medium | Active | | performance | +| AvoidAssertAsIdentifier | Avoid assert as identifier | High | Active | | errorprone | +| AvoidBranchingStatementAsLastInLoop | Avoid branching statement as last in loop | High | Active | | errorprone | +| AvoidCalendarDateCreation | Avoid calendar date creation | Medium | Active | | performance | +| AvoidCallingFinalize | Avoid calling finalize | Medium | Active | | errorprone | +| AvoidCatchingGenericException | Avoid catching generic exception | Medium | Active | | design | +| AvoidCatchingNPE | Avoid catching NPE | Medium | Active | | errorprone | +| AvoidCatchingThrowable | Avoid catching Throwable | Medium | Active | | errorprone | +| AvoidDecimalLiteralsInBigDecimalConstructor | Avoid decimal literals in BigDecimal constructor | Medium | Active | | errorprone | +| AvoidDeeplyNestedIfStmts | Avoid deeply nested if stmts | Medium | Active | | design | +| AvoidDuplicateLiterals | Avoid duplicate literals | Medium | Active | | errorprone | +| AvoidEnumAsIdentifier | Avoid enum as identifier | High | Active | | errorprone | +| AvoidFieldNameMatchingMethodName | Avoid field name matching method name | Medium | Active | | errorprone | +| AvoidFieldNameMatchingTypeName | Avoid field name matching type name | Medium | Active | | errorprone | +| AvoidFileStream | Avoid file stream | Blocker | Active | | performance | +| AvoidInstanceofChecksInCatchClause | Avoid instanceof checks in catch clause | Medium | Active | | errorprone | +| AvoidInstantiatingObjectsInLoops | Avoid instantiating objects in loops | Medium | Active | | performance | +| AvoidLiteralsInIfCondition | Avoid literals in if condition | Medium | Active | | errorprone | +| AvoidMessageDigestField | Avoid message digest field | Medium | Active | | bestpractices | +| AvoidMultipleUnaryOperators | Avoid multiple unary operators | High | Active | | errorprone | +| AvoidPrintStackTrace | Avoid print stack trace | Medium | Active | | bestpractices | +| AvoidReassigningCatchVariables | Avoid reassigning catch variables | Medium | Active | | bestpractices | +| AvoidReassigningLoopVariables | Avoid reassigning loop variables | Medium | Active | | bestpractices | +| AvoidReassigningParameters | Avoid reassigning parameters | High | Active | | bestpractices | +| AvoidRethrowingException | Avoid rethrowing exception | Medium | Active | | design | +| AvoidStringBufferField | Avoid StringBuffer field | Medium | Active | | bestpractices | +| AvoidSynchronizedAtMethodLevel | Avoid synchronized at method level | Medium | Active | | multithreading | +| AvoidSynchronizedStatement | Avoid synchronized statement | Medium | Active | | multithreading | +| AvoidThreadGroup | Avoid ThreadGroup | Medium | Active | | multithreading | +| AvoidThrowingNewInstanceOfSameException | Avoid throwing new instance of same exception | Medium | Active | | design | +| AvoidThrowingNullPointerException | Avoid throwing NullPointerException | Blocker | Active | | design | +| AvoidThrowingRawExceptionTypes | Avoid throwing raw exception types | Blocker | Active | | design | +| AvoidUncheckedExceptionsInSignatures | Avoid unchecked exceptions in signatures | Medium | Active | | design | +| AvoidUsingHardCodedIP | Avoid using hard coded IP | Medium | Active | | bestpractices | +| AvoidUsingOctalValues | Avoid using octal values | Medium | Active | | errorprone | +| AvoidUsingVolatile | Avoid using volatile | High | Active | | multithreading | +| BigIntegerInstantiation | BigInteger instantiation | Medium | Active | | performance | +| BooleanGetMethodName | Boolean get method name | Low | Active | | codestyle | +| BrokenNullCheck | Broken null check | High | Active | | errorprone | +| CallSuperFirst | Call super first | Medium | Active | | errorprone | +| CallSuperLast | Call super last | Medium | Active | | errorprone | +| CheckResultSet | Check result set | Medium | Active | | bestpractices | +| CheckSkipResult | Check skip result | Medium | Active | | errorprone | +| ClassCastExceptionWithToArray | ClassCastException with toArray | Medium | Active | | errorprone | +| ClassWithOnlyPrivateConstructorsShouldBeFinal | Class with only private constructors should be final | Blocker | Active | | design | +| CloneMethodMustBePublic | Clone method must be public | Medium | Active | | errorprone | +| CloneMethodMustImplementCloneable | Clone method must implement Cloneable | Medium | Active | | errorprone | +| CloneMethodReturnTypeMustMatchClassName | Clone method return type must match class name | Medium | Active | | errorprone | +| CloseResource | Close resource | Medium | Active | | errorprone | +| CognitiveComplexity | Cognitive complexity | Medium | Active | | design | +| CollapsibleIfStatements | Collapsible if statements | Medium | Active | | design | +| CommentContent | Comment content | Medium | Active | | documentation | +| CommentRequired | Comment required | Medium | Active | | documentation | +| CommentSize | Comment size | Medium | Active | | documentation | +| CompareObjectsWithEquals | Compare objects with equals | Medium | Active | | errorprone | +| ComparisonWithNaN | Comparison with NaN | Medium | Active | | errorprone | +| ConfusingArgumentToVarargsMethod | Confusing argument to varargs method | Medium | Active | | errorprone | +| ConsecutiveAppendsShouldReuse | Consecutive appends should reuse | Medium | Active | | performance | +| ConsecutiveLiteralAppends | Consecutive literal appends | Medium | Active | | performance | +| ConstantsInInterface | Constants in interface | Medium | Active | | bestpractices | +| ConstructorCallsOverridableMethod | Constructor calls overridable method | Blocker | Active | | errorprone | +| CouplingBetweenObjects | Coupling between objects | Medium | Active | | design | +| CyclomaticComplexity | Cyclomatic complexity | Medium | Active | | design | +| DataClass | Data class | Medium | Active | | design | +| DefaultLabelNotLastInSwitch | Default label not last in switch | Medium | Active | | bestpractices | +| DetachedTestCase | Detached test case | Medium | Active | | errorprone | +| DoNotCallGarbageCollectionExplicitly | Do not call garbage collection explicitly | High | Active | | errorprone | +| DoNotExtendJavaLangError | Do not extend java.lang.Error | Medium | Active | | design | +| DoNotExtendJavaLangThrowable | Do not extend java.lang.Throwable | Medium | Active | | errorprone | +| DoNotHardCodeSDCard | Do not hard code SDCard | Medium | Active | | errorprone | +| DoNotTerminateVM | Do not terminate VM | Medium | Active | | errorprone | +| DoNotThrowExceptionInFinally | Do not throw exception in finally | Low | Active | | errorprone | +| DoNotUseThreads | Do not use threads | Medium | Active | | multithreading | +| DontCallThreadRun | Dont call thread run | Low | Active | | multithreading | +| DontImportSun | Dont import sun | Low | Active | | errorprone | +| DontUseFloatTypeForLoopIndices | Dont use float type for loop indices | Medium | Active | | errorprone | +| DoubleBraceInitialization | Double brace initialization | Medium | Active | | bestpractices | +| DoubleCheckedLocking | Double checked locking | Blocker | Active | | multithreading | +| EmptyCatchBlock | Empty catch block | Medium | Active | | errorprone | +| EmptyFinalizer | Empty finalizer | Medium | Active | | errorprone | +| EqualsNull | Equals null | Blocker | Active | | errorprone | +| ExceptionAsFlowControl | Exception as flow control | Medium | Active | | design | +| ExcessiveImports | Excessive imports | Medium | Active | | design | +| ExcessiveParameterList | Excessive parameter List | Medium | Active | | design | +| ExcessivePublicCount | Excessive public count | Medium | Active | | design | +| ExhaustiveSwitchHasDefault | Exhaustive switch has default | Medium | Active | | bestpractices | +| ExtendsObject | Extends object | Low | Active | | codestyle | +| FinalFieldCouldBeStatic | Final field could be static | Medium | Active | | design | +| FinalizeDoesNotCallSuperFinalize | Finalize does not call super finalize | Medium | Active | | errorprone | +| FinalizeOnlyCallsSuperFinalize | Finalize only calls super finalize | Medium | Active | | errorprone | +| FinalizeOverloaded | Finalize overloaded | Medium | Active | | errorprone | +| FinalizeShouldBeProtected | Finalize should be protected | Medium | Active | | errorprone | +| ForLoopCanBeForeach | For loop can be foreach | Medium | Active | | bestpractices | +| ForLoopVariableCount | For loop variable count | Medium | Active | | bestpractices | +| GodClass | God class | Medium | Active | | design | +| GuardLogStatement | Guard log statement | High | Active | | bestpractices | +| HardCodedCryptoKey | Hard coded crypto key | Medium | Active | | security | +| IdempotentOperations | Idempotent operations | Medium | Active | | errorprone | +| ImmutableField | Immutable field | Medium | Active | | design | +| ImplicitFunctionalInterface | Implicit functional interface | High | Active | | bestpractices | +| ImplicitSwitchFallThrough | Implicit switch fall through | Medium | Active | | errorprone | +| InefficientEmptyStringCheck | Inefficient empty string check | Medium | Active | | performance | +| InefficientStringBuffering | Inefficient string buffering | Medium | Active | | performance | +| InsecureCryptoIv | Insecure crypto IV | Medium | Active | | security | +| InstantiationToGetClass | Instantiation to get class | Low | Active | | errorprone | +| InsufficientStringBufferDeclaration | Insufficient StringBuffer declaration | Medium | Active | | performance | +| InvalidJavaBean | Invalid Java bean | Medium | Active | | design | +| JUnit4SuitesShouldUseSuiteAnnotation | JUnit4 suites should use suite annotation | Medium | Active | | bestpractices | +| JUnit5TestShouldBePackagePrivate | JUnit5 test should be package private | Medium | Active | | bestpractices | +| JUnitSpelling | JUnit spelling | Medium | Active | | errorprone | +| JUnitStaticSuite | JUnit static suite | Medium | Active | | errorprone | +| JUnitUseExpected | JUnit use expected | Medium | Active | | bestpractices | +| JumbledIncrementer | Jumbled incrementer | Medium | Active | | errorprone | +| LawOfDemeter | Law of demeter | Medium | Active | | design | +| LiteralsFirstInComparisons | Literals first in comparisons | Medium | Active | | bestpractices | +| LocalHomeNamingConvention | Local home naming convention | Low | Active | | codestyle | +| LocalInterfaceSessionNamingConvention | Local interface session naming convention | Low | Active | | codestyle | +| LogicInversion | Logic inversion | Medium | Active | | design | +| LooseCoupling | Loose coupling | Medium | Active | | bestpractices | +| LoosePackageCoupling | Loose package coupling | Medium | Active | | design | +| MDBAndSessionBeanNamingConvention | MDB and session bean naming convention | Low | Active | | codestyle | +| MethodReturnsInternalArray | Method returns internal array | Medium | Active | | bestpractices | +| MethodWithSameNameAsEnclosingClass | Method with same name as enclosing class | Medium | Active | | errorprone | +| MisplacedNullCheck | Misplaced null check | Medium | Active | | errorprone | +| MissingOverride | Missing override | Medium | Active | | bestpractices | +| MissingSerialVersionUID | Missing serialVersionUID | Medium | Active | | errorprone | +| MissingStaticMethodInNonInstantiatableClass | Missing static method in non instantiatable class | Medium | Active | | errorprone | +| MoreThanOneLogger | More than one logger | High | Active | | errorprone | +| MutableStaticState | Mutable static state | Medium | Active | | design | +| NPathComplexity | NPath complexity | Medium | Active | | design | +| NcssCount | NCSS count | Medium | Active | | design | +| NonCaseLabelInSwitch | Non case label in switch | Medium | Active | | errorprone | +| NonExhaustiveSwitch | Non exhaustive switch | Medium | Active | | bestpractices | +| NonSerializableClass | Non serializable class | Medium | Active | | errorprone | +| NonStaticInitializer | Non static initializer | Medium | Active | | errorprone | +| NonThreadSafeSingleton | Non thread safe singleton | Medium | Active | | multithreading | +| NullAssignment | Null assignment | Medium | Active | | errorprone | +| OneDeclarationPerLine | One declaration per line | Low | Active | | bestpractices | +| OptimizableToArrayCall | Optimizable toArray call | Medium | Active | | performance | +| OverrideBothEqualsAndHashcode | Override both equals and hashcode | Medium | Active | | errorprone | +| PreserveStackTrace | Preserve stack trace | Medium | Active | | bestpractices | +| PrimitiveWrapperInstantiation | Primitive wrapper instantiation | Medium | Active | | bestpractices | +| ProperCloneImplementation | Proper clone implementation | High | Active | | errorprone | +| ProperLogger | Proper logger | Medium | Active | | errorprone | +| RedundantFieldInitializer | Redundant field initializer | Medium | Active | | performance | +| RemoteInterfaceNamingConvention | Remote interface naming convention | Low | Active | | codestyle | +| RemoteSessionInterfaceNamingConvention | Remote session interface naming convention | Low | Active | | codestyle | +| ReplaceEnumerationWithIterator | Replace Enumeration with Iterator | Medium | Active | | bestpractices | +| ReplaceHashtableWithMap | Replace Hashtable with Map | Medium | Active | | bestpractices | +| ReplaceVectorWithList | Replace Vector with List | Medium | Active | | bestpractices | +| ReturnEmptyCollectionRatherThanNull | Return empty collection rather than null | Blocker | Active | | errorprone | +| ReturnFromFinallyBlock | Return from finally block | Medium | Active | | errorprone | +| ShortClassName | Short class name | Low | Active | | codestyle | +| SignatureDeclareThrowsException | Signature declare throws Exception | Medium | Active | | design | +| SimpleDateFormatNeedsLocale | SimpleDateFormat needs Locale | Medium | Active | | errorprone | +| SimplifiableTestAssertion | Simplifiable test assertion | Medium | Active | | bestpractices | +| SimplifiedTernary | Simplified ternary | Medium | Active | | design | +| SimplifyBooleanExpressions | Simplify boolean expressions | Medium | Active | | design | +| SimplifyBooleanReturns | Simplify boolean returns | Medium | Active | | design | +| SimplifyConditional | Simplify conditional | Medium | Active | | design | +| SingleMethodSingleton | Single method singleton | High | Active | | errorprone | +| SingletonClassReturningNewInstance | Singleton class returning new instance | High | Active | | errorprone | +| SingularField | Singular field | Medium | Active | | design | +| StaticEJBFieldShouldBeFinal | Static EJBField should be final | Medium | Active | | errorprone | +| StringBufferInstantiationWithChar | StringBuffer instantiation with char | Low | Active | | errorprone | +| StringInstantiation | String instantiation | High | Active | | performance | +| StringToString | String to string | Medium | Active | | performance | +| SuspiciousEqualsMethodName | Suspicious equals method name | High | Active | | errorprone | +| SuspiciousHashcodeMethodName | Suspicious hashcode method name | Medium | Active | | errorprone | +| SuspiciousOctalEscape | Suspicious octal escape | Medium | Active | | errorprone | +| SwitchDensity | Switch density | Medium | Active | | design | +| SystemPrintln | System println | High | Active | | bestpractices | +| TestClassWithoutTestCases | Test class without test cases | Medium | Active | | errorprone | +| TooFewBranchesForSwitch | Too few branches for switch | Medium | Active | | performance | +| TooManyFields | Too many fields | Medium | Active | | design | +| TooManyMethods | Too many methods | Medium | Active | | design | +| UncommentedEmptyConstructor | Uncommented empty constructor | Medium | Active | | documentation | +| UncommentedEmptyMethodBody | Uncommented empty method body | Medium | Active | | documentation | +| UnconditionalIfStatement | Unconditional if statement | Medium | Active | | errorprone | +| UnitTestAssertionsShouldIncludeMessage | Unit test assertions should include message | Medium | Active | | bestpractices | +| UnitTestContainsTooManyAsserts | Unit test contains too many asserts | Medium | Active | | bestpractices | +| UnitTestShouldIncludeAssert | Unit test should include assert | Medium | Active | | bestpractices | +| UnitTestShouldUseAfterAnnotation | Unit test should use after annotation | Medium | Active | | bestpractices | +| UnitTestShouldUseBeforeAnnotation | Unit test should use before annotation | Medium | Active | | bestpractices | +| UnitTestShouldUseTestAnnotation | Unit test should use test annotation | Medium | Active | | bestpractices | +| UnnecessaryBooleanAssertion | Unnecessary boolean assertion | Medium | Active | | errorprone | +| UnnecessaryCaseChange | Unnecessary case change | Medium | Active | | errorprone | +| UnnecessaryConversionTemporary | Unnecessary conversion temporary | Medium | Active | | errorprone | +| UnnecessaryFullyQualifiedName | Unnecessary fully qualified name | Low | Active | | codestyle | +| UnnecessaryImport | Unnecessary import | Low | Active | | codestyle | +| UnnecessaryVarargsArrayCreation | Unnecessary varargs array creation | Medium | Active | | bestpractices | +| UnnecessaryWarningSuppression | Unnecessary warning suppression | Medium | Active | | bestpractices | +| UnsynchronizedStaticFormatter | Unsynchronized static formatter | Medium | Active | | multithreading | +| UnusedAssignment | Unused assignment | Medium | Active | | bestpractices | +| UnusedFormalParameter | Unused formal parameter | Medium | Active | | bestpractices | +| UnusedLocalVariable | Unused local variable | Medium | Active | | bestpractices | +| UnusedNullCheckInEquals | Unused null check in equals | Medium | Active | | errorprone | +| UnusedPrivateField | Unused private field | Medium | Active | | bestpractices | +| UnusedPrivateMethod | Unused private method | Medium | Active | | bestpractices | +| UseArrayListInsteadOfVector | Use Arrays.asList | Medium | Active | | performance | +| UseArraysAsList | Use arrays as List | Medium | Active | | performance | +| UseCollectionIsEmpty | Use Collection.isEmpty | Medium | Active | | bestpractices | +| UseConcurrentHashMap | Use ConcurrentHashMap | Medium | Active | | multithreading | +| UseCorrectExceptionLogging | Use correct exception logging | Medium | Active | | errorprone | +| UseEnumCollections | Use enum collections | Medium | Active | | bestpractices | +| UseEqualsToCompareStrings | Use equals to compare strings | Medium | Active | | errorprone | +| UseIOStreamsWithApacheCommonsFileItem | Use IOStreams with apache commons FileItem | Medium | Active | | performance | +| UseIndexOfChar | Use index of char | Medium | Active | | performance | +| UseLocaleWithCaseConversions | Use Locale with case conversions | Medium | Active | | errorprone | +| UseNotifyAllInsteadOfNotify | Use notifyAll instead of notify | Medium | Active | | multithreading | +| UseObjectForClearerAPI | Use object for clearer API | Medium | Active | | design | +| UseProperClassLoader | Use proper ClassLoader | Medium | Active | | errorprone | +| UseStandardCharsets | Use standard Charsets | Medium | Active | | bestpractices | +| UseStringBufferForStringAppends | Use StringBuffer for string appends | Medium | Active | | performance | +| UseStringBufferLength | Use StringBuffer length | Medium | Active | | performance | +| UseTryWithResources | Use try with resources | Medium | Active | | bestpractices | +| UseUtilityClass | Use utility class | Medium | Active | | design | +| UseVarargs | Use varargs | Low | Active | | bestpractices | +| UselessOverridingMethod | Useless overriding method | Medium | Active | | design | +| UselessParentheses | Useless parentheses | Low | Active | | codestyle | +| UselessStringValueOf | Useless String.valueOf | Medium | Active | | performance | +| WhileLoopWithLiteralBoolean | While loop with literal boolean | Medium | Active | | bestpractices | +| XPathRule | PMD XPath Template Rule | | Active | | | + +## Renamed Rules +The following rules have new names: + +| Rule name | New rule name | Category | +|-----------|---------------|----------| +| DefaultLabelNotLastInSwitchStmt | DefaultLabelNotLastInSwitch | bestpractices | +| JUnit4TestShouldUseAfterAnnotation | UnitTestShouldUseAfterAnnotation | bestpractices | +| JUnit4TestShouldUseBeforeAnnotation | UnitTestShouldUseBeforeAnnotation | bestpractices | +| JUnit4TestShouldUseTestAnnotation | UnitTestShouldUseTestAnnotation | bestpractices | +| JUnitAssertionsShouldIncludeMessage | UnitTestAssertionsShouldIncludeMessage | bestpractices | +| JUnitTestContainsTooManyAsserts | UnitTestContainsTooManyAsserts | bestpractices | +| JUnitTestsShouldIncludeAssert | UnitTestShouldIncludeAssert | bestpractices | +| NonCaseLabelInSwitchStatement | NonCaseLabelInSwitch | errorprone | +| SwitchStmtsShouldHaveDefault | NonExhaustiveSwitch | bestpractices | +| TooFewBranchesForASwitchStatement | TooFewBranchesForSwitch | performance | + +## Removed Rules +No rules were removed. + +Report generated on Mon Sep 29 11:44:31 CEST 2025 diff --git a/docs/rules/AbstractClassWithoutAbstractMethod.md b/docs/rules/AbstractClassWithoutAbstractMethod.md deleted file mode 100644 index 0feda2db..00000000 --- a/docs/rules/AbstractClassWithoutAbstractMethod.md +++ /dev/null @@ -1,9 +0,0 @@ -# AbstractClassWithoutAbstractMethod -**Category:** `pmd`
-**Rule Key:** `pmd:AbstractClassWithoutAbstractMethod`
-> :warning: This rule is **deprecated** in favour of [S1694](https://rules.sonarsource.com/java/RSPEC-1694). - ------ - - -The abstract class does not contain any abstract methods. An abstract class suggests an incomplete implementation, which is to be completed by subclasses implementing the abstract methods. If the class is intended to be used as a base class only (not to be instantiated directly) a protected constructor can be provided prevent direct instantiation. diff --git a/docs/rules/AbstractClassWithoutAnyMethod.md b/docs/rules/AbstractClassWithoutAnyMethod.md deleted file mode 100644 index feb03186..00000000 --- a/docs/rules/AbstractClassWithoutAnyMethod.md +++ /dev/null @@ -1,16 +0,0 @@ -# AbstractClassWithoutAnyMethod -**Category:** `pmd`
-**Rule Key:** `pmd:AbstractClassWithoutAnyMethod`
-> :warning: This rule is **deprecated** in favour of [S1694](https://rules.sonarsource.com/java/RSPEC-1694). - ------ - - -If an abstract class does not provide any method, it may be acting as a simple data container that is not meant to be instantiated. In this case, it is probably better to use a private or protected constructor in order to prevent instantiation than make the class misleadingly abstract. -

Example:

-
-public class abstract Example {
-  String field;
-  int otherField;
-}
-
diff --git a/docs/rules/AbstractNaming.md b/docs/rules/AbstractNaming.md deleted file mode 100644 index 30aed19d..00000000 --- a/docs/rules/AbstractNaming.md +++ /dev/null @@ -1,14 +0,0 @@ -# AbstractNaming -**Category:** `pmd`
-**Rule Key:** `pmd:AbstractNaming`
-> :warning: This rule is **deprecated** in favour of [S00118](https://rules.sonarsource.com/java/RSPEC-118). - ------ - - -Abstract classes should be named 'AbstractXXX'. -

Example:

h2> -
-public abstract class Foo { // should be AbstractFoo
-}
-  
diff --git a/docs/rules/AccessorClassGeneration.md b/docs/rules/AccessorClassGeneration.md deleted file mode 100644 index 9a9d7568..00000000 --- a/docs/rules/AccessorClassGeneration.md +++ /dev/null @@ -1,25 +0,0 @@ -# AccessorClassGeneration -**Category:** `pmd`
-**Rule Key:** `pmd:AccessorClassGeneration`
- - ------ - - -Instantiation by way of private constructors from outside of the constructor’s class often causes the generation of an accessor. -A factory method, or non-privatization of the constructor can eliminate this situation. -The generated class file is actually an interface. It gives the accessing class the ability to invoke a new hidden package scope constructor that takes the interface as a supplementary parameter. -This turns a private constructor effectively into one with package scope, and is challenging to discern. - -

Example:

-
-public class Outer {
-  void method() {
-    Inner ic = new Inner(); // Causes generation of accessor class
-  }
-
-  public class Inner {
-    private Inner() {}
-  }
-}
-
diff --git a/docs/rules/AddEmptyString.md b/docs/rules/AddEmptyString.md deleted file mode 100644 index 189c61d5..00000000 --- a/docs/rules/AddEmptyString.md +++ /dev/null @@ -1,16 +0,0 @@ -# AddEmptyString -**Category:** `pmd`
-**Rule Key:** `pmd:AddEmptyString`
- - ------ - - -The conversion of literals to strings by concatenating them with empty strings is inefficient. -It is much better to use one of the type-specific toString() methods instead. - -

Example:

-
-String s = "" + 123;                // inefficient
-String t = Integer.toString(456);   // preferred approach
-
diff --git a/docs/rules/AppendCharacterWithChar.md b/docs/rules/AppendCharacterWithChar.md deleted file mode 100644 index a10c3d35..00000000 --- a/docs/rules/AppendCharacterWithChar.md +++ /dev/null @@ -1,20 +0,0 @@ -# AppendCharacterWithChar -**Category:** `pmd`
-**Rule Key:** `pmd:AppendCharacterWithChar`
- - ------ - - -Avoid concatenating characters as strings in StringBuffer/StringBuilder.append methods. - -

Noncompliant Code Example

-
-StringBuffer sb = new StringBuffer();
-sb.append("a");     // avoid this
-
-

Compliant Solution

-
-StringBuffer sb = new StringBuffer();
-sb.append('a');     // use this instead
-
diff --git a/docs/rules/ArrayIsStoredDirectly.md b/docs/rules/ArrayIsStoredDirectly.md deleted file mode 100644 index b2934303..00000000 --- a/docs/rules/ArrayIsStoredDirectly.md +++ /dev/null @@ -1,9 +0,0 @@ -# ArrayIsStoredDirectly -**Category:** `pmd`
-**Rule Key:** `pmd:ArrayIsStoredDirectly`
-> :warning: This rule is **deprecated** in favour of [S2384](https://rules.sonarsource.com/java/RSPEC-2384). - ------ - - -Constructors and methods receiving arrays should clone objects and store the copy. This prevents future changes from the user from affecting the original array. diff --git a/docs/rules/AssignmentInOperand.md b/docs/rules/AssignmentInOperand.md deleted file mode 100644 index baad8c4f..00000000 --- a/docs/rules/AssignmentInOperand.md +++ /dev/null @@ -1,19 +0,0 @@ -# AssignmentInOperand -**Category:** `pmd`
-**Rule Key:** `pmd:AssignmentInOperand`
-> :warning: This rule is **deprecated** in favour of `squid:AssignmentInSubExpressionCheck`. - ------ - - -Avoid assignments in operands; this can make code more complicated and harder to read. - -

Example:

-
-public void bar() {
-  int x = 2;
-  if ((x = getX()) == 3) {
-    System.out.println("3!");
-  }
-}
-
diff --git a/docs/rules/AssignmentToNonFinalStatic.md b/docs/rules/AssignmentToNonFinalStatic.md deleted file mode 100644 index 7cb9f286..00000000 --- a/docs/rules/AssignmentToNonFinalStatic.md +++ /dev/null @@ -1,19 +0,0 @@ -# AssignmentToNonFinalStatic -**Category:** `pmd`
-**Rule Key:** `pmd:AssignmentToNonFinalStatic`
- - ------ - - -Identifies a possible unsafe usage of a static field. - -

Example:

-
-public class StaticField {
- static int x;
- public FinalFields(int y) {
-  x = y; // unsafe
- }
-}
-
diff --git a/docs/rules/AtLeastOneConstructor.md b/docs/rules/AtLeastOneConstructor.md deleted file mode 100644 index b6b0e181..00000000 --- a/docs/rules/AtLeastOneConstructor.md +++ /dev/null @@ -1,8 +0,0 @@ -# AtLeastOneConstructor -**Category:** `pmd`
-**Rule Key:** `pmd:AtLeastOneConstructor`
-> :warning: This rule is **deprecated** in favour of [S1118](https://rules.sonarsource.com/java/RSPEC-1118), [S1258](https://rules.sonarsource.com/java/RSPEC-1258). - ------ - -Each non-static class should declare at least one constructor. Classes with solely static members ("Utility class") are ignored. diff --git a/docs/rules/AvoidAccessibilityAlteration.md b/docs/rules/AvoidAccessibilityAlteration.md deleted file mode 100644 index 3b572dec..00000000 --- a/docs/rules/AvoidAccessibilityAlteration.md +++ /dev/null @@ -1,42 +0,0 @@ -# AvoidAccessibilityAlteration -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidAccessibilityAlteration`
- - ------ - - -Methods such as getDeclaredConstructors(), getDeclaredConstructor(Class[]) and setAccessible(), as the interface PrivilegedAction, allow for the runtime alteration of variable, class, or method visibility, even if they are private. This violates the principle of encapsulation. - -

Example:

-
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.Method;
-import java.security.PrivilegedAction;
-
-public class Violation {
-  public void invalidCallsInMethod() throws SecurityException, NoSuchMethodException {
-
-    // Possible call to forbidden getDeclaredConstructors
-    Class[] arrayOfClass = new Class[1];
-    this.getClass().getDeclaredConstructors();
-    this.getClass().getDeclaredConstructor(arrayOfClass);
-    Class clazz = this.getClass();
-    clazz.getDeclaredConstructor(arrayOfClass);
-    clazz.getDeclaredConstructors();
-
-    // Possible call to forbidden setAccessible
-    clazz.getMethod("", arrayOfClass).setAccessible(false);
-    AccessibleObject.setAccessible(null, false);
-    Method.setAccessible(null, false);
-    Method[] methodsArray = clazz.getMethods();
-    int nbMethod;
-    for (nbMethod = 0; nbMethod < methodsArray.length; nbMethod++ ) {
-      methodsArray[nbMethod].setAccessible(false);
-    }
-
-    // Possible call to forbidden PrivilegedAction
-    PrivilegedAction priv = (PrivilegedAction) new Object(); priv.run();
-  }
-}
-
diff --git a/docs/rules/AvoidArrayLoops.md b/docs/rules/AvoidArrayLoops.md deleted file mode 100644 index 948d5f53..00000000 --- a/docs/rules/AvoidArrayLoops.md +++ /dev/null @@ -1,31 +0,0 @@ -# AvoidArrayLoops -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidArrayLoops`
- - ------ - - -Instead of manually copying data between two arrays, use the efficient Arrays.copyOf or System.arraycopy method instead. - -

Noncompliant Code Example

-
-int[] a = new int[10];
-int[] b = new int[10];
-
-for (int i = 0; i < 10; i++) {
-  b[i] = a[i];
-}
-
- -

Compliant Solution

-
-int[] a = new int[10];
-int[] b;
-
-// Option 1
-b = Arrays.copyOf(a, a.length);
-
-// Option 2
-System.arraycopy(a, 0, b, 0, a.length);
-
diff --git a/docs/rules/AvoidAssertAsIdentifier.md b/docs/rules/AvoidAssertAsIdentifier.md deleted file mode 100644 index b0211a50..00000000 --- a/docs/rules/AvoidAssertAsIdentifier.md +++ /dev/null @@ -1,9 +0,0 @@ -# AvoidAssertAsIdentifier -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidAssertAsIdentifier`
-> :warning: This rule is **deprecated** in favour of [S1190](https://rules.sonarsource.com/java/RSPEC-1190). - ------ - - -Use of the term assert will conflict with newer versions of Java since it is a reserved word. diff --git a/docs/rules/AvoidBranchingStatementAsLastInLoop.md b/docs/rules/AvoidBranchingStatementAsLastInLoop.md deleted file mode 100644 index b5a15790..00000000 --- a/docs/rules/AvoidBranchingStatementAsLastInLoop.md +++ /dev/null @@ -1,30 +0,0 @@ -# AvoidBranchingStatementAsLastInLoop -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidBranchingStatementAsLastInLoop`
- - ------ - - -Using a branching statement as the last part of a loop may be a bug, and/or is confusing. Ensure that the usage is not a bug, or consider using another approach. - -

Noncompliant Code Example

-
-// unusual use of branching statement in a loop
-for (int i = 0; i < 10; i++) {
-  if (i*i <= 25) {
-    continue;
-  }
-  break;
-}
-
- -

Compliant Solution

-
-// this makes more sense...
-for (int i = 0; i < 10; i++) {
-  if (i*i > 25) {
-    break;
-  }
-}
-
diff --git a/docs/rules/AvoidCallingFinalize.md b/docs/rules/AvoidCallingFinalize.md deleted file mode 100644 index 37db4274..00000000 --- a/docs/rules/AvoidCallingFinalize.md +++ /dev/null @@ -1,15 +0,0 @@ -# AvoidCallingFinalize -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidCallingFinalize`
-> :warning: This rule is **deprecated** in favour of `squid:ObjectFinalizeCheck`. - ------ - - -

- The method Object.finalize() is called by the garbage collector on an object when garbage collection determines that there are no more references to the object. - It should not be invoked by application logic. -

-

- Note that Oracle has declared Object.finalize() as deprecated since JDK 9. -

diff --git a/docs/rules/AvoidCatchingGenericException.md b/docs/rules/AvoidCatchingGenericException.md deleted file mode 100644 index 19ab9f4a..00000000 --- a/docs/rules/AvoidCatchingGenericException.md +++ /dev/null @@ -1,9 +0,0 @@ -# AvoidCatchingGenericException -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidCatchingGenericException`
-> :warning: This rule is **deprecated** in favour of [S2221](https://rules.sonarsource.com/java/RSPEC-2221). - ------ - - -Avoid catching generic exceptions such as NullPointerException, RuntimeException, Exception in try-catch block. diff --git a/docs/rules/AvoidCatchingNPE.md b/docs/rules/AvoidCatchingNPE.md deleted file mode 100644 index acd8f61c..00000000 --- a/docs/rules/AvoidCatchingNPE.md +++ /dev/null @@ -1,10 +0,0 @@ -# AvoidCatchingNPE -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidCatchingNPE`
-> :warning: This rule is **deprecated** in favour of [S1696](https://rules.sonarsource.com/java/RSPEC-1696). - ------ - - -Code should never throw NullPointerExceptions under normal circumstances. -A catch block may hide the original error, causing other, more subtle problems later on. diff --git a/docs/rules/AvoidCatchingThrowable.md b/docs/rules/AvoidCatchingThrowable.md deleted file mode 100644 index 47dabc4f..00000000 --- a/docs/rules/AvoidCatchingThrowable.md +++ /dev/null @@ -1,10 +0,0 @@ -# AvoidCatchingThrowable -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidCatchingThrowable`
-> :warning: This rule is **deprecated** in favour of [S1181](https://rules.sonarsource.com/java/RSPEC-1181). - ------ - - -Catching Throwable errors is not recommended since its scope is very broad. It includes runtime issues such as -OutOfMemoryError that should be exposed and managed separately. diff --git a/docs/rules/AvoidConstantsInterface.md b/docs/rules/AvoidConstantsInterface.md deleted file mode 100644 index 5739fc77..00000000 --- a/docs/rules/AvoidConstantsInterface.md +++ /dev/null @@ -1,15 +0,0 @@ -# AvoidConstantsInterface -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidConstantsInterface`
-> :warning: This rule is **deprecated** in favour of [S1214](https://rules.sonarsource.com/java/RSPEC-1214). - ------ - - -

- Avoid constants in interfaces. Interfaces should define types, constants are implementation details better placed in - classes or enums. -

-

- See Effective Java, item 19. -

diff --git a/docs/rules/AvoidDecimalLiteralsInBigDecimalConstructor.md b/docs/rules/AvoidDecimalLiteralsInBigDecimalConstructor.md deleted file mode 100644 index 022a48ae..00000000 --- a/docs/rules/AvoidDecimalLiteralsInBigDecimalConstructor.md +++ /dev/null @@ -1,29 +0,0 @@ -# AvoidDecimalLiteralsInBigDecimalConstructor -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidDecimalLiteralsInBigDecimalConstructor`
-> :warning: This rule is **deprecated** in favour of [S2111](https://rules.sonarsource.com/java/RSPEC-2111). - ------ - - -

- One might assume that the result of new BigDecimal(0.1) is exactly equal to 0.1, but it is - actually equal to .1000000000000000055511151231257827021181583404541015625. This is because 0.1 - cannot be represented exactly as a double (or as a binary fraction of any finite length). - Thus, the long value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding. -

-

- The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal("0.1") is exactly equal - to 0.1, as one would expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one. -

-

Noncompliant Code Example

-
-BigDecimal bd = new BigDecimal(1.123);       // loss of precision, this would trigger the rule
-
- -

Compliant Solution

-
-BigDecimal bd = new BigDecimal("1.123");     // preferred approach
-
-BigDecimal bd = new BigDecimal(12);          // preferred approach, ok for integer values
-
diff --git a/docs/rules/AvoidDeeplyNestedIfStmts.md b/docs/rules/AvoidDeeplyNestedIfStmts.md deleted file mode 100644 index 928d00d8..00000000 --- a/docs/rules/AvoidDeeplyNestedIfStmts.md +++ /dev/null @@ -1,9 +0,0 @@ -# AvoidDeeplyNestedIfStmts -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidDeeplyNestedIfStmts`
-> :warning: This rule is **deprecated** in favour of [S134](https://rules.sonarsource.com/java/RSPEC-134). - ------ - - -Avoid creating deeply nested if-then statements since they are harder to read and error-prone to maintain. diff --git a/docs/rules/AvoidDollarSigns.md b/docs/rules/AvoidDollarSigns.md deleted file mode 100644 index 268f0250..00000000 --- a/docs/rules/AvoidDollarSigns.md +++ /dev/null @@ -1,15 +0,0 @@ -# AvoidDollarSigns -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidDollarSigns`
-> :warning: This rule is **deprecated** in favour of [S00114](https://rules.sonarsource.com/java/RSPEC-114), [S00115](https://rules.sonarsource.com/java/RSPEC-115), [S00116](https://rules.sonarsource.com/java/RSPEC-116), [S00117](https://rules.sonarsource.com/java/RSPEC-117). - ------ - -

- Avoid using dollar signs in variable/method/class/interface names. -

- -

- This rule is deprecated, use {rule:squid:S00114}, {rule:squid:S00115}, {rule:squid:S00116} and {rule:squid:S00117} - instead. -

diff --git a/docs/rules/AvoidDuplicateLiterals.md b/docs/rules/AvoidDuplicateLiterals.md deleted file mode 100644 index 112ab266..00000000 --- a/docs/rules/AvoidDuplicateLiterals.md +++ /dev/null @@ -1,19 +0,0 @@ -# AvoidDuplicateLiterals -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidDuplicateLiterals`
-> :warning: This rule is **deprecated** in favour of [S1192](https://rules.sonarsource.com/java/RSPEC-1192). - ------ - -Code containing duplicate String literals can usually be improved by declaring the String as a constant field. Example : -
-public class Foo {
- private void bar() {
-    buz("Howdy");
-    buz("Howdy");
-    buz("Howdy");
-    buz("Howdy");
- }
- private void buz(String x) {}
-}
-
diff --git a/docs/rules/AvoidEnumAsIdentifier.md b/docs/rules/AvoidEnumAsIdentifier.md deleted file mode 100644 index 7d42b824..00000000 --- a/docs/rules/AvoidEnumAsIdentifier.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidEnumAsIdentifier -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidEnumAsIdentifier`
-> :warning: This rule is **deprecated** in favour of [S1190](https://rules.sonarsource.com/java/RSPEC-1190). - ------ - -Finds all places 'enum' is used as an identifier is used. diff --git a/docs/rules/AvoidFieldNameMatchingMethodName.md b/docs/rules/AvoidFieldNameMatchingMethodName.md deleted file mode 100644 index 1fdcc8b8..00000000 --- a/docs/rules/AvoidFieldNameMatchingMethodName.md +++ /dev/null @@ -1,16 +0,0 @@ -# AvoidFieldNameMatchingMethodName -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidFieldNameMatchingMethodName`
-> :warning: This rule is **deprecated** in favour of [S1845](https://rules.sonarsource.com/java/RSPEC-1845). - ------ - -It is somewhat confusing to have a field name with the same name as a method. While this is totally legal, having information (field) and actions (method) is not clear naming. Example : -
-public class Foo {
-  Object bar;
-  // bar is data or an action or both?
-  void bar() {
-  }
-}
-
diff --git a/docs/rules/AvoidFieldNameMatchingTypeName.md b/docs/rules/AvoidFieldNameMatchingTypeName.md deleted file mode 100644 index 1d654751..00000000 --- a/docs/rules/AvoidFieldNameMatchingTypeName.md +++ /dev/null @@ -1,14 +0,0 @@ -# AvoidFieldNameMatchingTypeName -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidFieldNameMatchingTypeName`
-> :warning: This rule is **deprecated** in favour of [S1700](https://rules.sonarsource.com/java/RSPEC-1700). - ------ - -It is somewhat confusing to have a field name matching the declaring class name. This probably means that type and or field names could be more precise. Example : -
-public class Foo extends Bar {
-  // There's probably a better name for foo
-  int foo;
-}
-
diff --git a/docs/rules/AvoidFinalLocalVariable.md b/docs/rules/AvoidFinalLocalVariable.md deleted file mode 100644 index 4b19f892..00000000 --- a/docs/rules/AvoidFinalLocalVariable.md +++ /dev/null @@ -1,15 +0,0 @@ -# AvoidFinalLocalVariable -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidFinalLocalVariable`
- - ------ - -Avoid using final local variables, turn them into fields. Example : -
-public class MyClass {
-    public void foo() {
-        final String finalLocalVariable;
-    }
-}
-  
diff --git a/docs/rules/AvoidInstanceofChecksInCatchClause.md b/docs/rules/AvoidInstanceofChecksInCatchClause.md deleted file mode 100644 index 989f9a33..00000000 --- a/docs/rules/AvoidInstanceofChecksInCatchClause.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidInstanceofChecksInCatchClause -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidInstanceofChecksInCatchClause`
-> :warning: This rule is **deprecated** in favour of [S1193](https://rules.sonarsource.com/java/RSPEC-1193). - ------ - -Each caught exception type should be handled in its own catch clause. diff --git a/docs/rules/AvoidInstantiatingObjectsInLoops.md b/docs/rules/AvoidInstantiatingObjectsInLoops.md deleted file mode 100644 index 78c666a7..00000000 --- a/docs/rules/AvoidInstantiatingObjectsInLoops.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidInstantiatingObjectsInLoops -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidInstantiatingObjectsInLoops`
- - ------ - -Detects when a new object is created inside a loop diff --git a/docs/rules/AvoidLiteralsInIfCondition.md b/docs/rules/AvoidLiteralsInIfCondition.md deleted file mode 100644 index cfca6964..00000000 --- a/docs/rules/AvoidLiteralsInIfCondition.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidLiteralsInIfCondition -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidLiteralsInIfCondition`
-> :warning: This rule is **deprecated** in favour of [S109](https://rules.sonarsource.com/java/RSPEC-109). - ------ - -Avoid using hard coded literals in conditional statements, declare those as static variables or private members. diff --git a/docs/rules/AvoidLosingExceptionInformation.md b/docs/rules/AvoidLosingExceptionInformation.md deleted file mode 100644 index f1e01d9b..00000000 --- a/docs/rules/AvoidLosingExceptionInformation.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidLosingExceptionInformation -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidLosingExceptionInformation`
-> :warning: This rule is **deprecated** in favour of [S1166](https://rules.sonarsource.com/java/RSPEC-1166). - ------ - -Statements in a catch block that invoke accessors on the exception without using the information only add to code size. Either remove the invocation, or use the return result. diff --git a/docs/rules/AvoidMultipleUnaryOperators.md b/docs/rules/AvoidMultipleUnaryOperators.md deleted file mode 100644 index 7529a30b..00000000 --- a/docs/rules/AvoidMultipleUnaryOperators.md +++ /dev/null @@ -1,27 +0,0 @@ -# AvoidMultipleUnaryOperators -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidMultipleUnaryOperators`
-> :warning: This rule is **deprecated** in favour of [S881](https://rules.sonarsource.com/java/RSPEC-881). - ------ - -Using multiple unary operators may be a bug, and/or is confusing. Check the usage is not a bug, or consider simplifying the expression. Example : -
-// These are typo bugs, or at best needlessly complex and confusing:
-int i = - -1;
-int j = + - +1;
-int z = ~~2;
-boolean b = !!true;
-boolean c = !!!true;
-
-// These are better:
-int i = 1;
-int j = -1;
-int z = 2;
-boolean b = true;
-boolean c = false;
-
-// And these just make your brain hurt:
-int i = ~-2;
-int j = -~7;
-
diff --git a/docs/rules/AvoidPrefixingMethodParameters.md b/docs/rules/AvoidPrefixingMethodParameters.md deleted file mode 100644 index 076b707c..00000000 --- a/docs/rules/AvoidPrefixingMethodParameters.md +++ /dev/null @@ -1,20 +0,0 @@ -# AvoidPrefixingMethodParameters -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidPrefixingMethodParameters`
-> :warning: This rule is **deprecated** in favour of [S00117](https://rules.sonarsource.com/java/RSPEC-117). - ------ - -Prefixing parameters by 'in' or 'out' pollutes the name of the parameters and reduces code readability. -To indicate whether or not a parameter will be modify in a method, its better to document method -behavior with Javadoc. Example: -
-// Not really clear
-public class Foo {
-  public void bar(
-      int inLeftOperand,
-      Result outRightOperand) {
-      outRightOperand.setValue(inLeftOperand * outRightOperand.getValue());
-  }
-}
-
diff --git a/docs/rules/AvoidPrintStackTrace.md b/docs/rules/AvoidPrintStackTrace.md deleted file mode 100644 index c86b53e1..00000000 --- a/docs/rules/AvoidPrintStackTrace.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidPrintStackTrace -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidPrintStackTrace`
-> :warning: This rule is **deprecated** in favour of [S1148](https://rules.sonarsource.com/java/RSPEC-1148). - ------ - -Avoid printStackTrace(); use a logger call instead. diff --git a/docs/rules/AvoidProtectedFieldInFinalClass.md b/docs/rules/AvoidProtectedFieldInFinalClass.md deleted file mode 100644 index baa47ac5..00000000 --- a/docs/rules/AvoidProtectedFieldInFinalClass.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidProtectedFieldInFinalClass -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidProtectedFieldInFinalClass`
-> :warning: This rule is **deprecated** in favour of [S2156](https://rules.sonarsource.com/java/RSPEC-2156). - ------ - -Do not use protected fields in final classes since they cannot be subclassed. Clarify your intent by using private or package access modifiers instead. diff --git a/docs/rules/AvoidProtectedMethodInFinalClassNotExtending.md b/docs/rules/AvoidProtectedMethodInFinalClassNotExtending.md deleted file mode 100644 index d56b5ed2..00000000 --- a/docs/rules/AvoidProtectedMethodInFinalClassNotExtending.md +++ /dev/null @@ -1,16 +0,0 @@ -# AvoidProtectedMethodInFinalClassNotExtending -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidProtectedMethodInFinalClassNotExtending`
-> :warning: This rule is **deprecated** in favour of [S2156](https://rules.sonarsource.com/java/RSPEC-2156). - ------ - -Do not use protected methods in most final classes since they cannot be subclassed. This should -only be allowed in final classes that extend other classes with protected methods (whose -visibility cannot be reduced). Clarify your intent by using private or package access modifiers instead. Example: -
-public final class Foo {
-  private int bar() {}
-  protected int baz() {} // Foo cannot be subclassed, and doesn't extend anything, so is baz() really private or package visible? 
-}
-
diff --git a/docs/rules/AvoidReassigningParameters.md b/docs/rules/AvoidReassigningParameters.md deleted file mode 100644 index bb36e3bd..00000000 --- a/docs/rules/AvoidReassigningParameters.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidReassigningParameters -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidReassigningParameters`
-> :warning: This rule is **deprecated** in favour of [S1226](https://rules.sonarsource.com/java/RSPEC-1226). - ------ - -Reassigning values to parameters is a questionable practice. Use a temporary local variable instead. diff --git a/docs/rules/AvoidRethrowingException.md b/docs/rules/AvoidRethrowingException.md deleted file mode 100644 index e8733058..00000000 --- a/docs/rules/AvoidRethrowingException.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidRethrowingException -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidRethrowingException`
-> :warning: This rule is **deprecated** in favour of [S1166](https://rules.sonarsource.com/java/RSPEC-1166). - ------ - -Catch blocks that merely rethrow a caught exception only add to code size and runtime complexity. diff --git a/docs/rules/AvoidStringBufferField.md b/docs/rules/AvoidStringBufferField.md deleted file mode 100644 index 3ea538bb..00000000 --- a/docs/rules/AvoidStringBufferField.md +++ /dev/null @@ -1,13 +0,0 @@ -# AvoidStringBufferField -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidStringBufferField`
-> :warning: This rule is **deprecated** in favour of [S1149](https://rules.sonarsource.com/java/RSPEC-1149). - ------ - -StringBuffers can grow quite a lot, and so may become a source of memory leak (if the owning class has a long life time). Example : -
-class Foo {
-  private StringBuffer memoryLeak;
-}
-
diff --git a/docs/rules/AvoidSynchronizedAtMethodLevel.md b/docs/rules/AvoidSynchronizedAtMethodLevel.md deleted file mode 100644 index e70ecede..00000000 --- a/docs/rules/AvoidSynchronizedAtMethodLevel.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidSynchronizedAtMethodLevel -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidSynchronizedAtMethodLevel`
- - ------ - -Method level synchronization can backfire when new code is added to the method. Block-level synchronization helps to ensure that only the code that needs synchronization gets it. diff --git a/docs/rules/AvoidThreadGroup.md b/docs/rules/AvoidThreadGroup.md deleted file mode 100644 index 078865e4..00000000 --- a/docs/rules/AvoidThreadGroup.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidThreadGroup -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidThreadGroup`
- - ------ - -Avoid using ThreadGroup; although it is intended to be used in a threaded environment it contains methods that are not thread safe. diff --git a/docs/rules/AvoidThrowingNewInstanceOfSameException.md b/docs/rules/AvoidThrowingNewInstanceOfSameException.md deleted file mode 100644 index 3f5e59e2..00000000 --- a/docs/rules/AvoidThrowingNewInstanceOfSameException.md +++ /dev/null @@ -1,20 +0,0 @@ -# AvoidThrowingNewInstanceOfSameException -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidThrowingNewInstanceOfSameException`
-> :warning: This rule is **deprecated** in favour of [S1166](https://rules.sonarsource.com/java/RSPEC-1166). - ------ - -Catch blocks that merely rethrow a caught exception wrapped inside a new instance of the same type only add to code size and runtime complexity. Example : -
-public class Foo {
-  void bar() {
-    try {
-      // do something
-    }  catch (SomeException se) {
-      // harmless comment
-      throw new SomeException(se);
-    }
-  }
-}
-
diff --git a/docs/rules/AvoidThrowingNullPointerException.md b/docs/rules/AvoidThrowingNullPointerException.md deleted file mode 100644 index 3a2d1ef9..00000000 --- a/docs/rules/AvoidThrowingNullPointerException.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidThrowingNullPointerException -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidThrowingNullPointerException`
-> :warning: This rule is **deprecated** in favour of [S1695](https://rules.sonarsource.com/java/RSPEC-1695). - ------ - -Avoid throwing a NullPointerException - it's confusing because most people will assume that the virtual machine threw it. Consider using an IllegalArgumentException instead; this will be clearly seen as a programmer-initiated exception. diff --git a/docs/rules/AvoidThrowingRawExceptionTypes.md b/docs/rules/AvoidThrowingRawExceptionTypes.md deleted file mode 100644 index fc800acd..00000000 --- a/docs/rules/AvoidThrowingRawExceptionTypes.md +++ /dev/null @@ -1,11 +0,0 @@ -# AvoidThrowingRawExceptionTypes -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidThrowingRawExceptionTypes`
-> :warning: This rule is **deprecated** in favour of [S00112](https://rules.sonarsource.com/java/RSPEC-112). - ------ - -

- Avoid throwing certain exception types. Rather than throw a raw RuntimeException, Throwable, Exception, or Error, use - a subclassed exception or error instead. -

diff --git a/docs/rules/AvoidUsingHardCodedIP.md b/docs/rules/AvoidUsingHardCodedIP.md deleted file mode 100644 index 90283c51..00000000 --- a/docs/rules/AvoidUsingHardCodedIP.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidUsingHardCodedIP -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidUsingHardCodedIP`
-> :warning: This rule is **deprecated** in favour of [S1313](https://rules.sonarsource.com/java/RSPEC-1313). - ------ - -An application with hard-coded IP addresses can become impossible to deploy in some cases. Externalizing IP addresses is preferable. diff --git a/docs/rules/AvoidUsingNativeCode.md b/docs/rules/AvoidUsingNativeCode.md deleted file mode 100644 index 8d8fab0f..00000000 --- a/docs/rules/AvoidUsingNativeCode.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidUsingNativeCode -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidUsingNativeCode`
- - ------ - -As JVM and Java language offer already many help in creating application, it should be very rare to have to rely on non-java code. Even though, it is rare to actually have to use Java Native Interface (JNI). As the use of JNI make application less portable, and harder to maintain, it is not recommended. diff --git a/docs/rules/AvoidUsingOctalValues.md b/docs/rules/AvoidUsingOctalValues.md deleted file mode 100644 index 596a3529..00000000 --- a/docs/rules/AvoidUsingOctalValues.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidUsingOctalValues -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidUsingOctalValues`
-> :warning: This rule is **deprecated** in favour of [S1314](https://rules.sonarsource.com/java/RSPEC-1314). - ------ - -Integer literals should not start with zero. Zero means that the rest of literal will be interpreted as an octal value. diff --git a/docs/rules/AvoidUsingShortType.md b/docs/rules/AvoidUsingShortType.md deleted file mode 100644 index d4de59d9..00000000 --- a/docs/rules/AvoidUsingShortType.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidUsingShortType -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidUsingShortType`
- - ------ - -Java uses the short type to reduce memory usage, not to optimize calculation. On the contrary, the JVM does not have arithmetic capabilities with the type short. So, the P-code must convert the short into int, then do the proper calculation and then again, convert int to short. So, use of the short type may have a great effect on memory usage. diff --git a/docs/rules/AvoidUsingVolatile.md b/docs/rules/AvoidUsingVolatile.md deleted file mode 100644 index d0921366..00000000 --- a/docs/rules/AvoidUsingVolatile.md +++ /dev/null @@ -1,8 +0,0 @@ -# AvoidUsingVolatile -**Category:** `pmd`
-**Rule Key:** `pmd:AvoidUsingVolatile`
- - ------ - -Use of the keyword "volatile" is general used to fine tune a Java application, and therefore, requires a good expertise of the Java Memory Model. Morover, its range of action is somewhat misknown. Therefore, the volatile keyword should not be used for maintenance purpose and portability. diff --git a/docs/rules/BadComparison.md b/docs/rules/BadComparison.md deleted file mode 100644 index 439740e5..00000000 --- a/docs/rules/BadComparison.md +++ /dev/null @@ -1,8 +0,0 @@ -# BadComparison -**Category:** `pmd`
-**Rule Key:** `pmd:BadComparison`
- - ------ - -Avoid equality comparisons with Double.NaN - these are likely to be logic errors. diff --git a/docs/rules/BeanMembersShouldSerialize.md b/docs/rules/BeanMembersShouldSerialize.md deleted file mode 100644 index 99895f33..00000000 --- a/docs/rules/BeanMembersShouldSerialize.md +++ /dev/null @@ -1,8 +0,0 @@ -# BeanMembersShouldSerialize -**Category:** `pmd`
-**Rule Key:** `pmd:BeanMembersShouldSerialize`
- - ------ - -If a class is a bean, or is referenced by a bean directly or indirectly it needs to be serializable. Member variables need to be marked as transient, static, or have accessor methods in the class. Marking variables as transient is the safest and easiest modification. Accessor methods should follow the Java naming conventions, i.e.if you have a variable foo, you should provide getFoo and setFoo methods. diff --git a/docs/rules/BigIntegerInstantiation.md b/docs/rules/BigIntegerInstantiation.md deleted file mode 100644 index 8570a886..00000000 --- a/docs/rules/BigIntegerInstantiation.md +++ /dev/null @@ -1,8 +0,0 @@ -# BigIntegerInstantiation -**Category:** `pmd`
-**Rule Key:** `pmd:BigIntegerInstantiation`
- - ------ - -Don't create instances of already existing BigInteger (BigInteger.ZERO, BigInteger.ONE) and for 1.5 on, BigInteger.TEN and BigDecimal (BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN) diff --git a/docs/rules/BooleanGetMethodName.md b/docs/rules/BooleanGetMethodName.md deleted file mode 100644 index e7911cc4..00000000 --- a/docs/rules/BooleanGetMethodName.md +++ /dev/null @@ -1,8 +0,0 @@ -# BooleanGetMethodName -**Category:** `pmd`
-**Rule Key:** `pmd:BooleanGetMethodName`
- - ------ - -Looks for methods named "getX()" with "boolean" as the return type. The convention is to name these methods "isX()". diff --git a/docs/rules/BooleanInstantiation.md b/docs/rules/BooleanInstantiation.md deleted file mode 100644 index 9663e462..00000000 --- a/docs/rules/BooleanInstantiation.md +++ /dev/null @@ -1,8 +0,0 @@ -# BooleanInstantiation -**Category:** `pmd`
-**Rule Key:** `pmd:BooleanInstantiation`
- - ------ - -Avoid instantiating Boolean objects; you can reference Boolean.TRUE, Boolean.FALSE, or call Boolean.valueOf() instead. diff --git a/docs/rules/BrokenNullCheck.md b/docs/rules/BrokenNullCheck.md deleted file mode 100644 index 757fbf9a..00000000 --- a/docs/rules/BrokenNullCheck.md +++ /dev/null @@ -1,8 +0,0 @@ -# BrokenNullCheck -**Category:** `pmd`
-**Rule Key:** `pmd:BrokenNullCheck`
-> :warning: This rule is **deprecated** in favour of [S1697](https://rules.sonarsource.com/java/RSPEC-1697). - ------ - -The null check is broken since it will throw a Nullpointer itself. The reason is that a method is called on the object when it is null. It is likely that you used || instead of && or vice versa. diff --git a/docs/rules/ByteInstantiation.md b/docs/rules/ByteInstantiation.md deleted file mode 100644 index 452cdeee..00000000 --- a/docs/rules/ByteInstantiation.md +++ /dev/null @@ -1,14 +0,0 @@ -# ByteInstantiation -**Category:** `pmd`
-**Rule Key:** `pmd:ByteInstantiation`
- - ------ - -In JDK 1.5, calling new Byte() causes memory allocation. Byte.valueOf() is more memory friendly. Example : -
-public class Foo {
-private Byte i = new Byte(0); // change to Byte i =
-Byte.valueOf(0);
-}
-
diff --git a/docs/rules/CallSuperFirst.md b/docs/rules/CallSuperFirst.md deleted file mode 100644 index f9775f42..00000000 --- a/docs/rules/CallSuperFirst.md +++ /dev/null @@ -1,16 +0,0 @@ -# CallSuperFirst -**Category:** `pmd`
-**Rule Key:** `pmd:CallSuperFirst`
- - ------ - -Super should be called at the start of the method. Example : -
-public class DummyActivity extends Activity {
-  public void onCreate(Bundle bundle) {
-    // missing call to super.onCreate(bundle)
-    foo();
-  }
-}
-
diff --git a/docs/rules/CallSuperInConstructor.md b/docs/rules/CallSuperInConstructor.md deleted file mode 100644 index 27f149e4..00000000 --- a/docs/rules/CallSuperInConstructor.md +++ /dev/null @@ -1,8 +0,0 @@ -# CallSuperInConstructor -**Category:** `pmd`
-**Rule Key:** `pmd:CallSuperInConstructor`
- - ------ - -It is a good practice to call super() in a constructor. If super() is not called but another constructor (such as an overloaded constructor) is called, this rule will not report it. diff --git a/docs/rules/CallSuperLast.md b/docs/rules/CallSuperLast.md deleted file mode 100644 index d80f3934..00000000 --- a/docs/rules/CallSuperLast.md +++ /dev/null @@ -1,16 +0,0 @@ -# CallSuperLast -**Category:** `pmd`
-**Rule Key:** `pmd:CallSuperLast`
- - ------ - -Super should be called at the end of the method. Example : -
-public class DummyActivity extends Activity {
-  public void onPause() {
-    foo();
-    // missing call to super.onPause()
-  }
-}
-
diff --git a/docs/rules/CheckResultSet.md b/docs/rules/CheckResultSet.md deleted file mode 100644 index 6cf54d3d..00000000 --- a/docs/rules/CheckResultSet.md +++ /dev/null @@ -1,8 +0,0 @@ -# CheckResultSet -**Category:** `pmd`
-**Rule Key:** `pmd:CheckResultSet`
- - ------ - -Always check the return of one of the navigation method (next,previous,first,last) of a ResultSet. Indeed, if the value return is "false", the developer should deal with it ! diff --git a/docs/rules/CheckSkipResult.md b/docs/rules/CheckSkipResult.md deleted file mode 100644 index 32d69367..00000000 --- a/docs/rules/CheckSkipResult.md +++ /dev/null @@ -1,26 +0,0 @@ -# CheckSkipResult -**Category:** `pmd`
-**Rule Key:** `pmd:CheckSkipResult`
-> :warning: This rule is **deprecated** in favour of [S2674](https://rules.sonarsource.com/java/RSPEC-2674). - ------ - -The skip() method may skip a smaller number of bytes than requested. Check the returned value to find out if it was the case or not. Example: -
-public class Foo {
-
-   private FileInputStream _s = new FileInputStream("file");
-
-   public void skip(int n) throws IOException {
-      _s.skip(n); // You are not sure that exactly n bytes are skipped
-   }
-
-   public void skipExactly(int n) throws IOException {
-      while (n != 0) {
-         long skipped = _s.skip(n);
-         if (skipped == 0)
-            throw new EOFException();
-         n -= skipped;
-      }
-   }
-
diff --git a/docs/rules/ClassCastExceptionWithToArray.md b/docs/rules/ClassCastExceptionWithToArray.md deleted file mode 100644 index b883d1c6..00000000 --- a/docs/rules/ClassCastExceptionWithToArray.md +++ /dev/null @@ -1,8 +0,0 @@ -# ClassCastExceptionWithToArray -**Category:** `pmd`
-**Rule Key:** `pmd:ClassCastExceptionWithToArray`
- - ------ - -if you need to get an array of a class from your Collection, you should pass an array of the desidered class as the parameter of the toArray method. Otherwise you will get a ClassCastException. diff --git a/docs/rules/ClassNamingConventions.md b/docs/rules/ClassNamingConventions.md deleted file mode 100644 index 0335f144..00000000 --- a/docs/rules/ClassNamingConventions.md +++ /dev/null @@ -1,10 +0,0 @@ -# ClassNamingConventions -**Category:** `pmd`
-**Rule Key:** `pmd:ClassNamingConventions`
-> :warning: This rule is **deprecated** in favour of [S00101](https://rules.sonarsource.com/java/RSPEC-101), [S00114](https://rules.sonarsource.com/java/RSPEC-114). - ------ - -

- Class names should always begin with an upper case character. -

diff --git a/docs/rules/ClassWithOnlyPrivateConstructorsShouldBeFinal.md b/docs/rules/ClassWithOnlyPrivateConstructorsShouldBeFinal.md deleted file mode 100644 index a4f8c2df..00000000 --- a/docs/rules/ClassWithOnlyPrivateConstructorsShouldBeFinal.md +++ /dev/null @@ -1,13 +0,0 @@ -# ClassWithOnlyPrivateConstructorsShouldBeFinal -**Category:** `pmd`
-**Rule Key:** `pmd:ClassWithOnlyPrivateConstructorsShouldBeFinal`
-> :warning: This rule is **deprecated** in favour of [S2974](https://rules.sonarsource.com/java/RSPEC-2974). - ------ - -A class with only private constructors should be final, unless the private constructor is called by a inner class. Example : -
-public class Foo {  //Should be final
-    private Foo() { }
-}
-
diff --git a/docs/rules/CloneMethodMustBePublic.md b/docs/rules/CloneMethodMustBePublic.md deleted file mode 100644 index aafe71c9..00000000 --- a/docs/rules/CloneMethodMustBePublic.md +++ /dev/null @@ -1,31 +0,0 @@ -# CloneMethodMustBePublic -**Category:** `pmd`
-**Rule Key:** `pmd:CloneMethodMustBePublic`
- - ------ - -

- The java Manual says “By convention, classes that implement this interface should override Object.clone (which is - protected) with a public method.” -

- -

Examples:

-
-public class Foo implements Cloneable {
-  @Override
-  protected Object clone() throws CloneNotSupportedException { // Violation, must be public
-  }
-}
-
-public class Foo implements Cloneable {
-  @Override
-  protected Foo clone() { // Violation, must be public
-  }
-}
-
-public class Foo implements Cloneable {
-  @Override
-  public Object clone() // Ok
-}
-
diff --git a/docs/rules/CloneMethodMustImplementCloneable.md b/docs/rules/CloneMethodMustImplementCloneable.md deleted file mode 100644 index e5fb30da..00000000 --- a/docs/rules/CloneMethodMustImplementCloneable.md +++ /dev/null @@ -1,8 +0,0 @@ -# CloneMethodMustImplementCloneable -**Category:** `pmd`
-**Rule Key:** `pmd:CloneMethodMustImplementCloneable`
-> :warning: This rule is **deprecated** in favour of [S1182](https://rules.sonarsource.com/java/RSPEC-1182). - ------ - -The method clone() should only be implemented if the class implements the Cloneable interface with the exception of a final method that only throws CloneNotSupportedException. diff --git a/docs/rules/CloneMethodMustImplementCloneableWithTypeResolution.md b/docs/rules/CloneMethodMustImplementCloneableWithTypeResolution.md deleted file mode 100644 index f7e7e0c4..00000000 --- a/docs/rules/CloneMethodMustImplementCloneableWithTypeResolution.md +++ /dev/null @@ -1,17 +0,0 @@ -# CloneMethodMustImplementCloneableWithTypeResolution -**Category:** `pmd`
-**Rule Key:** `pmd:CloneMethodMustImplementCloneableWithTypeResolution`
-> :warning: This rule is **deprecated** in favour of [S1182](https://rules.sonarsource.com/java/RSPEC-1182). - ------ - -The method clone() should only be implemented if the class implements the Cloneable interface with the exception -of a final method that only throws CloneNotSupportedException. This version uses PMD's type resolution facilities, -and can detect if the class implements or extends a Cloneable class. Example: -
-public class MyClass {
-  public Object clone() throws CloneNotSupportedException {
-    return foo;
-  }
-}
-
diff --git a/docs/rules/CloneMethodReturnTypeMustMatchClassName.md b/docs/rules/CloneMethodReturnTypeMustMatchClassName.md deleted file mode 100644 index 444ed80c..00000000 --- a/docs/rules/CloneMethodReturnTypeMustMatchClassName.md +++ /dev/null @@ -1,30 +0,0 @@ -# CloneMethodReturnTypeMustMatchClassName -**Category:** `pmd`
-**Rule Key:** `pmd:CloneMethodReturnTypeMustMatchClassName`
- - ------ - -

Minimum Language Version: java 1.5

-

- If a class implements cloneable the return type of the method clone() must be the class name. That way, the caller of - the clone method doesn’t need to cast the returned clone to the correct type. -

-

- Note: This is only possible with Java 1.5 or higher. -

- -

Examples:

-
-public class Foo implements Cloneable {
-    @Override
-    protected Object clone() { // Violation, Object must be Foo
-    }
-}
-
-public class Foo implements Cloneable {
-    @Override
-    public Foo clone() { //Ok
-    }
-}
-
diff --git a/docs/rules/CloneThrowsCloneNotSupportedException.md b/docs/rules/CloneThrowsCloneNotSupportedException.md deleted file mode 100644 index b0b4a928..00000000 --- a/docs/rules/CloneThrowsCloneNotSupportedException.md +++ /dev/null @@ -1,8 +0,0 @@ -# CloneThrowsCloneNotSupportedException -**Category:** `pmd`
-**Rule Key:** `pmd:CloneThrowsCloneNotSupportedException`
-> :warning: This rule is **deprecated** in favour of [S1182](https://rules.sonarsource.com/java/RSPEC-1182). - ------ - -The method clone() should throw a CloneNotSupportedException. diff --git a/docs/rules/CloseResource.md b/docs/rules/CloseResource.md deleted file mode 100644 index e83047e3..00000000 --- a/docs/rules/CloseResource.md +++ /dev/null @@ -1,16 +0,0 @@ -# CloseResource -**Category:** `pmd`
-**Rule Key:** `pmd:CloseResource`
-> :warning: This rule is **deprecated** in favour of [S2095](https://rules.sonarsource.com/java/RSPEC-2095). - ------ - -Ensure that resources (like Connection, Statement, and ResultSet objects) are always closed after use. It does this by looking for code patterned like : -
-Connection c = openConnection();
-try {
-  // do stuff, and maybe catch something
-} finally {
-  c.close();
-}
-
diff --git a/docs/rules/CollapsibleIfStatements.md b/docs/rules/CollapsibleIfStatements.md deleted file mode 100644 index bdfc6857..00000000 --- a/docs/rules/CollapsibleIfStatements.md +++ /dev/null @@ -1,8 +0,0 @@ -# CollapsibleIfStatements -**Category:** `pmd`
-**Rule Key:** `pmd:CollapsibleIfStatements`
-> :warning: This rule is **deprecated** in favour of [S1066](https://rules.sonarsource.com/java/RSPEC-1066). - ------ - -Sometimes two 'if' statements can be consolidated by separating their conditions with a boolean short-circuit operator. diff --git a/docs/rules/CommentContent.md b/docs/rules/CommentContent.md deleted file mode 100644 index 41585c9e..00000000 --- a/docs/rules/CommentContent.md +++ /dev/null @@ -1,11 +0,0 @@ -# CommentContent -**Category:** `pmd`
-**Rule Key:** `pmd:CommentContent`
- - ------ - -A rule for the politically correct... we don't want to offend anyone. Example: -
-// OMG, this is horrible, Bob is an idiot !!!
-
diff --git a/docs/rules/CommentDefaultAccessModifier.md b/docs/rules/CommentDefaultAccessModifier.md deleted file mode 100644 index 8c54f317..00000000 --- a/docs/rules/CommentDefaultAccessModifier.md +++ /dev/null @@ -1,35 +0,0 @@ -# CommentDefaultAccessModifier -**Category:** `pmd`
-**Rule Key:** `pmd:CommentDefaultAccessModifier`
- - ------ - -

- To avoid mistakes if we want that a Method, Field or Nested class have a default access modifier - we must add a comment at the beginning of the Method, Field or Nested class. - By default the comment must be /* default */, if you want another, you have to provide a regex. -

- -
-public class Foo {
-    final String stringValue = "some string";
-    String getString() {
-       return stringValue;
-    }
-
-    class NestedFoo {
-    }
-}
-
-// should be
-public class Foo {
-  /* default */ final String stringValue = "some string";
-  /* default */ String getString() {
-     return stringValue;
-  }
-
-  /* default */ class NestedFoo {
-  }
-}
-
diff --git a/docs/rules/CommentRequired.md b/docs/rules/CommentRequired.md deleted file mode 100644 index 34af27b5..00000000 --- a/docs/rules/CommentRequired.md +++ /dev/null @@ -1,15 +0,0 @@ -# CommentRequired -**Category:** `pmd`
-**Rule Key:** `pmd:CommentRequired`
- - ------ - -Denotes whether comments are required (or unwanted) for specific language elements. Example: -
-/**
-* 
-*
-* @author George Bush
-*/
-
diff --git a/docs/rules/CommentSize.md b/docs/rules/CommentSize.md deleted file mode 100644 index 80bfc6df..00000000 --- a/docs/rules/CommentSize.md +++ /dev/null @@ -1,26 +0,0 @@ -# CommentSize -**Category:** `pmd`
-**Rule Key:** `pmd:CommentSize`
- - ------ - -Determines whether the dimensions of non-header comments found are within the specified limits. Example: -
-/**
-*
-* too many lines!
-*
-*
-*
-*
-*
-*
-*
-*
-*
-*
-*
-*
-*/
-
diff --git a/docs/rules/CompareObjectsWithEquals.md b/docs/rules/CompareObjectsWithEquals.md deleted file mode 100644 index 89912807..00000000 --- a/docs/rules/CompareObjectsWithEquals.md +++ /dev/null @@ -1,8 +0,0 @@ -# CompareObjectsWithEquals -**Category:** `pmd`
-**Rule Key:** `pmd:CompareObjectsWithEquals`
-> :warning: This rule is **deprecated** in favour of [S1698](https://rules.sonarsource.com/java/RSPEC-1698). - ------ - -Use equals() to compare object references; avoid comparing them with ==. diff --git a/docs/rules/ConfusingTernary.md b/docs/rules/ConfusingTernary.md deleted file mode 100644 index a4759098..00000000 --- a/docs/rules/ConfusingTernary.md +++ /dev/null @@ -1,8 +0,0 @@ -# ConfusingTernary -**Category:** `pmd`
-**Rule Key:** `pmd:ConfusingTernary`
- - ------ - -In an if expression with an else clause, avoid negation in the test. For example, rephrase: if (x != y) diff(); else same(); as: if (x == y) same(); else diff(); Most if (x != y) cases without an else are often return cases, so consistent use of this rule makes the code easier to read. Also, this resolves trivial ordering problems, such as does the error case go first? or does the common case go first?. diff --git a/docs/rules/ConsecutiveAppendsShouldReuse.md b/docs/rules/ConsecutiveAppendsShouldReuse.md deleted file mode 100644 index 3bbf3545..00000000 --- a/docs/rules/ConsecutiveAppendsShouldReuse.md +++ /dev/null @@ -1,19 +0,0 @@ -# ConsecutiveAppendsShouldReuse -**Category:** `pmd`
-**Rule Key:** `pmd:ConsecutiveAppendsShouldReuse`
- - ------ - -Consecutively calls to StringBuffer/StringBuilder .append should reuse the target object. This can improve the performance. Example: -
-String foo = " ";
-
-StringBuffer buf = new StringBuffer();
-buf.append("Hello"); // poor
-buf.append(foo);
-buf.append("World");
-
-StringBuffer buf = new StringBuffer();
-buf.append("Hello").append(foo).append("World"); // good
-
diff --git a/docs/rules/ConsecutiveLiteralAppends.md b/docs/rules/ConsecutiveLiteralAppends.md deleted file mode 100644 index d7a1cb7c..00000000 --- a/docs/rules/ConsecutiveLiteralAppends.md +++ /dev/null @@ -1,8 +0,0 @@ -# ConsecutiveLiteralAppends -**Category:** `pmd`
-**Rule Key:** `pmd:ConsecutiveLiteralAppends`
- - ------ - -Consecutively calling StringBuffer.append with String literals diff --git a/docs/rules/ConstructorCallsOverridableMethod.md b/docs/rules/ConstructorCallsOverridableMethod.md deleted file mode 100644 index 4d5b9da8..00000000 --- a/docs/rules/ConstructorCallsOverridableMethod.md +++ /dev/null @@ -1,34 +0,0 @@ -# ConstructorCallsOverridableMethod -**Category:** `pmd`
-**Rule Key:** `pmd:ConstructorCallsOverridableMethod`
-> :warning: This rule is **deprecated** in favour of [S1699](https://rules.sonarsource.com/java/RSPEC-1699). - ------ - -Calling overridable methods during construction poses a risk of invoking methods on an incompletely constructed object -and can be difficult to discern. It may leave the sub-class unable to construct its superclass or forced to replicate -the construction process completely within itself, losing the ability to call super(). -If the default constructor contains a call to an overridable method, the subclass may be completely uninstantiable. -Note that this includes method calls throughout the control flow graph - i.e., if a constructor Foo() calls -a private method bar() that calls a public method buz(), this denotes a problem. -
Example : -
-public class SeniorClass {
-  public SeniorClass(){
-      toString(); //may throw NullPointerException if overridden
-  }
-  public String toString(){
-    return "IAmSeniorClass";
-  }
-}
-public class JuniorClass extends SeniorClass {
-  private String name;
-  public JuniorClass(){
-    super(); //Automatic call leads to NullPointerException
-    name = "JuniorClass";
-  }
-  public String toString(){
-    return name.toUpperCase();
-  }
-}
-
diff --git a/docs/rules/CouplingBetweenObjects.md b/docs/rules/CouplingBetweenObjects.md deleted file mode 100644 index 97ca1efd..00000000 --- a/docs/rules/CouplingBetweenObjects.md +++ /dev/null @@ -1,8 +0,0 @@ -# CouplingBetweenObjects -**Category:** `pmd`
-**Rule Key:** `pmd:CouplingBetweenObjects`
-> :warning: This rule is **deprecated** in favour of [S1200](https://rules.sonarsource.com/java/RSPEC-1200). - ------ - -This rule counts unique attributes, local variables and return types within an object. A number higher than specified threshold can indicate a high degree of coupling. diff --git a/docs/rules/CyclomaticComplexity.md b/docs/rules/CyclomaticComplexity.md deleted file mode 100644 index 755885f5..00000000 --- a/docs/rules/CyclomaticComplexity.md +++ /dev/null @@ -1,12 +0,0 @@ -# CyclomaticComplexity -**Category:** `pmd`
-**Rule Key:** `pmd:CyclomaticComplexity`
-> :warning: This rule is **deprecated** in favour of `squid:MethodCyclomaticComplexity`, `squid:ClassCyclomaticComplexity`. - ------ - -

- Complexity is determined by the number of decision points in a method plus one for the method entry. The decision - points are 'if', 'while', 'for', and 'case labels'. Generally, 1-4 is low complexity, 5-7 indicates moderate - complexity, 8-10 is high complexity, and 11+ is very high complexity. -

diff --git a/docs/rules/DataflowAnomalyAnalysis.md b/docs/rules/DataflowAnomalyAnalysis.md deleted file mode 100644 index dd5ba116..00000000 --- a/docs/rules/DataflowAnomalyAnalysis.md +++ /dev/null @@ -1,8 +0,0 @@ -# DataflowAnomalyAnalysis -**Category:** `pmd`
-**Rule Key:** `pmd:DataflowAnomalyAnalysis`
- - ------ - -The dataflow analysis tracks local definitions, undefinitions and references to variables on different paths on the data flow. From those informations there can be found various problems. 1. UR - Anomaly: There is a reference to a variable that was not defined before. This is a bug and leads to an error. 2. DU - Anomaly: A recently defined variable is undefined. These anomalies may appear in normal source text. 3. DD - Anomaly: A recently defined variable is redefined. This is ominous but don't have to be a bug. diff --git a/docs/rules/DefaultLabelNotLastInSwitchStmt.md b/docs/rules/DefaultLabelNotLastInSwitchStmt.md deleted file mode 100644 index 62238f10..00000000 --- a/docs/rules/DefaultLabelNotLastInSwitchStmt.md +++ /dev/null @@ -1,22 +0,0 @@ -# DefaultLabelNotLastInSwitchStmt -**Category:** `pmd`
-**Rule Key:** `pmd:DefaultLabelNotLastInSwitchStmt`
-> :warning: This rule is **deprecated** in favour of `squid:SwitchLastCaseIsDefaultCheck`. - ------ - -Switch statements should have a default label. Example : -
-public class Foo {
- void bar(int a) {
-  switch (a) {
-   case 1:  // do something
-      break;
-   default:  // the default case should be last, by convention
-      break;
-   case 2:
-      break;
-  }
- }
-}
-  
diff --git a/docs/rules/DefaultPackage.md b/docs/rules/DefaultPackage.md deleted file mode 100644 index 2631e81f..00000000 --- a/docs/rules/DefaultPackage.md +++ /dev/null @@ -1,8 +0,0 @@ -# DefaultPackage -**Category:** `pmd`
-**Rule Key:** `pmd:DefaultPackage`
- - ------ - -Use explicit scoping instead of the default package private level. diff --git a/docs/rules/DoNotCallGarbageCollectionExplicitly.md b/docs/rules/DoNotCallGarbageCollectionExplicitly.md deleted file mode 100644 index 15a774f4..00000000 --- a/docs/rules/DoNotCallGarbageCollectionExplicitly.md +++ /dev/null @@ -1,27 +0,0 @@ -# DoNotCallGarbageCollectionExplicitly -**Category:** `pmd`
-**Rule Key:** `pmd:DoNotCallGarbageCollectionExplicitly`
-> :warning: This rule is **deprecated** in favour of [S1215](https://rules.sonarsource.com/java/RSPEC-1215). - ------ - -Calls to System.gc(), Runtime.getRuntime().gc(), and System.runFinalization() are not advised. Code should have the same behavior whether the garbage collection is disabled using the option -Xdisableexplicitgc or not. Moreover, "modern" jvms do a very good job handling garbage collections. If memory usage issues unrelated to memory leaks develop within an application, it should be dealt with JVM options rather than within the code itself. Example : -
- public class GCCall
-{
-  public GCCall()
-  {
-  // Explicit gc call !
-    System.gc();
-  }
-  public void doSomething()
-  {
-    // Explicit gc call !
-    Runtime.getRuntime().gc();
-  }
-
-  public explicitGCcall() { // Explicit gc call ! System.gc(); }
-
-  public void doSomething() { // Explicit gc call ! Runtime.getRuntime().gc(); }
-}
-
diff --git a/docs/rules/DoNotCallSystemExit.md b/docs/rules/DoNotCallSystemExit.md deleted file mode 100644 index c8b06fee..00000000 --- a/docs/rules/DoNotCallSystemExit.md +++ /dev/null @@ -1,8 +0,0 @@ -# DoNotCallSystemExit -**Category:** `pmd`
-**Rule Key:** `pmd:DoNotCallSystemExit`
-> :warning: This rule is **deprecated** in favour of [S1147](https://rules.sonarsource.com/java/RSPEC-1147). - ------ - -Web applications should not call System.exit(), since only the web container or the application server should stop the JVM. diff --git a/docs/rules/DoNotExtendJavaLangError.md b/docs/rules/DoNotExtendJavaLangError.md deleted file mode 100644 index 75b593f8..00000000 --- a/docs/rules/DoNotExtendJavaLangError.md +++ /dev/null @@ -1,8 +0,0 @@ -# DoNotExtendJavaLangError -**Category:** `pmd`
-**Rule Key:** `pmd:DoNotExtendJavaLangError`
-> :warning: This rule is **deprecated** in favour of [S1194](https://rules.sonarsource.com/java/RSPEC-1194). - ------ - -Errors are system exceptions. Do not extend them. diff --git a/docs/rules/DoNotHardCodeSDCard.md b/docs/rules/DoNotHardCodeSDCard.md deleted file mode 100644 index 383b9d4f..00000000 --- a/docs/rules/DoNotHardCodeSDCard.md +++ /dev/null @@ -1,8 +0,0 @@ -# DoNotHardCodeSDCard -**Category:** `pmd`
-**Rule Key:** `pmd:DoNotHardCodeSDCard`
- - ------ - -Use Environment.getExternalStorageDirectory() instead of "/sdcard". diff --git a/docs/rules/DoNotThrowExceptionInFinally.md b/docs/rules/DoNotThrowExceptionInFinally.md deleted file mode 100644 index a4f1741c..00000000 --- a/docs/rules/DoNotThrowExceptionInFinally.md +++ /dev/null @@ -1,27 +0,0 @@ -# DoNotThrowExceptionInFinally -**Category:** `pmd`
-**Rule Key:** `pmd:DoNotThrowExceptionInFinally`
-> :warning: This rule is **deprecated** in favour of [S1163](https://rules.sonarsource.com/java/RSPEC-1163). - ------ - -Throwing exception in a finally block is confusing. It may mask exception or a defect of the code, it also render code cleanup uninstable. Example : -
-public class Foo
-{
-  public void bar()
-  {
-    try {
-    // Here do some stuff
-    }
-    catch( Exception e) {
-    // Handling the issue
-    }
-    finally
-    {
-      // is this really a good idea ?
-      throw new Exception();
-    }
-  }
-}
-
diff --git a/docs/rules/DoNotUseThreads.md b/docs/rules/DoNotUseThreads.md deleted file mode 100644 index 7ce2b2a9..00000000 --- a/docs/rules/DoNotUseThreads.md +++ /dev/null @@ -1,8 +0,0 @@ -# DoNotUseThreads -**Category:** `pmd`
-**Rule Key:** `pmd:DoNotUseThreads`
- - ------ - -The J2EE specification explicitly forbid use of threads. diff --git a/docs/rules/DontCallThreadRun.md b/docs/rules/DontCallThreadRun.md deleted file mode 100644 index c4672c69..00000000 --- a/docs/rules/DontCallThreadRun.md +++ /dev/null @@ -1,8 +0,0 @@ -# DontCallThreadRun -**Category:** `pmd`
-**Rule Key:** `pmd:DontCallThreadRun`
-> :warning: This rule is **deprecated** in favour of [S1217](https://rules.sonarsource.com/java/RSPEC-1217). - ------ - -Explicitly calling Thread.run() method will execute in the caller's thread of control. Instead, call Thread.start() for the intended behavior. diff --git a/docs/rules/DontImportJavaLang.md b/docs/rules/DontImportJavaLang.md deleted file mode 100644 index 4922ecf3..00000000 --- a/docs/rules/DontImportJavaLang.md +++ /dev/null @@ -1,8 +0,0 @@ -# DontImportJavaLang -**Category:** `pmd`
-**Rule Key:** `pmd:DontImportJavaLang`
-> :warning: This rule is **deprecated** in favour of `squid:UselessImportCheck`. - ------ - -Avoid importing anything from the package 'java.lang'. These classes are automatically imported (JLS 7.5.3). diff --git a/docs/rules/DontImportSun.md b/docs/rules/DontImportSun.md deleted file mode 100644 index 40e097c1..00000000 --- a/docs/rules/DontImportSun.md +++ /dev/null @@ -1,8 +0,0 @@ -# DontImportSun -**Category:** `pmd`
-**Rule Key:** `pmd:DontImportSun`
-> :warning: This rule is **deprecated** in favour of [S1191](https://rules.sonarsource.com/java/RSPEC-1191). - ------ - -Avoid importing anything from the 'sun.*' packages. These packages are not portable and are likely to change. diff --git a/docs/rules/DontUseFloatTypeForLoopIndices.md b/docs/rules/DontUseFloatTypeForLoopIndices.md deleted file mode 100644 index 49c5390e..00000000 --- a/docs/rules/DontUseFloatTypeForLoopIndices.md +++ /dev/null @@ -1,23 +0,0 @@ -# DontUseFloatTypeForLoopIndices -**Category:** `pmd`
-**Rule Key:** `pmd:DontUseFloatTypeForLoopIndices`
- - ------ - -Don't use floating point for loop indices. If you must use floating point, use double -unless you're certain that float provides enough precision and you have a compelling -performance need (space or time). Example: -
-public class Count {
-  public static void main(String[] args) {
-    final int START = 2000000000;
-    int count = 0;
-    for (float f = START; f < START + 50; f++)
-      count++;
-      //Prints 0 because (float) START == (float) (START + 50).
-      System.out.println(count);
-      //The termination test misbehaves due to floating point granularity.
-    }
-}
-
diff --git a/docs/rules/DoubleCheckedLocking.md b/docs/rules/DoubleCheckedLocking.md deleted file mode 100644 index c171778a..00000000 --- a/docs/rules/DoubleCheckedLocking.md +++ /dev/null @@ -1,24 +0,0 @@ -# DoubleCheckedLocking -**Category:** `pmd`
-**Rule Key:** `pmd:DoubleCheckedLocking`
- - ------ - -Partially created objects can be returned by the Double Checked Locking pattern when used in Java. An optimizing JRE may assign a reference to the baz variable before it creates the object the reference is intended to point to. -More details. Example : -
-public class Foo {
-  Object baz;
-  Object bar() {
-    if(baz == null) { //baz may be non-null yet not fully created
-      synchronized(this){
-        if(baz == null){
-          baz = new Object();
-        }
-      }
-    }
-    return baz;
-  }
-}
-
diff --git a/docs/rules/DuplicateImports.md b/docs/rules/DuplicateImports.md deleted file mode 100644 index 549f6c47..00000000 --- a/docs/rules/DuplicateImports.md +++ /dev/null @@ -1,8 +0,0 @@ -# DuplicateImports -**Category:** `pmd`
-**Rule Key:** `pmd:DuplicateImports`
-> :warning: This rule is **deprecated** in favour of `squid:UselessImportCheck`. - ------ - -Avoid duplicate import statements. diff --git a/docs/rules/EmptyCatchBlock.md b/docs/rules/EmptyCatchBlock.md deleted file mode 100644 index f868e997..00000000 --- a/docs/rules/EmptyCatchBlock.md +++ /dev/null @@ -1,11 +0,0 @@ -# EmptyCatchBlock -**Category:** `pmd`
-**Rule Key:** `pmd:EmptyCatchBlock`
-> :warning: This rule is **deprecated** in favour of [S00108](https://rules.sonarsource.com/java/RSPEC-108). - ------ - -

- Empty Catch Block finds instances where an exception is caught, but nothing is done. In most circumstances, this - swallows an exception which should either be acted on or reported. -

diff --git a/docs/rules/EmptyFinalizer.md b/docs/rules/EmptyFinalizer.md deleted file mode 100644 index 57ffe619..00000000 --- a/docs/rules/EmptyFinalizer.md +++ /dev/null @@ -1,8 +0,0 @@ -# EmptyFinalizer -**Category:** `pmd`
-**Rule Key:** `pmd:EmptyFinalizer`
-> :warning: This rule is **deprecated** in favour of [S1186](https://rules.sonarsource.com/java/RSPEC-1186). - ------ - -

If the finalize() method is empty, then it does not need to exist.

diff --git a/docs/rules/EmptyFinallyBlock.md b/docs/rules/EmptyFinallyBlock.md deleted file mode 100644 index 15bac996..00000000 --- a/docs/rules/EmptyFinallyBlock.md +++ /dev/null @@ -1,10 +0,0 @@ -# EmptyFinallyBlock -**Category:** `pmd`
-**Rule Key:** `pmd:EmptyFinallyBlock`
-> :warning: This rule is **deprecated** in favour of [S00108](https://rules.sonarsource.com/java/RSPEC-108). - ------ - -

- Avoid empty finally blocks - these can be deleted. -

diff --git a/docs/rules/EmptyIfStmt.md b/docs/rules/EmptyIfStmt.md deleted file mode 100644 index bec4fc84..00000000 --- a/docs/rules/EmptyIfStmt.md +++ /dev/null @@ -1,10 +0,0 @@ -# EmptyIfStmt -**Category:** `pmd`
-**Rule Key:** `pmd:EmptyIfStmt`
-> :warning: This rule is **deprecated** in favour of [S00108](https://rules.sonarsource.com/java/RSPEC-108). - ------ - -

- Empty If Statement finds instances where a condition is checked but nothing is done about it. -

diff --git a/docs/rules/EmptyInitializer.md b/docs/rules/EmptyInitializer.md deleted file mode 100644 index 5af896f2..00000000 --- a/docs/rules/EmptyInitializer.md +++ /dev/null @@ -1,17 +0,0 @@ -# EmptyInitializer -**Category:** `pmd`
-**Rule Key:** `pmd:EmptyInitializer`
-> :warning: This rule is **deprecated** in favour of [S00108](https://rules.sonarsource.com/java/RSPEC-108). - ------ - -An empty initializer was found. Example : -
-public class Foo {
-
-   static {} // Why ?
-
-   {} // Again, why ?
-
-}
-
diff --git a/docs/rules/EmptyMethodInAbstractClassShouldBeAbstract.md b/docs/rules/EmptyMethodInAbstractClassShouldBeAbstract.md deleted file mode 100644 index 435ab6d3..00000000 --- a/docs/rules/EmptyMethodInAbstractClassShouldBeAbstract.md +++ /dev/null @@ -1,22 +0,0 @@ -# EmptyMethodInAbstractClassShouldBeAbstract -**Category:** `pmd`
-**Rule Key:** `pmd:EmptyMethodInAbstractClassShouldBeAbstract`
- - ------ - -An empty method in an abstract class should be abstract instead, as developer may rely on this empty implementation rather than code the appropriate one. -
-public abstract class ShouldBeAbstract
-{
-  public Object couldBeAbstract()
-  {
-  // Should be abstract method ?
-    return null;
-  }
-
-  public void couldBeAbstract()
-  {
-  }
-}
-
diff --git a/docs/rules/EmptyStatementBlock.md b/docs/rules/EmptyStatementBlock.md deleted file mode 100644 index 7e9dc1cb..00000000 --- a/docs/rules/EmptyStatementBlock.md +++ /dev/null @@ -1,20 +0,0 @@ -# EmptyStatementBlock -**Category:** `pmd`
-**Rule Key:** `pmd:EmptyStatementBlock`
-> :warning: This rule is **deprecated** in favour of [S00108](https://rules.sonarsource.com/java/RSPEC-108). - ------ - -Empty block statements serve no purpose and should be removed. Example: -
-public class Foo {
-
-   private int _bar;
-
-   public void setBar(int bar) {
-      { _bar = bar; } // Why not?
-      {} // But remove this.
-   }
-
-}
-
diff --git a/docs/rules/EmptyStatementNotInLoop.md b/docs/rules/EmptyStatementNotInLoop.md deleted file mode 100644 index 856200dd..00000000 --- a/docs/rules/EmptyStatementNotInLoop.md +++ /dev/null @@ -1,8 +0,0 @@ -# EmptyStatementNotInLoop -**Category:** `pmd`
-**Rule Key:** `pmd:EmptyStatementNotInLoop`
-> :warning: This rule is **deprecated** in favour of `squid:EmptyStatementUsageCheck`. - ------ - -An empty statement (aka a semicolon by itself) that is not used as the sole body of a for loop or while loop is probably a bug. It could also be a double semicolon, which is useless and should be removed. diff --git a/docs/rules/EmptyStaticInitializer.md b/docs/rules/EmptyStaticInitializer.md deleted file mode 100644 index f59cdef5..00000000 --- a/docs/rules/EmptyStaticInitializer.md +++ /dev/null @@ -1,8 +0,0 @@ -# EmptyStaticInitializer -**Category:** `pmd`
-**Rule Key:** `pmd:EmptyStaticInitializer`
-> :warning: This rule is **deprecated** in favour of [S00108](https://rules.sonarsource.com/java/RSPEC-108). - ------ - -An empty static initializer was found. diff --git a/docs/rules/EmptySwitchStatements.md b/docs/rules/EmptySwitchStatements.md deleted file mode 100644 index db2743cc..00000000 --- a/docs/rules/EmptySwitchStatements.md +++ /dev/null @@ -1,8 +0,0 @@ -# EmptySwitchStatements -**Category:** `pmd`
-**Rule Key:** `pmd:EmptySwitchStatements`
-> :warning: This rule is **deprecated** in favour of [S00108](https://rules.sonarsource.com/java/RSPEC-108). - ------ - -Avoid empty switch statements. diff --git a/docs/rules/EmptySynchronizedBlock.md b/docs/rules/EmptySynchronizedBlock.md deleted file mode 100644 index 213e03c7..00000000 --- a/docs/rules/EmptySynchronizedBlock.md +++ /dev/null @@ -1,8 +0,0 @@ -# EmptySynchronizedBlock -**Category:** `pmd`
-**Rule Key:** `pmd:EmptySynchronizedBlock`
-> :warning: This rule is **deprecated** in favour of [S00108](https://rules.sonarsource.com/java/RSPEC-108). - ------ - -Avoid empty synchronized blocks - they're useless. diff --git a/docs/rules/EmptyTryBlock.md b/docs/rules/EmptyTryBlock.md deleted file mode 100644 index 8e8edee1..00000000 --- a/docs/rules/EmptyTryBlock.md +++ /dev/null @@ -1,8 +0,0 @@ -# EmptyTryBlock -**Category:** `pmd`
-**Rule Key:** `pmd:EmptyTryBlock`
-> :warning: This rule is **deprecated** in favour of [S00108](https://rules.sonarsource.com/java/RSPEC-108). - ------ - -Avoid empty try blocks - what's the point? diff --git a/docs/rules/EmptyWhileStmt.md b/docs/rules/EmptyWhileStmt.md deleted file mode 100644 index a6b5b517..00000000 --- a/docs/rules/EmptyWhileStmt.md +++ /dev/null @@ -1,8 +0,0 @@ -# EmptyWhileStmt -**Category:** `pmd`
-**Rule Key:** `pmd:EmptyWhileStmt`
-> :warning: This rule is **deprecated** in favour of [S00108](https://rules.sonarsource.com/java/RSPEC-108). - ------ - -Empty While Statement finds all instances where a while statement does nothing. If it is a timing loop, then you should use Thread.sleep() for it; if it's a while loop that does a lot in the exit expression, rewrite it to make it clearer. diff --git a/docs/rules/EqualsNull.md b/docs/rules/EqualsNull.md deleted file mode 100644 index 212f52b8..00000000 --- a/docs/rules/EqualsNull.md +++ /dev/null @@ -1,8 +0,0 @@ -# EqualsNull -**Category:** `pmd`
-**Rule Key:** `pmd:EqualsNull`
-> :warning: This rule is **deprecated** in favour of [S2159](https://rules.sonarsource.com/java/RSPEC-2159). - ------ - -Inexperienced programmers sometimes confuse comparison concepts and use equals() to compare to null. diff --git a/docs/rules/ExceptionAsFlowControl.md b/docs/rules/ExceptionAsFlowControl.md deleted file mode 100644 index 1306ea13..00000000 --- a/docs/rules/ExceptionAsFlowControl.md +++ /dev/null @@ -1,8 +0,0 @@ -# ExceptionAsFlowControl -**Category:** `pmd`
-**Rule Key:** `pmd:ExceptionAsFlowControl`
-> :warning: This rule is **deprecated** in favour of [S1141](https://rules.sonarsource.com/java/RSPEC-1141). - ------ - -Using Exceptions as flow control leads to GOTOish code and obscures true exceptions when debugging. diff --git a/docs/rules/ExcessiveClassLength.md b/docs/rules/ExcessiveClassLength.md deleted file mode 100644 index 4b971ee2..00000000 --- a/docs/rules/ExcessiveClassLength.md +++ /dev/null @@ -1,8 +0,0 @@ -# ExcessiveClassLength -**Category:** `pmd`
-**Rule Key:** `pmd:ExcessiveClassLength`
-> :warning: This rule is **deprecated** in favour of [S1448](https://rules.sonarsource.com/java/RSPEC-1448). - ------ - -Long Class files are indications that the class may be trying to do too much. Try to break it down, and reduce the size to something manageable. diff --git a/docs/rules/ExcessiveImports.md b/docs/rules/ExcessiveImports.md deleted file mode 100644 index 91956dec..00000000 --- a/docs/rules/ExcessiveImports.md +++ /dev/null @@ -1,8 +0,0 @@ -# ExcessiveImports -**Category:** `pmd`
-**Rule Key:** `pmd:ExcessiveImports`
-> :warning: This rule is **deprecated** in favour of [S1200](https://rules.sonarsource.com/java/RSPEC-1200). - ------ - -A high number of imports can indicate a high degree of coupling within an object. Rule counts the number of unique imports and reports a violation if the count is above the user defined threshold. diff --git a/docs/rules/ExcessiveMethodLength.md b/docs/rules/ExcessiveMethodLength.md deleted file mode 100644 index 979707c7..00000000 --- a/docs/rules/ExcessiveMethodLength.md +++ /dev/null @@ -1,8 +0,0 @@ -# ExcessiveMethodLength -**Category:** `pmd`
-**Rule Key:** `pmd:ExcessiveMethodLength`
-> :warning: This rule is **deprecated** in favour of [S138](https://rules.sonarsource.com/java/RSPEC-138). - ------ - -Violations of this rule usually indicate that the method is doing too much. Try to reduce the method size by creating helper methods and removing any copy/pasted code. diff --git a/docs/rules/ExcessiveParameterList.md b/docs/rules/ExcessiveParameterList.md deleted file mode 100644 index 7ac29cc5..00000000 --- a/docs/rules/ExcessiveParameterList.md +++ /dev/null @@ -1,11 +0,0 @@ -# ExcessiveParameterList -**Category:** `pmd`
-**Rule Key:** `pmd:ExcessiveParameterList`
-> :warning: This rule is **deprecated** in favour of [S00107](https://rules.sonarsource.com/java/RSPEC-107). - ------ - -

- Long parameter lists can indicate that a new object should be created to wrap the numerous parameters. Basically, try - to group the parameters together. -

diff --git a/docs/rules/ExcessivePublicCount.md b/docs/rules/ExcessivePublicCount.md deleted file mode 100644 index ac081423..00000000 --- a/docs/rules/ExcessivePublicCount.md +++ /dev/null @@ -1,8 +0,0 @@ -# ExcessivePublicCount -**Category:** `pmd`
-**Rule Key:** `pmd:ExcessivePublicCount`
-> :warning: This rule is **deprecated** in favour of [S1448](https://rules.sonarsource.com/java/RSPEC-1448). - ------ - -A large number of public methods and attributes declared in a class can indicate the class may need to be broken up as increased effort will be required to thoroughly test it. diff --git a/docs/rules/ExtendsObject.md b/docs/rules/ExtendsObject.md deleted file mode 100644 index 5ab0b143..00000000 --- a/docs/rules/ExtendsObject.md +++ /dev/null @@ -1,12 +0,0 @@ -# ExtendsObject -**Category:** `pmd`
-**Rule Key:** `pmd:ExtendsObject`
-> :warning: This rule is **deprecated** in favour of [S1939](https://rules.sonarsource.com/java/RSPEC-1939). - ------ - -No need to explicitly extend Object. Example: -
-public class Foo extends Object { // not required
-}
-
diff --git a/docs/rules/FieldDeclarationsShouldBeAtStartOfClass.md b/docs/rules/FieldDeclarationsShouldBeAtStartOfClass.md deleted file mode 100644 index 3a5c0bdb..00000000 --- a/docs/rules/FieldDeclarationsShouldBeAtStartOfClass.md +++ /dev/null @@ -1,22 +0,0 @@ -# FieldDeclarationsShouldBeAtStartOfClass -**Category:** `pmd`
-**Rule Key:** `pmd:FieldDeclarationsShouldBeAtStartOfClass`
-> :warning: This rule is **deprecated** in favour of [S1213](https://rules.sonarsource.com/java/RSPEC-1213). - ------ - -Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes. Example: -
-public class HelloWorldBean {
-
-  // Field declared before methods / inner classes - OK
-  private String _thing;
-
-  public String getMessage() {
-    return "Hello World!";
-  }
-
-  // Field declared after methods / inner classes - avoid this
-  private String _fieldInWrongLocation;
-}
-
diff --git a/docs/rules/FinalFieldCouldBeStatic.md b/docs/rules/FinalFieldCouldBeStatic.md deleted file mode 100644 index 75af7276..00000000 --- a/docs/rules/FinalFieldCouldBeStatic.md +++ /dev/null @@ -1,8 +0,0 @@ -# FinalFieldCouldBeStatic -**Category:** `pmd`
-**Rule Key:** `pmd:FinalFieldCouldBeStatic`
-> :warning: This rule is **deprecated** in favour of [S1170](https://rules.sonarsource.com/java/RSPEC-1170). - ------ - -If a final field is assigned to a compile-time constant, it could be made static, thus saving overhead in each object at runtime. diff --git a/docs/rules/FinalizeDoesNotCallSuperFinalize.md b/docs/rules/FinalizeDoesNotCallSuperFinalize.md deleted file mode 100644 index e3c6bcb6..00000000 --- a/docs/rules/FinalizeDoesNotCallSuperFinalize.md +++ /dev/null @@ -1,8 +0,0 @@ -# FinalizeDoesNotCallSuperFinalize -**Category:** `pmd`
-**Rule Key:** `pmd:FinalizeDoesNotCallSuperFinalize`
-> :warning: This rule is **deprecated** in favour of `squid:ObjectFinalizeOverridenCallsSuperFinalizeCheck`. - ------ - -If the finalize() is implemented, its last action should be to call super.finalize. diff --git a/docs/rules/FinalizeOnlyCallsSuperFinalize.md b/docs/rules/FinalizeOnlyCallsSuperFinalize.md deleted file mode 100644 index cba91cbc..00000000 --- a/docs/rules/FinalizeOnlyCallsSuperFinalize.md +++ /dev/null @@ -1,8 +0,0 @@ -# FinalizeOnlyCallsSuperFinalize -**Category:** `pmd`
-**Rule Key:** `pmd:FinalizeOnlyCallsSuperFinalize`
-> :warning: This rule is **deprecated** in favour of [S1185](https://rules.sonarsource.com/java/RSPEC-1185). - ------ - -If the finalize() is implemented, it should do something besides just calling super.finalize(). diff --git a/docs/rules/FinalizeOverloaded.md b/docs/rules/FinalizeOverloaded.md deleted file mode 100644 index 511b9b19..00000000 --- a/docs/rules/FinalizeOverloaded.md +++ /dev/null @@ -1,8 +0,0 @@ -# FinalizeOverloaded -**Category:** `pmd`
-**Rule Key:** `pmd:FinalizeOverloaded`
-> :warning: This rule is **deprecated** in favour of [S1175](https://rules.sonarsource.com/java/RSPEC-1175). - ------ - -Methods named finalize() should not have parameters. It is confusing and probably a bug to overload finalize(). It will not be called by the VM. diff --git a/docs/rules/FinalizeShouldBeProtected.md b/docs/rules/FinalizeShouldBeProtected.md deleted file mode 100644 index fbf546e7..00000000 --- a/docs/rules/FinalizeShouldBeProtected.md +++ /dev/null @@ -1,8 +0,0 @@ -# FinalizeShouldBeProtected -**Category:** `pmd`
-**Rule Key:** `pmd:FinalizeShouldBeProtected`
-> :warning: This rule is **deprecated** in favour of [S1174](https://rules.sonarsource.com/java/RSPEC-1174). - ------ - -If you override finalize(), make it protected. If you make it public, other classes may call it. diff --git a/docs/rules/ForLoopShouldBeWhileLoop.md b/docs/rules/ForLoopShouldBeWhileLoop.md deleted file mode 100644 index 22f339a5..00000000 --- a/docs/rules/ForLoopShouldBeWhileLoop.md +++ /dev/null @@ -1,8 +0,0 @@ -# ForLoopShouldBeWhileLoop -**Category:** `pmd`
-**Rule Key:** `pmd:ForLoopShouldBeWhileLoop`
-> :warning: This rule is **deprecated** in favour of [S1264](https://rules.sonarsource.com/java/RSPEC-1264). - ------ - -Some for loops can be simplified to while loops - this makes them more concise. diff --git a/docs/rules/ForLoopsMustUseBraces.md b/docs/rules/ForLoopsMustUseBraces.md deleted file mode 100644 index bedecff3..00000000 --- a/docs/rules/ForLoopsMustUseBraces.md +++ /dev/null @@ -1,10 +0,0 @@ -# ForLoopsMustUseBraces -**Category:** `pmd`
-**Rule Key:** `pmd:ForLoopsMustUseBraces`
-> :warning: This rule is **deprecated** in favour of [S00121](https://rules.sonarsource.com/java/RSPEC-121). - ------ - -

- Avoid using 'for' statements without using curly braces, like for (int i=0; i<42;i++) foo(); -

diff --git a/docs/rules/GenericsNaming.md b/docs/rules/GenericsNaming.md deleted file mode 100644 index 6f0718ff..00000000 --- a/docs/rules/GenericsNaming.md +++ /dev/null @@ -1,8 +0,0 @@ -# GenericsNaming -**Category:** `pmd`
-**Rule Key:** `pmd:GenericsNaming`
-> :warning: This rule is **deprecated** in favour of [S00119](https://rules.sonarsource.com/java/RSPEC-119). - ------ - -Generics names should be a one letter long and upper case. diff --git a/docs/rules/GodClass.md b/docs/rules/GodClass.md deleted file mode 100644 index a68af8f2..00000000 --- a/docs/rules/GodClass.md +++ /dev/null @@ -1,14 +0,0 @@ -# GodClass -**Category:** `pmd`
-**Rule Key:** `pmd:GodClass`
- - ------ - -The God Class rule detects the God Class design flaw using metrics. God classes do too many things, -are very big and overly complex. They should be split apart to be more object-oriented. -The rule uses the detection strategy described in "Object-Oriented Metrics in Practice". -The violations are reported against the entire class. See also the references: -Michele Lanza and Radu Marinescu. Object-Oriented Metrics in Practice: -Using Software Metrics to Characterize, Evaluate, and Improve the Design -of Object-Oriented Systems. Springer, Berlin, 1 edition, October 2006. Page 80. diff --git a/docs/rules/GuardDebugLogging.md b/docs/rules/GuardDebugLogging.md deleted file mode 100644 index 1a345af2..00000000 --- a/docs/rules/GuardDebugLogging.md +++ /dev/null @@ -1,8 +0,0 @@ -# GuardDebugLogging -**Category:** `pmd`
-**Rule Key:** `pmd:GuardDebugLogging`
- - ------ - -When log messages are composed by concatenating strings, the whole section should be guarded by a isDebugEnabled() check to avoid performance and memory issues. diff --git a/docs/rules/GuardLogStatement.md b/docs/rules/GuardLogStatement.md deleted file mode 100644 index 23859d67..00000000 --- a/docs/rules/GuardLogStatement.md +++ /dev/null @@ -1,14 +0,0 @@ -# GuardLogStatement -**Category:** `pmd`
-**Rule Key:** `pmd:GuardLogStatement`
- - ------ - -Whenever using a log level, one should check if the loglevel is actually enabled, or -otherwise skip the associate String creation and manipulation. Example: -
-// Add this for performance
-if (log.isDebugEnabled() { ...
-  log.debug("This happens");
-
diff --git a/docs/rules/GuardLogStatementJavaUtil.md b/docs/rules/GuardLogStatementJavaUtil.md deleted file mode 100644 index 76c2f87a..00000000 --- a/docs/rules/GuardLogStatementJavaUtil.md +++ /dev/null @@ -1,14 +0,0 @@ -# GuardLogStatementJavaUtil -**Category:** `pmd`
-**Rule Key:** `pmd:GuardLogStatementJavaUtil`
- - ------ - -Whenever using a log level, one should check if the loglevel is actually enabled, or -otherwise skip the associate String creation and manipulation. Example: -
-// Add this for performance
-if (log.isLoggable(Level.FINE)) { ...
-  log.fine("This happens");
-
diff --git a/docs/rules/IdempotentOperations.md b/docs/rules/IdempotentOperations.md deleted file mode 100644 index 0fd1ec32..00000000 --- a/docs/rules/IdempotentOperations.md +++ /dev/null @@ -1,8 +0,0 @@ -# IdempotentOperations -**Category:** `pmd`
-**Rule Key:** `pmd:IdempotentOperations`
-> :warning: This rule is **deprecated** in favour of [S1656](https://rules.sonarsource.com/java/RSPEC-1656). - ------ - -Avoid idempotent operations - they are have no effect. Example :
int x = 2;
x = x;
diff --git a/docs/rules/IfElseStmtsMustUseBraces.md b/docs/rules/IfElseStmtsMustUseBraces.md deleted file mode 100644 index 6601cd73..00000000 --- a/docs/rules/IfElseStmtsMustUseBraces.md +++ /dev/null @@ -1,10 +0,0 @@ -# IfElseStmtsMustUseBraces -**Category:** `pmd`
-**Rule Key:** `pmd:IfElseStmtsMustUseBraces`
-> :warning: This rule is **deprecated** in favour of [S00121](https://rules.sonarsource.com/java/RSPEC-121). - ------ - -

- Avoid using if..else statements without using curly braces. -

diff --git a/docs/rules/IfStmtsMustUseBraces.md b/docs/rules/IfStmtsMustUseBraces.md deleted file mode 100644 index 228d06ea..00000000 --- a/docs/rules/IfStmtsMustUseBraces.md +++ /dev/null @@ -1,10 +0,0 @@ -# IfStmtsMustUseBraces -**Category:** `pmd`
-**Rule Key:** `pmd:IfStmtsMustUseBraces`
-> :warning: This rule is **deprecated** in favour of [S00121](https://rules.sonarsource.com/java/RSPEC-121). - ------ - -

- Avoid using if statements without using curly braces. -

diff --git a/docs/rules/ImmutableField.md b/docs/rules/ImmutableField.md deleted file mode 100644 index 978a2774..00000000 --- a/docs/rules/ImmutableField.md +++ /dev/null @@ -1,8 +0,0 @@ -# ImmutableField -**Category:** `pmd`
-**Rule Key:** `pmd:ImmutableField`
- - ------ - -Identifies private fields whose values never change once they are initialized either in the declaration of the field or by a constructor. This aids in converting existing classes to immutable classes. diff --git a/docs/rules/ImportFromSamePackage.md b/docs/rules/ImportFromSamePackage.md deleted file mode 100644 index ebe2ac8f..00000000 --- a/docs/rules/ImportFromSamePackage.md +++ /dev/null @@ -1,8 +0,0 @@ -# ImportFromSamePackage -**Category:** `pmd`
-**Rule Key:** `pmd:ImportFromSamePackage`
-> :warning: This rule is **deprecated** in favour of `squid:UselessImportCheck`. - ------ - -No need to import a type that lives in the same package. diff --git a/docs/rules/InefficientEmptyStringCheck.md b/docs/rules/InefficientEmptyStringCheck.md deleted file mode 100644 index e1af7eb9..00000000 --- a/docs/rules/InefficientEmptyStringCheck.md +++ /dev/null @@ -1,8 +0,0 @@ -# InefficientEmptyStringCheck -**Category:** `pmd`
-**Rule Key:** `pmd:InefficientEmptyStringCheck`
- - ------ - -String.trim().length() is an inefficient way to check if a String is really empty, as it creates a new String object just to check its size. Consider creating a static function that loops through a string, checking Character.isWhitespace() on each character and returning false if a non-whitespace character is found. diff --git a/docs/rules/InefficientStringBuffering.md b/docs/rules/InefficientStringBuffering.md deleted file mode 100644 index 60d9dbcc..00000000 --- a/docs/rules/InefficientStringBuffering.md +++ /dev/null @@ -1,8 +0,0 @@ -# InefficientStringBuffering -**Category:** `pmd`
-**Rule Key:** `pmd:InefficientStringBuffering`
- - ------ - -Avoid concatenating non literals in a StringBuffer constructor or append(). diff --git a/docs/rules/InstantiationToGetClass.md b/docs/rules/InstantiationToGetClass.md deleted file mode 100644 index e8370bf0..00000000 --- a/docs/rules/InstantiationToGetClass.md +++ /dev/null @@ -1,9 +0,0 @@ -# InstantiationToGetClass -**Category:** `pmd`
-**Rule Key:** `pmd:InstantiationToGetClass`
-> :warning: This rule is **deprecated** in favour of [S2133](https://rules.sonarsource.com/java/RSPEC-2133). - ------ - -Avoid instantiating an object just to call getClass() on it; use the .class public member instead. Example : replace -Class c = new String().getClass(); with Class c = String.class; diff --git a/docs/rules/InsufficientStringBufferDeclaration.md b/docs/rules/InsufficientStringBufferDeclaration.md deleted file mode 100644 index e82e416a..00000000 --- a/docs/rules/InsufficientStringBufferDeclaration.md +++ /dev/null @@ -1,8 +0,0 @@ -# InsufficientStringBufferDeclaration -**Category:** `pmd`
-**Rule Key:** `pmd:InsufficientStringBufferDeclaration`
- - ------ - -Failing to pre-size a StringBuffer properly could cause it to re-size many times during runtime. This rule checks the characters that are actually passed into StringBuffer.append(), but represents a best guess worst case scenario. An empty StringBuffer constructor initializes the object to 16 characters. This default is assumed if the length of the constructor can not be determined. diff --git a/docs/rules/IntegerInstantiation.md b/docs/rules/IntegerInstantiation.md deleted file mode 100644 index a3e46720..00000000 --- a/docs/rules/IntegerInstantiation.md +++ /dev/null @@ -1,8 +0,0 @@ -# IntegerInstantiation -**Category:** `pmd`
-**Rule Key:** `pmd:IntegerInstantiation`
- - ------ - -In JDK 1.5, calling new Integer() causes memory allocation. Integer.valueOf() is more memory friendly. diff --git a/docs/rules/JUnit4SuitesShouldUseSuiteAnnotation.md b/docs/rules/JUnit4SuitesShouldUseSuiteAnnotation.md deleted file mode 100644 index 299fece8..00000000 --- a/docs/rules/JUnit4SuitesShouldUseSuiteAnnotation.md +++ /dev/null @@ -1,22 +0,0 @@ -# JUnit4SuitesShouldUseSuiteAnnotation -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:JUnit4SuitesShouldUseSuiteAnnotation`
- - ------ - -In JUnit 3, test suites are indicated by the suite() method. In JUnit 4, suites are indicated -through the @RunWith(Suite.class) annotation. Example: -
-public class BadExample extends TestCase{
-
-    public static Test suite(){
-    	return new Suite();
-    }
-}
-
-@RunWith(Suite.class)
-@SuiteClasses( { TestOne.class, TestTwo.class })
-public class GoodTest {
-}
-
diff --git a/docs/rules/JUnit4TestShouldUseAfterAnnotation.md b/docs/rules/JUnit4TestShouldUseAfterAnnotation.md deleted file mode 100644 index b91ef788..00000000 --- a/docs/rules/JUnit4TestShouldUseAfterAnnotation.md +++ /dev/null @@ -1,21 +0,0 @@ -# JUnit4TestShouldUseAfterAnnotation -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:JUnit4TestShouldUseAfterAnnotation`
- - ------ - -In JUnit 3, the tearDown method was used to clean up all data entities required in running tests. -JUnit 4 skips the tearDown method and executes all methods annotated with @After after running each test Example: -
-public class MyTest {
-    public void tearDown() {
-        bad();
-    }
-}
-public class MyTest2 {
-    @After public void tearDown() {
-        good();
-    }
-}
-
diff --git a/docs/rules/JUnit4TestShouldUseBeforeAnnotation.md b/docs/rules/JUnit4TestShouldUseBeforeAnnotation.md deleted file mode 100644 index ab8409c0..00000000 --- a/docs/rules/JUnit4TestShouldUseBeforeAnnotation.md +++ /dev/null @@ -1,21 +0,0 @@ -# JUnit4TestShouldUseBeforeAnnotation -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:JUnit4TestShouldUseBeforeAnnotation`
- - ------ - -In JUnit 3, the setUp method was used to set up all data entities required in running tests. -JUnit 4 skips the setUp method and executes all methods annotated with @Before before all tests Example: -
-public class MyTest {
-    public void setUp() {
-        bad();
-    }
-}
-public class MyTest2 {
-    @Before public void setUp() {
-        good();
-    }
-}
-
diff --git a/docs/rules/JUnit4TestShouldUseTestAnnotation.md b/docs/rules/JUnit4TestShouldUseTestAnnotation.md deleted file mode 100644 index 87f04700..00000000 --- a/docs/rules/JUnit4TestShouldUseTestAnnotation.md +++ /dev/null @@ -1,21 +0,0 @@ -# JUnit4TestShouldUseTestAnnotation -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:JUnit4TestShouldUseTestAnnotation`
- - ------ - -In JUnit 3, the framework executed all methods which started with the word test as a unit test. -In JUnit 4, only methods annotated with the @Test annotation are executed. Example: -
-public class MyTest {
-    public void testBad() {
-        doSomething();
-    }
-
-	@Test
-    public void testGood() {
-        doSomething();
-    }
-}
-
diff --git a/docs/rules/JUnitAssertionsShouldIncludeMessage.md b/docs/rules/JUnitAssertionsShouldIncludeMessage.md deleted file mode 100644 index c1cdd0cf..00000000 --- a/docs/rules/JUnitAssertionsShouldIncludeMessage.md +++ /dev/null @@ -1,15 +0,0 @@ -# JUnitAssertionsShouldIncludeMessage -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:JUnitAssertionsShouldIncludeMessage`
-> :warning: This rule is **deprecated** in favour of [S2698](https://rules.sonarsource.com/java/RSPEC-2698). - ------ - -JUnit assertions should include a message - i.e., use the three argument version of assertEquals(), not the two argument version. -
-public class Foo extends TestCase {
-  public void testSomething() {
-    assertEquals("foo", "bar"); // violation, should be assertEquals("Foo does not equals bar", "foo", "bar");
-  }
-}
-
diff --git a/docs/rules/JUnitSpelling.md b/docs/rules/JUnitSpelling.md deleted file mode 100644 index 65f330f5..00000000 --- a/docs/rules/JUnitSpelling.md +++ /dev/null @@ -1,16 +0,0 @@ -# JUnitSpelling -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:JUnitSpelling`
- - ------ - -Some JUnit framework methods are easy to misspell. -
-import junit.framework.*;
-
-public class Foo extends TestCase {
-  public void setup() {} // violation, should be setUp()
-  public void TearDown() {} // violation, should be tearDown()
-}
-
diff --git a/docs/rules/JUnitStaticSuite.md b/docs/rules/JUnitStaticSuite.md deleted file mode 100644 index b0d3640d..00000000 --- a/docs/rules/JUnitStaticSuite.md +++ /dev/null @@ -1,16 +0,0 @@ -# JUnitStaticSuite -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:JUnitStaticSuite`
- - ------ - -The suite() method in a JUnit test needs to be both public and static. -
-import junit.framework.*;
-
-public class Foo extends TestCase {
-  public void suite() {} // violation, should be static
-  private static void suite() {} // violation, should be public
-}
-
diff --git a/docs/rules/JUnitTestContainsTooManyAsserts.md b/docs/rules/JUnitTestContainsTooManyAsserts.md deleted file mode 100644 index 00dee06f..00000000 --- a/docs/rules/JUnitTestContainsTooManyAsserts.md +++ /dev/null @@ -1,26 +0,0 @@ -# JUnitTestContainsTooManyAsserts -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:JUnitTestContainsTooManyAsserts`
- - ------ - -JUnit tests should not contain too many asserts. Many asserts are indicative of a complex test, for which -it is harder to verify correctness. Consider breaking the test scenario into multiple, shorter test scenarios. -Customize the maximum number of assertions used by this Rule to suit your needs. Example: -
-public class MyTestCase extends TestCase {
-	// Ok
-	public void testMyCaseWithOneAssert() {
-		boolean myVar = false;		
-		assertFalse("should be false", myVar);
-	}
-
-	// Bad, too many asserts (assuming max=1)
-	public void testMyCaseWithMoreAsserts() {
-		boolean myVar = false;		
-		assertFalse("myVar should be false", myVar);
-		assertEquals("should equals false", false, myVar);
-	}
-}
-
diff --git a/docs/rules/JUnitTestsShouldIncludeAssert.md b/docs/rules/JUnitTestsShouldIncludeAssert.md deleted file mode 100644 index e6e5c223..00000000 --- a/docs/rules/JUnitTestsShouldIncludeAssert.md +++ /dev/null @@ -1,17 +0,0 @@ -# JUnitTestsShouldIncludeAssert -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:JUnitTestsShouldIncludeAssert`
- - ------ - -JUnit tests should include at least one assertion. This makes the tests more robust, and using assert with messages provide the developer a clearer idea of what the test does. -
-public class Foo extends TestCase {
-  public void testSomething() {
-    Bar b = findBar();
-    b.work();
-    // violation, we could use assertNotNull("bar not found", b);
-  }
-}
-
diff --git a/docs/rules/JUnitUseExpected.md b/docs/rules/JUnitUseExpected.md deleted file mode 100644 index 0117f897..00000000 --- a/docs/rules/JUnitUseExpected.md +++ /dev/null @@ -1,25 +0,0 @@ -# JUnitUseExpected -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:JUnitUseExpected`
- - ------ - -In JUnit4, use the @Test(expected) annotation to denote tests that should throw exceptions. Example: -
-public class MyTest {
-	@Test
-    public void testBad() {
-        try {
-            doSomething();
-            fail("should have thrown an exception");
-        } catch (Exception e) {
-        }
-    }
-
-	@Test(expected=Exception.class)
-    public void testGood() {
-        doSomething();
-    }
-}
-
diff --git a/docs/rules/JumbledIncrementer.md b/docs/rules/JumbledIncrementer.md deleted file mode 100644 index 23608eaa..00000000 --- a/docs/rules/JumbledIncrementer.md +++ /dev/null @@ -1,19 +0,0 @@ -# JumbledIncrementer -**Category:** `pmd`
-**Rule Key:** `pmd:JumbledIncrementer`
-> :warning: This rule is **deprecated** in favour of `squid:ForLoopCounterChangedCheck`. - ------ - -Avoid jumbled loop incrementers - it's usually a mistake, and it's confusing even if it's what's intended. -
Example : -
-public class JumbledIncrementerRule1 {
-  public void foo() {
-   for (int i = 0; i < 10; i++) {
-    for (int k = 0; k < 20; i++) {
-     System.out.println("Hello");
-    }
-   }
-  }
-}
diff --git a/docs/rules/LawOfDemeter.md b/docs/rules/LawOfDemeter.md deleted file mode 100644 index 479cca5b..00000000 --- a/docs/rules/LawOfDemeter.md +++ /dev/null @@ -1,37 +0,0 @@ -# LawOfDemeter -**Category:** `pmd`
-**Rule Key:** `pmd:LawOfDemeter`
- - ------ - -The Law of Demeter is a simple rule, that says "only talk to friends". It helps to reduce coupling between classes or objects. -See also the references: -Andrew Hunt, David Thomas, and Ward Cunningham. The Pragmatic Programmer. From Journeyman to Master. Addison-Wesley Longman, Amsterdam, October 1999.; -K.J. Lieberherr and I.M. Holland. Assuring good style for object-oriented programs. Software, IEEE, 6(5):38–48, 1989.; -http://www.ccs.neu.edu/home/lieber/LoD.html; -http://en.wikipedia.org/wiki/Law_of_Demeter -

Example:

-
-public class Foo {
-    /**
-     * This example will result in two violations.
-     */
-    public void example(Bar b) {
-        // this method call is ok, as b is a parameter of "example"
-        C c = b.getC();
-        
-        // this method call is a violation, as we are using c, which we got from B.
-        // We should ask b directly instead, e.g. "b.doItOnC();"
-        c.doIt();
-        
-        // this is also a violation, just expressed differently as a method chain without temporary variables.
-        b.getC().doIt();
-        
-        // a constructor call, not a method call.
-        D d = new D();
-        // this method call is ok, because we have create the new instance of D locally.
-        d.doSomethingElse(); 
-    }
-}
-
diff --git a/docs/rules/LocalHomeNamingConvention.md b/docs/rules/LocalHomeNamingConvention.md deleted file mode 100644 index 87b0fe65..00000000 --- a/docs/rules/LocalHomeNamingConvention.md +++ /dev/null @@ -1,8 +0,0 @@ -# LocalHomeNamingConvention -**Category:** `pmd`
-**Rule Key:** `pmd:LocalHomeNamingConvention`
- - ------ - -The Local Home interface of a Session EJB should be suffixed by "LocalHome". diff --git a/docs/rules/LocalInterfaceSessionNamingConvention.md b/docs/rules/LocalInterfaceSessionNamingConvention.md deleted file mode 100644 index f156dd5e..00000000 --- a/docs/rules/LocalInterfaceSessionNamingConvention.md +++ /dev/null @@ -1,8 +0,0 @@ -# LocalInterfaceSessionNamingConvention -**Category:** `pmd`
-**Rule Key:** `pmd:LocalInterfaceSessionNamingConvention`
- - ------ - -The Local Interface of a Session EJB should be suffixed by "Local". diff --git a/docs/rules/LocalVariableCouldBeFinal.md b/docs/rules/LocalVariableCouldBeFinal.md deleted file mode 100644 index 7cffcb76..00000000 --- a/docs/rules/LocalVariableCouldBeFinal.md +++ /dev/null @@ -1,16 +0,0 @@ -# LocalVariableCouldBeFinal -**Category:** `pmd`
-**Rule Key:** `pmd:LocalVariableCouldBeFinal`
- - ------ - -A local variable assigned only once can be declared final. Example : -
-public class Bar {
- public void foo () {
-  String a = "a"; //if a will not be assigned again it is better to do this:
-  final String b = "b";
- }
-}
-  
diff --git a/docs/rules/LoggerIsNotStaticFinal.md b/docs/rules/LoggerIsNotStaticFinal.md deleted file mode 100644 index 3862ca6c..00000000 --- a/docs/rules/LoggerIsNotStaticFinal.md +++ /dev/null @@ -1,8 +0,0 @@ -# LoggerIsNotStaticFinal -**Category:** `pmd`
-**Rule Key:** `pmd:LoggerIsNotStaticFinal`
-> :warning: This rule is **deprecated** in favour of [S1312](https://rules.sonarsource.com/java/RSPEC-1312). - ------ - -In most cases, the Logger can be declared static and final. diff --git a/docs/rules/LogicInversion.md b/docs/rules/LogicInversion.md deleted file mode 100644 index 5139c034..00000000 --- a/docs/rules/LogicInversion.md +++ /dev/null @@ -1,20 +0,0 @@ -# LogicInversion -**Category:** `pmd`
-**Rule Key:** `pmd:LogicInversion`
-> :warning: This rule is **deprecated** in favour of [S1940](https://rules.sonarsource.com/java/RSPEC-1940). - ------ - -Use opposite operator instead of negating the whole expression with a logic complement operator. Example: -
-public boolean bar(int a, int b) {
-
-  if (!(a == b)) // use !=
-    return false;
-
-  if (!(a < b)) // use >=
-    return false;
-
-  return true;
-}
-
diff --git a/docs/rules/LongInstantiation.md b/docs/rules/LongInstantiation.md deleted file mode 100644 index 91cb0abc..00000000 --- a/docs/rules/LongInstantiation.md +++ /dev/null @@ -1,14 +0,0 @@ -# LongInstantiation -**Category:** `pmd`
-**Rule Key:** `pmd:LongInstantiation`
- - ------ - -In JDK 1.5, calling new Long() causes memory allocation. Long.valueOf() is more memory friendly. Example : -
-public class Foo {
-private Long i = new Long(0); // change to Long i =
-Long.valueOf(0);
-}
-  
diff --git a/docs/rules/LongVariable.md b/docs/rules/LongVariable.md deleted file mode 100644 index 0e9cb34b..00000000 --- a/docs/rules/LongVariable.md +++ /dev/null @@ -1,8 +0,0 @@ -# LongVariable -**Category:** `pmd`
-**Rule Key:** `pmd:LongVariable`
-> :warning: This rule is **deprecated** in favour of [S00117](https://rules.sonarsource.com/java/RSPEC-117). - ------ - -Detects when a field, formal or local variable is declared with a long name. diff --git a/docs/rules/LooseCoupling.md b/docs/rules/LooseCoupling.md deleted file mode 100644 index dac50e36..00000000 --- a/docs/rules/LooseCoupling.md +++ /dev/null @@ -1,8 +0,0 @@ -# LooseCoupling -**Category:** `pmd`
-**Rule Key:** `pmd:LooseCoupling`
-> :warning: This rule is **deprecated** in favour of [S1319](https://rules.sonarsource.com/java/RSPEC-1319). - ------ - -Avoid using implementation types (i.e., HashSet); use the interface (i.e, Set) instead diff --git a/docs/rules/LooseCouplingWithTypeResolution.md b/docs/rules/LooseCouplingWithTypeResolution.md deleted file mode 100644 index adad9ed1..00000000 --- a/docs/rules/LooseCouplingWithTypeResolution.md +++ /dev/null @@ -1,23 +0,0 @@ -# LooseCouplingWithTypeResolution -**Category:** `pmd`
-**Rule Key:** `pmd:LooseCouplingWithTypeResolution`
-> :warning: This rule is **deprecated** in favour of [S1319](https://rules.sonarsource.com/java/RSPEC-1319). - ------ - -Avoid using implementation types (i.e., HashSet); use the interface (i.e, Set) instead Example: -
-import java.util.ArrayList;
-import java.util.HashSet;
-
-public class Bar {
-
-  // Use List instead
-  private ArrayList list = new ArrayList();
-
-  // Use Set instead
-  public HashSet getFoo() {
-    return new HashSet();
-  }
-}
-
diff --git a/docs/rules/LoosePackageCoupling.md b/docs/rules/LoosePackageCoupling.md deleted file mode 100644 index bcc596d1..00000000 --- a/docs/rules/LoosePackageCoupling.md +++ /dev/null @@ -1,18 +0,0 @@ -# LoosePackageCoupling -**Category:** `pmd`
-**Rule Key:** `pmd:LoosePackageCoupling`
-> :warning: This rule is **deprecated** in favour of `squid:ArchitecturalConstraint`. - ------ - -Avoid using classes from the configured package hierarchy outside of the package hierarchy, -except when using one of the configured allowed classes. Example: -
-package some.package;
-
-import some.other.package.subpackage.subsubpackage.DontUseThisClass;
-
-public class Bar {
-   DontUseThisClass boo = new DontUseThisClass();
-}
-
diff --git a/docs/rules/MDBAndSessionBeanNamingConvention.md b/docs/rules/MDBAndSessionBeanNamingConvention.md deleted file mode 100644 index ff779af4..00000000 --- a/docs/rules/MDBAndSessionBeanNamingConvention.md +++ /dev/null @@ -1,8 +0,0 @@ -# MDBAndSessionBeanNamingConvention -**Category:** `pmd`
-**Rule Key:** `pmd:MDBAndSessionBeanNamingConvention`
- - ------ - -The EJB Specification state that any MessageDrivenBean or SessionBean should be suffixed by Bean. diff --git a/docs/rules/MethodArgumentCouldBeFinal.md b/docs/rules/MethodArgumentCouldBeFinal.md deleted file mode 100644 index 55d0369c..00000000 --- a/docs/rules/MethodArgumentCouldBeFinal.md +++ /dev/null @@ -1,8 +0,0 @@ -# MethodArgumentCouldBeFinal -**Category:** `pmd`
-**Rule Key:** `pmd:MethodArgumentCouldBeFinal`
-> :warning: This rule is **deprecated** in favour of [S1226](https://rules.sonarsource.com/java/RSPEC-1226). - ------ - -A method argument that is never assigned can be declared final. diff --git a/docs/rules/MethodNamingConventions.md b/docs/rules/MethodNamingConventions.md deleted file mode 100644 index 8418c2e0..00000000 --- a/docs/rules/MethodNamingConventions.md +++ /dev/null @@ -1,14 +0,0 @@ -# MethodNamingConventions -**Category:** `pmd`
-**Rule Key:** `pmd:MethodNamingConventions`
-> :warning: This rule is **deprecated** in favour of [S00100](https://rules.sonarsource.com/java/RSPEC-100). - ------ - -Method names should always begin with a lower case character, and should not contain underscores. Example : -
-public class Foo {
-  public void fooStuff() {
-  }
-}
-
diff --git a/docs/rules/MethodReturnsInternalArray.md b/docs/rules/MethodReturnsInternalArray.md deleted file mode 100644 index 36e2d27d..00000000 --- a/docs/rules/MethodReturnsInternalArray.md +++ /dev/null @@ -1,8 +0,0 @@ -# MethodReturnsInternalArray -**Category:** `pmd`
-**Rule Key:** `pmd:MethodReturnsInternalArray`
-> :warning: This rule is **deprecated** in favour of [S2384](https://rules.sonarsource.com/java/RSPEC-2384). - ------ - -Exposing internal arrays directly allows the user to modify some code that could be critical. It is safer to return a copy of the array. diff --git a/docs/rules/MethodWithSameNameAsEnclosingClass.md b/docs/rules/MethodWithSameNameAsEnclosingClass.md deleted file mode 100644 index b1bdbe21..00000000 --- a/docs/rules/MethodWithSameNameAsEnclosingClass.md +++ /dev/null @@ -1,16 +0,0 @@ -# MethodWithSameNameAsEnclosingClass -**Category:** `pmd`
-**Rule Key:** `pmd:MethodWithSameNameAsEnclosingClass`
-> :warning: This rule is **deprecated** in favour of [S1223](https://rules.sonarsource.com/java/RSPEC-1223). - ------ - -Non-constructor methods should not have the same name as the enclosing class. Example : -
-public class MyClass {
-  // this is bad because it is a method
-  public void MyClass() {}
-  // this is OK because it is a constructor
-  public MyClass() {}
-}
-
diff --git a/docs/rules/MisleadingVariableName.md b/docs/rules/MisleadingVariableName.md deleted file mode 100644 index 566176df..00000000 --- a/docs/rules/MisleadingVariableName.md +++ /dev/null @@ -1,16 +0,0 @@ -# MisleadingVariableName -**Category:** `pmd`
-**Rule Key:** `pmd:MisleadingVariableName`
-> :warning: This rule is **deprecated** in favour of [S00117](https://rules.sonarsource.com/java/RSPEC-117). - ------ - -Detects when a non-field has a name starting with 'm_'. This usually indicates a field and thus is confusing. Example : -
-public class Foo {
-  private int m_foo; // OK
-  public void bar(String m_baz) {  // Bad
-    int m_boz = 42; // Bad
-  }
-}
-
diff --git a/docs/rules/MisplacedNullCheck.md b/docs/rules/MisplacedNullCheck.md deleted file mode 100644 index 431089c2..00000000 --- a/docs/rules/MisplacedNullCheck.md +++ /dev/null @@ -1,15 +0,0 @@ -# MisplacedNullCheck -**Category:** `pmd`
-**Rule Key:** `pmd:MisplacedNullCheck`
-> :warning: This rule is **deprecated** in favour of [S1697](https://rules.sonarsource.com/java/RSPEC-1697), [S2259](https://rules.sonarsource.com/java/RSPEC-2259). - ------ - -The null check here is misplaced. if the variable is null you'll get a NullPointerException. -Either the check is useless (the variable will never be null) or it's incorrect. -
Example : -
-if (object1!=null && object2.equals(object1)) { 
-  ...
-}      
-
diff --git a/docs/rules/MissingBreakInSwitch.md b/docs/rules/MissingBreakInSwitch.md deleted file mode 100644 index eaabeb4c..00000000 --- a/docs/rules/MissingBreakInSwitch.md +++ /dev/null @@ -1,8 +0,0 @@ -# MissingBreakInSwitch -**Category:** `pmd`
-**Rule Key:** `pmd:MissingBreakInSwitch`
-> :warning: This rule is **deprecated** in favour of [S128](https://rules.sonarsource.com/java/RSPEC-128). - ------ - -A switch statement without an enclosed break statement may be a bug. diff --git a/docs/rules/MissingSerialVersionUID.md b/docs/rules/MissingSerialVersionUID.md deleted file mode 100644 index d19cf20d..00000000 --- a/docs/rules/MissingSerialVersionUID.md +++ /dev/null @@ -1,8 +0,0 @@ -# MissingSerialVersionUID -**Category:** `pmd`
-**Rule Key:** `pmd:MissingSerialVersionUID`
-> :warning: This rule is **deprecated** in favour of [S2057](https://rules.sonarsource.com/java/RSPEC-2057). - ------ - -Classes that are serializable should provide a serialVersionUID field. diff --git a/docs/rules/MissingStaticMethodInNonInstantiatableClass.md b/docs/rules/MissingStaticMethodInNonInstantiatableClass.md deleted file mode 100644 index 5c704a11..00000000 --- a/docs/rules/MissingStaticMethodInNonInstantiatableClass.md +++ /dev/null @@ -1,8 +0,0 @@ -# MissingStaticMethodInNonInstantiatableClass -**Category:** `pmd`
-**Rule Key:** `pmd:MissingStaticMethodInNonInstantiatableClass`
- - ------ - -A class that has private constructors and does not have any static methods or fields cannot be used. diff --git a/docs/rules/ModifiedCyclomaticComplexity.md b/docs/rules/ModifiedCyclomaticComplexity.md deleted file mode 100644 index 59c14234..00000000 --- a/docs/rules/ModifiedCyclomaticComplexity.md +++ /dev/null @@ -1,8 +0,0 @@ -# ModifiedCyclomaticComplexity -**Category:** `pmd`
-**Rule Key:** `pmd:ModifiedCyclomaticComplexity`
-> :warning: This rule is **deprecated** in favour of `squid:MethodCyclomaticComplexity`. - ------ - -Complexity directly affects maintenance costs is determined by the number of decision points in a method plus one for the method entry. The decision points include 'if', 'while', 'for', and 'case labels' calls. Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote high complexity, and 11+ is very high complexity. Modified complexity treats switch statements as a single decision point. diff --git a/docs/rules/MoreThanOneLogger.md b/docs/rules/MoreThanOneLogger.md deleted file mode 100644 index 432ee494..00000000 --- a/docs/rules/MoreThanOneLogger.md +++ /dev/null @@ -1,8 +0,0 @@ -# MoreThanOneLogger -**Category:** `pmd`
-**Rule Key:** `pmd:MoreThanOneLogger`
-> :warning: This rule is **deprecated** in favour of [S1312](https://rules.sonarsource.com/java/RSPEC-1312). - ------ - -Normally only one logger is used in each class. diff --git a/docs/rules/NPathComplexity.md b/docs/rules/NPathComplexity.md deleted file mode 100644 index cfa10c1f..00000000 --- a/docs/rules/NPathComplexity.md +++ /dev/null @@ -1,15 +0,0 @@ -# NPathComplexity -**Category:** `pmd`
-**Rule Key:** `pmd:NPathComplexity`
- - ------ - -The NPath complexity of a method is the number of acyclic execution paths through that method. A threshold of 200 is generally considered the point where measures should be taken to reduce complexity. Example : -
-public class Foo {
-  void bar() {
-   // lots of complicated code
-  }
- }
-
diff --git a/docs/rules/NcssConstructorCount.md b/docs/rules/NcssConstructorCount.md deleted file mode 100644 index f91b8ae9..00000000 --- a/docs/rules/NcssConstructorCount.md +++ /dev/null @@ -1,8 +0,0 @@ -# NcssConstructorCount -**Category:** `pmd`
-**Rule Key:** `pmd:NcssConstructorCount`
-> :warning: This rule is **deprecated** in favour of [S138](https://rules.sonarsource.com/java/RSPEC-138). - ------ - -This rule uses the NCSS (Non Commenting Source Statements) algorithm to determine the number of lines of code for a given constructor. NCSS ignores comments, and counts actual statements. Using this algorithm, lines of code that are split are counted as one. diff --git a/docs/rules/NcssMethodCount.md b/docs/rules/NcssMethodCount.md deleted file mode 100644 index 5ce6f2e5..00000000 --- a/docs/rules/NcssMethodCount.md +++ /dev/null @@ -1,8 +0,0 @@ -# NcssMethodCount -**Category:** `pmd`
-**Rule Key:** `pmd:NcssMethodCount`
-> :warning: This rule is **deprecated** in favour of [S138](https://rules.sonarsource.com/java/RSPEC-138). - ------ - -This rule uses the NCSS (Non Commenting Source Statements) algorithm to determine the number of lines of code for a given method. NCSS ignores comments, and counts actual statements. Using this algorithm, lines of code that are split are counted as one. diff --git a/docs/rules/NcssTypeCount.md b/docs/rules/NcssTypeCount.md deleted file mode 100644 index 260ec358..00000000 --- a/docs/rules/NcssTypeCount.md +++ /dev/null @@ -1,12 +0,0 @@ -# NcssTypeCount -**Category:** `pmd`
-**Rule Key:** `pmd:NcssTypeCount`
- - ------ - -This rule uses the NCSS (Non Commenting Source Statements) algorithm to determine the number of lines of code for a given type. NCSS ignores comments, and counts actual statements. Using this algorithm, lines of code that are split are counted as one. - -

- This rule is deprecated, use {rule:common-java:InsufficientCommentDensity} instead. -

diff --git a/docs/rules/NoPackage.md b/docs/rules/NoPackage.md deleted file mode 100644 index 2cc68876..00000000 --- a/docs/rules/NoPackage.md +++ /dev/null @@ -1,13 +0,0 @@ -# NoPackage -**Category:** `pmd`
-**Rule Key:** `pmd:NoPackage`
-> :warning: This rule is **deprecated** in favour of [S1220](https://rules.sonarsource.com/java/RSPEC-1220). - ------ - -Detects when a class or interface does not have a package definition. Example : -
-// no package declaration
-public class ClassInDefaultPackage {
-}
-  
diff --git a/docs/rules/NonCaseLabelInSwitchStatement.md b/docs/rules/NonCaseLabelInSwitchStatement.md deleted file mode 100644 index ac2138a3..00000000 --- a/docs/rules/NonCaseLabelInSwitchStatement.md +++ /dev/null @@ -1,8 +0,0 @@ -# NonCaseLabelInSwitchStatement -**Category:** `pmd`
-**Rule Key:** `pmd:NonCaseLabelInSwitchStatement`
-> :warning: This rule is **deprecated** in favour of [S1219](https://rules.sonarsource.com/java/RSPEC-1219). - ------ - -A non-case label (e.g. a named break/continue label) was present in a switch statement. This legal, but confusing. It is easy to mix up the case labels and the non-case labels. diff --git a/docs/rules/NonStaticInitializer.md b/docs/rules/NonStaticInitializer.md deleted file mode 100644 index b1695382..00000000 --- a/docs/rules/NonStaticInitializer.md +++ /dev/null @@ -1,10 +0,0 @@ -# NonStaticInitializer -**Category:** `pmd`
-**Rule Key:** `pmd:NonStaticInitializer`
-> :warning: This rule is **deprecated** in favour of [S1171](https://rules.sonarsource.com/java/RSPEC-1171). - ------ - -A nonstatic initializer block will be called any time a constructor is invoked (just prior to invoking the constructor). While this is a valid language construct, it is rarely used and is confusing. Example : -
public class MyClass {
// this block gets run before any call to a constructor {
System.out.println("I - am about to construct myself");
}
}
diff --git a/docs/rules/NonThreadSafeSingleton.md b/docs/rules/NonThreadSafeSingleton.md deleted file mode 100644 index 39c60312..00000000 --- a/docs/rules/NonThreadSafeSingleton.md +++ /dev/null @@ -1,8 +0,0 @@ -# NonThreadSafeSingleton -**Category:** `pmd`
-**Rule Key:** `pmd:NonThreadSafeSingleton`
-> :warning: This rule is **deprecated** in favour of [S2444](https://rules.sonarsource.com/java/RSPEC-2444). - ------ - -Non-thread safe singletons can result in bad state changes. Eliminate static singletons if possible by instantiating the object directly. Static singletons are usually not needed as only a single instance exists anyway. Other possible fixes are to synchronize the entire method or to use an initialize-on-demand holder class (do not use the double-check idiom). See Effective Java, item 48. diff --git a/docs/rules/NullAssignment.md b/docs/rules/NullAssignment.md deleted file mode 100644 index 486525b8..00000000 --- a/docs/rules/NullAssignment.md +++ /dev/null @@ -1,8 +0,0 @@ -# NullAssignment -**Category:** `pmd`
-**Rule Key:** `pmd:NullAssignment`
- - ------ - -Assigning a null to a variable (outside of its declaration) is usually bad form. Some times, the assignment is an indication that the programmer doesn't completely understand what is going on in the code. NOTE: This sort of assignment may in rare cases be useful to encourage garbage collection. If that's what you're using it for, by all means, disregard this rule :-) diff --git a/docs/rules/OneDeclarationPerLine.md b/docs/rules/OneDeclarationPerLine.md deleted file mode 100644 index deffa693..00000000 --- a/docs/rules/OneDeclarationPerLine.md +++ /dev/null @@ -1,15 +0,0 @@ -# OneDeclarationPerLine -**Category:** `pmd`
-**Rule Key:** `pmd:OneDeclarationPerLine`
-> :warning: This rule is **deprecated** in favour of [S00122](https://rules.sonarsource.com/java/RSPEC-122). - ------ - -Java allows the use of several variables declaration of the same type on one line. However, it -can lead to quite messy code. This rule looks for several declarations on the same line. Example: -
-String name; // separate declarations
-String lastname;
-
-String name, lastname; // combined declaration, a violation
-
diff --git a/docs/rules/OnlyOneReturn.md b/docs/rules/OnlyOneReturn.md deleted file mode 100644 index a8765ee2..00000000 --- a/docs/rules/OnlyOneReturn.md +++ /dev/null @@ -1,8 +0,0 @@ -# OnlyOneReturn -**Category:** `pmd`
-**Rule Key:** `pmd:OnlyOneReturn`
-> :warning: This rule is **deprecated** in favour of [S1142](https://rules.sonarsource.com/java/RSPEC-1142). - ------ - -A method should have only one exit point, and that should be the last statement in the method. diff --git a/docs/rules/OptimizableToArrayCall.md b/docs/rules/OptimizableToArrayCall.md deleted file mode 100644 index d7ca172a..00000000 --- a/docs/rules/OptimizableToArrayCall.md +++ /dev/null @@ -1,41 +0,0 @@ -# OptimizableToArrayCall -**Category:** `pmd`
-**Rule Key:** `pmd:OptimizableToArrayCall`
- - ------ - - -

- Calls to a collection’s toArray(E[]) method should specify a target array of zero size. This allows the - JVM to - optimize the memory allocation and copying as much as possible. -

-

- Previous versions of this rule (pre PMD 6.0.0) suggested the opposite, but current JVM implementations - perform always better, when they have full control over the target array. And allocation an array via - reflection is nowadays as fast as the direct allocation. -

-

- See also Arrays of Wisdom of the Ancients -

-

- Note: If you don’t need an array of the correct type, then the simple toArray() method without an array - is faster, but - returns only an array of type Object[]. -

-

Noncompliant Code Example

-
-List<Foo> foos = getFoos();
-
-// inefficient, the array needs to be zeroed out by the jvm before it is handed over to the toArray method
-Foo[] fooArray = foos.toArray(new Foo[foos.size()]);
-
-

Compliant Solution

-
-List<Foo> foos = getFoos();
-
-// much better; this one allows the jvm to allocate an array of the correct size and effectively skip
-// the zeroing, since each array element will be overridden anyways
-Foo[] fooArray = foos.toArray(new Foo[0]);
-
diff --git a/docs/rules/OverrideBothEqualsAndHashcode.md b/docs/rules/OverrideBothEqualsAndHashcode.md deleted file mode 100644 index 6d807f12..00000000 --- a/docs/rules/OverrideBothEqualsAndHashcode.md +++ /dev/null @@ -1,33 +0,0 @@ -# OverrideBothEqualsAndHashcode -**Category:** `pmd`
-**Rule Key:** `pmd:OverrideBothEqualsAndHashcode`
-> :warning: This rule is **deprecated** in favour of [S1206](https://rules.sonarsource.com/java/RSPEC-1206). - ------ - -Override both public boolean Object.equals(Object other), and public int Object.hashCode(), or override neither. Even if you are inheriting a hashCode() from a parent class, consider implementing hashCode and explicitly delegating to your superclass. Example : -
-// this is bad
-public class Bar {
-  public boolean equals(Object o) {
-      // do some comparison
-  }
-}
-
-// and so is this
-public class Baz {
-  public int hashCode() {
-      // return some hash value
-  }
-}
-
-// this is OK
-public class Foo {
-  public boolean equals(Object other) {
-      // do some comparison
-  }
-  public int hashCode() {
-      // return some hash value
-  }
-}
-
diff --git a/docs/rules/PackageCase.md b/docs/rules/PackageCase.md deleted file mode 100644 index 762030ca..00000000 --- a/docs/rules/PackageCase.md +++ /dev/null @@ -1,13 +0,0 @@ -# PackageCase -**Category:** `pmd`
-**Rule Key:** `pmd:PackageCase`
-> :warning: This rule is **deprecated** in favour of [S00120](https://rules.sonarsource.com/java/RSPEC-120). - ------ - -Detects when a package definition contains upper case characters. Example : -
-package com.MyCompany;  // <- should be lower case name
-public class SomeClass {
-}
-
diff --git a/docs/rules/PositionLiteralsFirstInCaseInsensitiveComparisons.md b/docs/rules/PositionLiteralsFirstInCaseInsensitiveComparisons.md deleted file mode 100644 index f0662ba8..00000000 --- a/docs/rules/PositionLiteralsFirstInCaseInsensitiveComparisons.md +++ /dev/null @@ -1,16 +0,0 @@ -# PositionLiteralsFirstInCaseInsensitiveComparisons -**Category:** `pmd`
-**Rule Key:** `pmd:PositionLiteralsFirstInCaseInsensitiveComparisons`
-> :warning: This rule is **deprecated** in favour of [S1132](https://rules.sonarsource.com/java/RSPEC-1132). - ------ - -Position literals first in comparisons, if the second argument is null then NullPointerExceptions -can be avoided, they will just return false. Example: -
-class Foo {
-  boolean bar(String x) {
-    return x.equalsIgnoreCase("2"); // should be "2".equalsIgnoreCase(x)
-  }
-}
-
diff --git a/docs/rules/PositionLiteralsFirstInComparisons.md b/docs/rules/PositionLiteralsFirstInComparisons.md deleted file mode 100644 index c1e6310e..00000000 --- a/docs/rules/PositionLiteralsFirstInComparisons.md +++ /dev/null @@ -1,8 +0,0 @@ -# PositionLiteralsFirstInComparisons -**Category:** `pmd`
-**Rule Key:** `pmd:PositionLiteralsFirstInComparisons`
-> :warning: This rule is **deprecated** in favour of [S1132](https://rules.sonarsource.com/java/RSPEC-1132). - ------ - -Position literals first in String comparisons - that way if the String is null you won't get a NullPointerException, it'll just return false. diff --git a/docs/rules/PrematureDeclaration.md b/docs/rules/PrematureDeclaration.md deleted file mode 100644 index d51d27c2..00000000 --- a/docs/rules/PrematureDeclaration.md +++ /dev/null @@ -1,22 +0,0 @@ -# PrematureDeclaration -**Category:** `pmd`
-**Rule Key:** `pmd:PrematureDeclaration`
-> :warning: This rule is **deprecated** in favour of [S1941](https://rules.sonarsource.com/java/RSPEC-1941). - ------ - -Checks for variables that are defined before they might be used. A reference is deemed to be premature if it is created right before a block of code that doesn't use it that also has the ability to return or throw an exception. Example: -
-public int getLength(String[] strings) {
-
-  int length = 0; // declared prematurely
-
-  if (strings == null || strings.length == 0) return 0;
-
-  for (String str : strings) {
-    length += str.length();
-  }
-
-  return length;
-}
-
diff --git a/docs/rules/PreserveStackTrace.md b/docs/rules/PreserveStackTrace.md deleted file mode 100644 index 5124fd58..00000000 --- a/docs/rules/PreserveStackTrace.md +++ /dev/null @@ -1,8 +0,0 @@ -# PreserveStackTrace -**Category:** `pmd`
-**Rule Key:** `pmd:PreserveStackTrace`
-> :warning: This rule is **deprecated** in favour of [S1166](https://rules.sonarsource.com/java/RSPEC-1166). - ------ - -Throwing a new exception from a catch block without passing the original exception into the new Exception will cause the true stack trace to be lost, and can make it difficult to debug effectively. diff --git a/docs/rules/ProperCloneImplementation.md b/docs/rules/ProperCloneImplementation.md deleted file mode 100644 index 8ece5d5e..00000000 --- a/docs/rules/ProperCloneImplementation.md +++ /dev/null @@ -1,15 +0,0 @@ -# ProperCloneImplementation -**Category:** `pmd`
-**Rule Key:** `pmd:ProperCloneImplementation`
-> :warning: This rule is **deprecated** in favour of [S1182](https://rules.sonarsource.com/java/RSPEC-1182). - ------ - -Object clone() should be implemented with super.clone(). Example : -
-class Foo{
-    public Object clone(){
-        return new Foo(); // This is bad
-    }
-}
-  
diff --git a/docs/rules/ProperLogger.md b/docs/rules/ProperLogger.md deleted file mode 100644 index 07b655e8..00000000 --- a/docs/rules/ProperLogger.md +++ /dev/null @@ -1,8 +0,0 @@ -# ProperLogger -**Category:** `pmd`
-**Rule Key:** `pmd:ProperLogger`
-> :warning: This rule is **deprecated** in favour of [S1312](https://rules.sonarsource.com/java/RSPEC-1312). - ------ - -Logger should normally be defined private static final and have the correct class. Private final Log log; is also allowed for rare cases when loggers need to be passed around, but the logger needs to be passed into the constructor. diff --git a/docs/rules/RedundantFieldInitializer.md b/docs/rules/RedundantFieldInitializer.md deleted file mode 100644 index d1fa57e9..00000000 --- a/docs/rules/RedundantFieldInitializer.md +++ /dev/null @@ -1,30 +0,0 @@ -# RedundantFieldInitializer -**Category:** `pmd`
-**Rule Key:** `pmd:RedundantFieldInitializer`
- - ------ - -Java will initialize fields with known default values so any explicit initialization of those same defaults -is redundant and results in a larger class file (approximately three additional bytecode instructions per field). Example: -
-public class C {
-  boolean b = false; // examples of redundant initializers
-  byte by   = 0;
-  short s   = 0;
-  char c    = 0;
-  int i     = 0;
-  long l    = 0;
-
-  float f   = .0f;   // all possible float literals
-  doable d  = 0d;    // all possible double literals
-  Object o  = null;
-
-  MyClass mca[] = null;
-  int i1 = 0, ia1[] = null;
-
-  class Nested {
-    boolean b = false;
-  }
-}
-
diff --git a/docs/rules/RemoteInterfaceNamingConvention.md b/docs/rules/RemoteInterfaceNamingConvention.md deleted file mode 100644 index 4d69ea0f..00000000 --- a/docs/rules/RemoteInterfaceNamingConvention.md +++ /dev/null @@ -1,8 +0,0 @@ -# RemoteInterfaceNamingConvention -**Category:** `pmd`
-**Rule Key:** `pmd:RemoteInterfaceNamingConvention`
- - ------ - -Remote Interface of a Session EJB should NOT be suffixed. diff --git a/docs/rules/RemoteSessionInterfaceNamingConvention.md b/docs/rules/RemoteSessionInterfaceNamingConvention.md deleted file mode 100644 index 1a0ffc4c..00000000 --- a/docs/rules/RemoteSessionInterfaceNamingConvention.md +++ /dev/null @@ -1,8 +0,0 @@ -# RemoteSessionInterfaceNamingConvention -**Category:** `pmd`
-**Rule Key:** `pmd:RemoteSessionInterfaceNamingConvention`
- - ------ - -Remote Home interface of a Session EJB should be suffixed by "Home". diff --git a/docs/rules/ReplaceEnumerationWithIterator.md b/docs/rules/ReplaceEnumerationWithIterator.md deleted file mode 100644 index 23dfc8dd..00000000 --- a/docs/rules/ReplaceEnumerationWithIterator.md +++ /dev/null @@ -1,8 +0,0 @@ -# ReplaceEnumerationWithIterator -**Category:** `pmd`
-**Rule Key:** `pmd:ReplaceEnumerationWithIterator`
-> :warning: This rule is **deprecated** in favour of [S1150](https://rules.sonarsource.com/java/RSPEC-1150). - ------ - -Consider replacing this Enumeration with the newer java.util.Iterator diff --git a/docs/rules/ReplaceHashtableWithMap.md b/docs/rules/ReplaceHashtableWithMap.md deleted file mode 100644 index 37471019..00000000 --- a/docs/rules/ReplaceHashtableWithMap.md +++ /dev/null @@ -1,8 +0,0 @@ -# ReplaceHashtableWithMap -**Category:** `pmd`
-**Rule Key:** `pmd:ReplaceHashtableWithMap`
-> :warning: This rule is **deprecated** in favour of [S1149](https://rules.sonarsource.com/java/RSPEC-1149). - ------ - -Consider replacing this Hashtable with the newer java.util.Map diff --git a/docs/rules/ReplaceVectorWithList.md b/docs/rules/ReplaceVectorWithList.md deleted file mode 100644 index de41fa97..00000000 --- a/docs/rules/ReplaceVectorWithList.md +++ /dev/null @@ -1,8 +0,0 @@ -# ReplaceVectorWithList -**Category:** `pmd`
-**Rule Key:** `pmd:ReplaceVectorWithList`
-> :warning: This rule is **deprecated** in favour of [S1149](https://rules.sonarsource.com/java/RSPEC-1149). - ------ - -Consider replacing Vector usages with the newer java.util.ArrayList if expensive threadsafe operation is not required. diff --git a/docs/rules/ReturnEmptyArrayRatherThanNull.md b/docs/rules/ReturnEmptyArrayRatherThanNull.md deleted file mode 100644 index 5874df46..00000000 --- a/docs/rules/ReturnEmptyArrayRatherThanNull.md +++ /dev/null @@ -1,26 +0,0 @@ -# ReturnEmptyArrayRatherThanNull -**Category:** `pmd`
-**Rule Key:** `pmd:ReturnEmptyArrayRatherThanNull`
-> :warning: This rule is **deprecated** in favour of [S1168](https://rules.sonarsource.com/java/RSPEC-1168). - ------ - -For any method that returns an array, it's a better behavior to return an empty array rather than a null reference. Example : -
-public class Example
-{
-  // Not a good idea...
-  public int []badBehavior()
-  {
-    // ...
-    return null;
-  }
-
-  // Good behavior
-  public String[] bonnePratique()
-  {
-    //...
-    return new String[0];
-  }
-}
-
diff --git a/docs/rules/ReturnFromFinallyBlock.md b/docs/rules/ReturnFromFinallyBlock.md deleted file mode 100644 index 43c828d3..00000000 --- a/docs/rules/ReturnFromFinallyBlock.md +++ /dev/null @@ -1,8 +0,0 @@ -# ReturnFromFinallyBlock -**Category:** `pmd`
-**Rule Key:** `pmd:ReturnFromFinallyBlock`
-> :warning: This rule is **deprecated** in favour of [S1143](https://rules.sonarsource.com/java/RSPEC-1143). - ------ - -Avoid returning from a finally block - this can discard exceptions. diff --git a/docs/rules/ShortClassName.md b/docs/rules/ShortClassName.md deleted file mode 100644 index 5be899e0..00000000 --- a/docs/rules/ShortClassName.md +++ /dev/null @@ -1,12 +0,0 @@ -# ShortClassName -**Category:** `pmd`
-**Rule Key:** `pmd:ShortClassName`
-> :warning: This rule is **deprecated** in favour of [S00101](https://rules.sonarsource.com/java/RSPEC-101). - ------ - -Classnames with fewer than five characters are not recommended. Example: -
-public class Foo {
-}
-
diff --git a/docs/rules/ShortInstantiation.md b/docs/rules/ShortInstantiation.md deleted file mode 100644 index 5f16c723..00000000 --- a/docs/rules/ShortInstantiation.md +++ /dev/null @@ -1,14 +0,0 @@ -# ShortInstantiation -**Category:** `pmd`
-**Rule Key:** `pmd:ShortInstantiation`
- - ------ - -In JDK 1.5, calling new Short() causes memory allocation. Short.valueOf() is more memory friendly. Example : -
-public class Foo {
-private Short i = new Short(0); // change to Short i =
-Short.valueOf(0);
-}
-  
diff --git a/docs/rules/ShortMethodName.md b/docs/rules/ShortMethodName.md deleted file mode 100644 index b9e924a4..00000000 --- a/docs/rules/ShortMethodName.md +++ /dev/null @@ -1,14 +0,0 @@ -# ShortMethodName -**Category:** `pmd`
-**Rule Key:** `pmd:ShortMethodName`
-> :warning: This rule is **deprecated** in favour of [S00100](https://rules.sonarsource.com/java/RSPEC-100). - ------ - -Detects when very short method names are used. Example : -
-public class ShortMethod {
-  public void a( int i ) { // Violation
-  }
-}
-
diff --git a/docs/rules/ShortVariable.md b/docs/rules/ShortVariable.md deleted file mode 100644 index 736ddc9c..00000000 --- a/docs/rules/ShortVariable.md +++ /dev/null @@ -1,8 +0,0 @@ -# ShortVariable -**Category:** `pmd`
-**Rule Key:** `pmd:ShortVariable`
-> :warning: This rule is **deprecated** in favour of [S00117](https://rules.sonarsource.com/java/RSPEC-117). - ------ - -Detects when a field, local, or parameter has a very short name. diff --git a/docs/rules/SignatureDeclareThrowsException.md b/docs/rules/SignatureDeclareThrowsException.md deleted file mode 100644 index 82b7beba..00000000 --- a/docs/rules/SignatureDeclareThrowsException.md +++ /dev/null @@ -1,8 +0,0 @@ -# SignatureDeclareThrowsException -**Category:** `pmd`
-**Rule Key:** `pmd:SignatureDeclareThrowsException`
-> :warning: This rule is **deprecated** in favour of [S00112](https://rules.sonarsource.com/java/RSPEC-112). - ------ - -It is unclear which exceptions that can be thrown from the methods. It might be difficult to document and understand the vague interfaces. Use either a class derived from RuntimeException or a checked exception. diff --git a/docs/rules/SignatureDeclareThrowsExceptionWithTypeResolution.md b/docs/rules/SignatureDeclareThrowsExceptionWithTypeResolution.md deleted file mode 100644 index fb4785c4..00000000 --- a/docs/rules/SignatureDeclareThrowsExceptionWithTypeResolution.md +++ /dev/null @@ -1,16 +0,0 @@ -# SignatureDeclareThrowsExceptionWithTypeResolution -**Category:** `pmd`
-**Rule Key:** `pmd:SignatureDeclareThrowsExceptionWithTypeResolution`
-> :warning: This rule is **deprecated** in favour of [S00112](https://rules.sonarsource.com/java/RSPEC-112). - ------ - -It is unclear which exceptions that can be thrown from the methods. -It might be difficult to document and understand the vague interfaces. -Use either a class derived from RuntimeException or a checked exception. - -JUnit classes are excluded. Example: -
-public void methodThrowingException() throws Exception {
-}
-
diff --git a/docs/rules/SimpleDateFormatNeedsLocale.md b/docs/rules/SimpleDateFormatNeedsLocale.md deleted file mode 100644 index ab01298e..00000000 --- a/docs/rules/SimpleDateFormatNeedsLocale.md +++ /dev/null @@ -1,8 +0,0 @@ -# SimpleDateFormatNeedsLocale -**Category:** `pmd`
-**Rule Key:** `pmd:SimpleDateFormatNeedsLocale`
- - ------ - -Be sure to specify a Locale when creating a new instance of SimpleDateFormat. diff --git a/docs/rules/SimplifiedTernary.md b/docs/rules/SimplifiedTernary.md deleted file mode 100644 index 56778ff2..00000000 --- a/docs/rules/SimplifiedTernary.md +++ /dev/null @@ -1,31 +0,0 @@ -# SimplifiedTernary -**Category:** `pmd`
-**Rule Key:** `pmd:SimplifiedTernary`
- - ------ - -

- Look for ternary operators with the form condition ? literalBoolean : foo or condition ? foo : literalBoolean. -

- -

Examples:

-
-public class Foo {
-  public boolean test() {
-    return condition ? true : something(); // can be as simple as return condition || something();
-  }
-
-  public void test2() {
-    final boolean value = condition ? false : something(); // can be as simple as value = !condition && something();
-  }
-
-  public boolean test3() {
-    return condition ? something() : true; // can be as simple as return !condition || something();
-  }
-
-  public void test4() {
-    final boolean otherValue = condition ? something() : false; // can be as simple as condition && something();
-  }
-}
-
diff --git a/docs/rules/SimplifyBooleanAssertion.md b/docs/rules/SimplifyBooleanAssertion.md deleted file mode 100644 index aabafc77..00000000 --- a/docs/rules/SimplifyBooleanAssertion.md +++ /dev/null @@ -1,16 +0,0 @@ -# SimplifyBooleanAssertion -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:SimplifyBooleanAssertion`
- - ------ - -Avoid negation in an assertTrue or assertFalse test. For example, rephrase: assertTrue(!expr); as: assertFalse(expr); -
-public class SimpleTest extends TestCase {
-  public void testX() {
-    assertTrue("not empty", !r.isEmpty()); // violation, replace with assertFalse("not empty", r.isEmpty())
-    assertFalse(!r.isEmpty()); // violation, replace with assertTrue("empty", r.isEmpty())
-  }
-}
-
diff --git a/docs/rules/SimplifyBooleanExpressions.md b/docs/rules/SimplifyBooleanExpressions.md deleted file mode 100644 index 4ab8c84b..00000000 --- a/docs/rules/SimplifyBooleanExpressions.md +++ /dev/null @@ -1,17 +0,0 @@ -# SimplifyBooleanExpressions -**Category:** `pmd`
-**Rule Key:** `pmd:SimplifyBooleanExpressions`
-> :warning: This rule is **deprecated** in favour of [S1125](https://rules.sonarsource.com/java/RSPEC-1125). - ------ - -Avoid unnecessary comparisons in boolean expressions - this complicates simple code. Example : -
-public class Bar {
- // can be simplified to
- // bar = isFoo();
- private boolean bar = (isFoo() == true);
-
- public isFoo() { return false;}
-}
-
diff --git a/docs/rules/SimplifyBooleanReturns.md b/docs/rules/SimplifyBooleanReturns.md deleted file mode 100644 index 87c3df5f..00000000 --- a/docs/rules/SimplifyBooleanReturns.md +++ /dev/null @@ -1,23 +0,0 @@ -# SimplifyBooleanReturns -**Category:** `pmd`
-**Rule Key:** `pmd:SimplifyBooleanReturns`
-> :warning: This rule is **deprecated** in favour of [S1126](https://rules.sonarsource.com/java/RSPEC-1126). - ------ - -Avoid unnecessary if..then..else statements when returning a boolean. Example : -
-public class Foo {
-  private int bar =2;
-  public boolean isBarEqualsTo(int x) {
-    // this bit of code
-    if (bar == x) {
-     return true;
-    } else {
-     return false;
-    }
-    // can be replaced with a simple
-    // return bar == x;
-  }
-}
-
diff --git a/docs/rules/SimplifyConditional.md b/docs/rules/SimplifyConditional.md deleted file mode 100644 index 6d5af3d1..00000000 --- a/docs/rules/SimplifyConditional.md +++ /dev/null @@ -1,8 +0,0 @@ -# SimplifyConditional -**Category:** `pmd`
-**Rule Key:** `pmd:SimplifyConditional`
- - ------ - -No need to check for null before an instanceof; the instanceof keyword returns false when given a null argument. diff --git a/docs/rules/SimplifyStartsWith.md b/docs/rules/SimplifyStartsWith.md deleted file mode 100644 index 810ba790..00000000 --- a/docs/rules/SimplifyStartsWith.md +++ /dev/null @@ -1,8 +0,0 @@ -# SimplifyStartsWith -**Category:** `pmd`
-**Rule Key:** `pmd:SimplifyStartsWith`
- - ------ - -Since it passes in a literal of length 1, this call to String.startsWith can be rewritten using String.charAt(0) to save some time. diff --git a/docs/rules/SingleMethodSingleton.md b/docs/rules/SingleMethodSingleton.md deleted file mode 100644 index b3608e2f..00000000 --- a/docs/rules/SingleMethodSingleton.md +++ /dev/null @@ -1,30 +0,0 @@ -# SingleMethodSingleton -**Category:** `pmd`
-**Rule Key:** `pmd:SingleMethodSingleton`
- - ------ - -

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

- -

Examples:

-
-public class Singleton {
-  private static Singleton singleton = new Singleton( );
-
-  private Singleton() { }
-
-  public static Singleton getInstance( ) {
-    return singleton;
-  }
-
-  public static Singleton getInstance(Object obj) {
-    Singleton singleton = (Singleton) obj;
-    return singleton; //violation
-  }
-}
-
diff --git a/docs/rules/SingletonClassReturningNewInstance.md b/docs/rules/SingletonClassReturningNewInstance.md deleted file mode 100644 index d020e22b..00000000 --- a/docs/rules/SingletonClassReturningNewInstance.md +++ /dev/null @@ -1,25 +0,0 @@ -# SingletonClassReturningNewInstance -**Category:** `pmd`
-**Rule Key:** `pmd: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. -

- -

Examples:

-
-class Singleton {
-  private static Singleton instance = null;
-
-  public static Singleton getInstance() {
-    synchronized(Singleton.class) {
-      return new Singleton();
-    }
-  }
-}
-
diff --git a/docs/rules/SingularField.md b/docs/rules/SingularField.md deleted file mode 100644 index 230367db..00000000 --- a/docs/rules/SingularField.md +++ /dev/null @@ -1,8 +0,0 @@ -# SingularField -**Category:** `pmd`
-**Rule Key:** `pmd:SingularField`
- - ------ - -A field that's only used by one method could perhaps be replaced by a local variable. diff --git a/docs/rules/StaticEJBFieldShouldBeFinal.md b/docs/rules/StaticEJBFieldShouldBeFinal.md deleted file mode 100644 index 2f17acbc..00000000 --- a/docs/rules/StaticEJBFieldShouldBeFinal.md +++ /dev/null @@ -1,8 +0,0 @@ -# StaticEJBFieldShouldBeFinal -**Category:** `pmd`
-**Rule Key:** `pmd:StaticEJBFieldShouldBeFinal`
- - ------ - -According to the J2EE specification (p.494), an EJB should not have any static fields with write access. However, static read only fields are allowed. This ensures proper behavior especially when instances are distributed by the container on several JREs. diff --git a/docs/rules/StdCyclomaticComplexity.md b/docs/rules/StdCyclomaticComplexity.md deleted file mode 100644 index 3f1379f8..00000000 --- a/docs/rules/StdCyclomaticComplexity.md +++ /dev/null @@ -1,8 +0,0 @@ -# StdCyclomaticComplexity -**Category:** `pmd`
-**Rule Key:** `pmd:StdCyclomaticComplexity`
-> :warning: This rule is **deprecated** in favour of `squid:MethodCyclomaticComplexity`, `squid:ClassCyclomaticComplexity`. - ------ - -Complexity directly affects maintenance costs is determined by the number of decision points in a method plus one for the method entry. The decision points include 'if', 'while', 'for', and 'case labels' calls. Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote high complexity, and 11+ is very high complexity. diff --git a/docs/rules/StringBufferInstantiationWithChar.md b/docs/rules/StringBufferInstantiationWithChar.md deleted file mode 100644 index adc4bce1..00000000 --- a/docs/rules/StringBufferInstantiationWithChar.md +++ /dev/null @@ -1,8 +0,0 @@ -# StringBufferInstantiationWithChar -**Category:** `pmd`
-**Rule Key:** `pmd:StringBufferInstantiationWithChar`
-> :warning: This rule is **deprecated** in favour of [S1317](https://rules.sonarsource.com/java/RSPEC-1317). - ------ - -StringBuffer sb = new StringBuffer('c'); The char will be converted into int to intialize StringBuffer size. diff --git a/docs/rules/StringInstantiation.md b/docs/rules/StringInstantiation.md deleted file mode 100644 index d19eaedf..00000000 --- a/docs/rules/StringInstantiation.md +++ /dev/null @@ -1,8 +0,0 @@ -# StringInstantiation -**Category:** `pmd`
-**Rule Key:** `pmd:StringInstantiation`
- - ------ - -Avoid instantiating String objects; this is usually unnecessary. diff --git a/docs/rules/StringToString.md b/docs/rules/StringToString.md deleted file mode 100644 index d47a2ec8..00000000 --- a/docs/rules/StringToString.md +++ /dev/null @@ -1,8 +0,0 @@ -# StringToString -**Category:** `pmd`
-**Rule Key:** `pmd:StringToString`
-> :warning: This rule is **deprecated** in favour of [S1858](https://rules.sonarsource.com/java/RSPEC-1858). - ------ - -Avoid calling toString() on String objects; this is unnecessary. diff --git a/docs/rules/SuspiciousConstantFieldName.md b/docs/rules/SuspiciousConstantFieldName.md deleted file mode 100644 index 15818027..00000000 --- a/docs/rules/SuspiciousConstantFieldName.md +++ /dev/null @@ -1,16 +0,0 @@ -# SuspiciousConstantFieldName -**Category:** `pmd`
-**Rule Key:** `pmd:SuspiciousConstantFieldName`
-> :warning: This rule is **deprecated** in favour of [S00116](https://rules.sonarsource.com/java/RSPEC-116). - ------ - -A field name is all in uppercase characters, which in Sun's Java naming conventions indicate a constant. However, the field is not final. Example : -
-public class Foo {
-  // this is bad, since someone could accidentally
-  // do PI = 2.71828; which is actualy e
-  // final double PI = 3.16; is ok
-  double PI = 3.16;
-}
-
diff --git a/docs/rules/SuspiciousEqualsMethodName.md b/docs/rules/SuspiciousEqualsMethodName.md deleted file mode 100644 index 7a6eb44a..00000000 --- a/docs/rules/SuspiciousEqualsMethodName.md +++ /dev/null @@ -1,18 +0,0 @@ -# SuspiciousEqualsMethodName -**Category:** `pmd`
-**Rule Key:** `pmd:SuspiciousEqualsMethodName`
-> :warning: This rule is **deprecated** in favour of [S1201](https://rules.sonarsource.com/java/RSPEC-1201). - ------ - -The method name and parameter number are suspiciously close to equals(Object), which may mean you are intending to override the equals(Object) method. Example : -
-public class Foo {
-  public int equals(Object o) {
-  // oops, this probably was supposed to be boolean equals
-  }
-  public boolean equals(String s) {
-  // oops, this probably was supposed to be equals(Object)
-  }
-}
-
diff --git a/docs/rules/SuspiciousHashcodeMethodName.md b/docs/rules/SuspiciousHashcodeMethodName.md deleted file mode 100644 index 362a51d3..00000000 --- a/docs/rules/SuspiciousHashcodeMethodName.md +++ /dev/null @@ -1,14 +0,0 @@ -# SuspiciousHashcodeMethodName -**Category:** `pmd`
-**Rule Key:** `pmd:SuspiciousHashcodeMethodName`
-> :warning: This rule is **deprecated** in favour of [S1221](https://rules.sonarsource.com/java/RSPEC-1221). - ------ - -The method name and return type are suspiciously close to hashCode(), which may mean you are intending to override the hashCode() method. Example : -
-public class Foo {
-  public int hashcode() {
-  // oops, this probably was supposed to be hashCode
-  }
-}
diff --git a/docs/rules/SuspiciousOctalEscape.md b/docs/rules/SuspiciousOctalEscape.md deleted file mode 100644 index c0534466..00000000 --- a/docs/rules/SuspiciousOctalEscape.md +++ /dev/null @@ -1,8 +0,0 @@ -# SuspiciousOctalEscape -**Category:** `pmd`
-**Rule Key:** `pmd:SuspiciousOctalEscape`
- - ------ - -A suspicious octal escape sequence was found inside a String literal. The Java language specification (section 3.10.6) says an octal escape sequence inside a literal String shall consist of a backslash followed by: OctalDigit | OctalDigit OctalDigit | ZeroToThree OctalDigit OctalDigit Any octal escape sequence followed by non-octal digits can be confusing, e.g. "\038" is interpreted as the octal escape sequence "\03" followed by the literal character 8. diff --git a/docs/rules/SwitchDensity.md b/docs/rules/SwitchDensity.md deleted file mode 100644 index c04ef3c5..00000000 --- a/docs/rules/SwitchDensity.md +++ /dev/null @@ -1,8 +0,0 @@ -# SwitchDensity -**Category:** `pmd`
-**Rule Key:** `pmd:SwitchDensity`
-> :warning: This rule is **deprecated** in favour of [S1151](https://rules.sonarsource.com/java/RSPEC-1151). - ------ - -A high ratio of statements to labels in a switch statement implies that the switch statement is doing too much work. Consider moving the statements into new methods, or creating subclasses based on the switch variable. diff --git a/docs/rules/SwitchStmtsShouldHaveDefault.md b/docs/rules/SwitchStmtsShouldHaveDefault.md deleted file mode 100644 index 48dab687..00000000 --- a/docs/rules/SwitchStmtsShouldHaveDefault.md +++ /dev/null @@ -1,18 +0,0 @@ -# SwitchStmtsShouldHaveDefault -**Category:** `pmd`
-**Rule Key:** `pmd:SwitchStmtsShouldHaveDefault`
-> :warning: This rule is **deprecated** in favour of `squid:SwitchLastCaseIsDefaultCheck`. - ------ - -Switch statements should have a default label. Example : -
-public class Foo {
- public void bar() {
-  int x = 2;
-  switch (x) {
-   case 2: int j = 8;
-  }
- }
-}
-
diff --git a/docs/rules/SystemPrintln.md b/docs/rules/SystemPrintln.md deleted file mode 100644 index 46395f9a..00000000 --- a/docs/rules/SystemPrintln.md +++ /dev/null @@ -1,8 +0,0 @@ -# SystemPrintln -**Category:** `pmd`
-**Rule Key:** `pmd:SystemPrintln`
-> :warning: This rule is **deprecated** in favour of [S106](https://rules.sonarsource.com/java/RSPEC-106). - ------ - -System.(out|err).print is used, consider using a logger. diff --git a/docs/rules/TestClassWithoutTestCases.md b/docs/rules/TestClassWithoutTestCases.md deleted file mode 100644 index 5bdf97d4..00000000 --- a/docs/rules/TestClassWithoutTestCases.md +++ /dev/null @@ -1,17 +0,0 @@ -# TestClassWithoutTestCases -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:TestClassWithoutTestCases`
- - ------ - -Test classes end with the suffix Test. Having a non-test class with that name is not a good practice, since most people will assume it is a test case. Test classes have test methods named testXXX. -Beware: This rule doesn't support JUnit 4.x's @Test annotation. -
-public class CarTest { // violation, consider changing the name of the class if it is not a test
-  // consider adding test methods if it is a test
-  public static void main(String[] args) {
-    // do something
-  }
-}
-
diff --git a/docs/rules/TooFewBranchesForASwitchStatement.md b/docs/rules/TooFewBranchesForASwitchStatement.md deleted file mode 100644 index 273a5d39..00000000 --- a/docs/rules/TooFewBranchesForASwitchStatement.md +++ /dev/null @@ -1,23 +0,0 @@ -# TooFewBranchesForASwitchStatement -**Category:** `pmd`
-**Rule Key:** `pmd:TooFewBranchesForASwitchStatement`
-> :warning: This rule is **deprecated** in favour of [S1301](https://rules.sonarsource.com/java/RSPEC-1301). - ------ - -Swith are designed complex branches, and allow branches to share treatement. Using a switch for only a few branches is ill advised, as switches are not as easy to understand as if. In this case, it's most likely is a good idea to use a if statement instead, at least to increase code readability. Example : -
-// With a minimumNumberCaseForASwitch of 3
-public class Foo {
-  public void bar() {
-    switch (condition) {
-      case ONE:
-        instruction;
-        break;
-      default:
-        break; // not enough for a 'switch' stmt,
-               // a simple 'if' stmt would have been more appropriate
-    }
-  }
-}
-
diff --git a/docs/rules/TooManyFields.md b/docs/rules/TooManyFields.md deleted file mode 100644 index aadf3598..00000000 --- a/docs/rules/TooManyFields.md +++ /dev/null @@ -1,8 +0,0 @@ -# TooManyFields -**Category:** `pmd`
-**Rule Key:** `pmd:TooManyFields`
- - ------ - -Classes that have too many fields could be redesigned to have fewer fields, possibly through some nested object grouping of some of the information. For example, a class with city/state/zip fields could instead have one Address field. diff --git a/docs/rules/TooManyMethods.md b/docs/rules/TooManyMethods.md deleted file mode 100644 index d204581d..00000000 --- a/docs/rules/TooManyMethods.md +++ /dev/null @@ -1,8 +0,0 @@ -# TooManyMethods -**Category:** `pmd`
-**Rule Key:** `pmd:TooManyMethods`
-> :warning: This rule is **deprecated** in favour of [S1448](https://rules.sonarsource.com/java/RSPEC-1448). - ------ - -A class with too many methods is probably a good suspect for refactoring, in order to reduce its complexity and find a way to have more fine grained objects. diff --git a/docs/rules/TooManyStaticImports.md b/docs/rules/TooManyStaticImports.md deleted file mode 100644 index 6d1faaaa..00000000 --- a/docs/rules/TooManyStaticImports.md +++ /dev/null @@ -1,8 +0,0 @@ -# TooManyStaticImports -**Category:** `pmd`
-**Rule Key:** `pmd:TooManyStaticImports`
- - ------ - -If you overuse the static import feature, it can make your program unreadable and unmaintainable, polluting its namespace with all the static members you import. Readers of your code (including you, a few months after you wrote it) will not know which class a static member comes from (Sun 1.5 Language Guide). diff --git a/docs/rules/UncommentedEmptyConstructor.md b/docs/rules/UncommentedEmptyConstructor.md deleted file mode 100644 index c9ecfd4c..00000000 --- a/docs/rules/UncommentedEmptyConstructor.md +++ /dev/null @@ -1,8 +0,0 @@ -# UncommentedEmptyConstructor -**Category:** `pmd`
-**Rule Key:** `pmd:UncommentedEmptyConstructor`
-> :warning: This rule is **deprecated** in favour of [S2094](https://rules.sonarsource.com/java/RSPEC-2094). - ------ - -Uncommented Empty Constructor finds instances where a constructor does not contain statements, but there is no comment. By explicitly commenting empty constructors it is easier to distinguish between intentional (commented) and unintentional empty constructors. diff --git a/docs/rules/UncommentedEmptyMethodBody.md b/docs/rules/UncommentedEmptyMethodBody.md deleted file mode 100644 index f5a63f91..00000000 --- a/docs/rules/UncommentedEmptyMethodBody.md +++ /dev/null @@ -1,10 +0,0 @@ -# UncommentedEmptyMethodBody -**Category:** `pmd`
-**Rule Key:** `pmd:UncommentedEmptyMethodBody`
-> :warning: This rule is **deprecated** in favour of [S1186](https://rules.sonarsource.com/java/RSPEC-1186). - ------ - -

Uncommented Empty Method finds instances where a method does not contain statements, but there is no comment. By - explicitly commenting empty methods it is easier to distinguish between intentional (commented) and unintentional - empty methods.

diff --git a/docs/rules/UnconditionalIfStatement.md b/docs/rules/UnconditionalIfStatement.md deleted file mode 100644 index 16ca9f1b..00000000 --- a/docs/rules/UnconditionalIfStatement.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnconditionalIfStatement -**Category:** `pmd`
-**Rule Key:** `pmd:UnconditionalIfStatement`
-> :warning: This rule is **deprecated** in favour of [S2583](https://rules.sonarsource.com/java/RSPEC-2583). - ------ - -Do not use if statements that are always true or always false. diff --git a/docs/rules/UnnecessaryBooleanAssertion.md b/docs/rules/UnnecessaryBooleanAssertion.md deleted file mode 100644 index 0e5f69cf..00000000 --- a/docs/rules/UnnecessaryBooleanAssertion.md +++ /dev/null @@ -1,14 +0,0 @@ -# UnnecessaryBooleanAssertion -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:UnnecessaryBooleanAssertion`
- - ------ - -A JUnit test assertion with a boolean literal is unnecessary since it always will eval to the same thing. Consider using flow control (in case of assertTrue(false) or similar) or simply removing statements like assertTrue(true) and assertFalse(false). If you just want a test to halt, use the fail method. -
-public class SimpleTest extends TestCase {
-  public void testX() {
-    assertTrue(true); // violation
-  }
-}
diff --git a/docs/rules/UnnecessaryCaseChange.md b/docs/rules/UnnecessaryCaseChange.md deleted file mode 100644 index 2a9d602f..00000000 --- a/docs/rules/UnnecessaryCaseChange.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnnecessaryCaseChange -**Category:** `pmd`
-**Rule Key:** `pmd:UnnecessaryCaseChange`
-> :warning: This rule is **deprecated** in favour of [S1157](https://rules.sonarsource.com/java/RSPEC-1157). - ------ - -Using equalsIgnoreCase() is faster than using toUpperCase/toLowerCase().equals() diff --git a/docs/rules/UnnecessaryConstructor.md b/docs/rules/UnnecessaryConstructor.md deleted file mode 100644 index 1e666689..00000000 --- a/docs/rules/UnnecessaryConstructor.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnnecessaryConstructor -**Category:** `pmd`
-**Rule Key:** `pmd:UnnecessaryConstructor`
-> :warning: This rule is **deprecated** in favour of [S1186](https://rules.sonarsource.com/java/RSPEC-1186). - ------ - -This rule detects when a constructor is not necessary; i.e., when there's only one constructor, it's public, has an empty body, and takes no arguments. diff --git a/docs/rules/UnnecessaryConversionTemporary.md b/docs/rules/UnnecessaryConversionTemporary.md deleted file mode 100644 index 7b5b87bf..00000000 --- a/docs/rules/UnnecessaryConversionTemporary.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnnecessaryConversionTemporary -**Category:** `pmd`
-**Rule Key:** `pmd:UnnecessaryConversionTemporary`
-> :warning: This rule is **deprecated** in favour of [S1158](https://rules.sonarsource.com/java/RSPEC-1158). - ------ - -Avoid unnecessary temporaries when converting primitives to Strings diff --git a/docs/rules/UnnecessaryFinalModifier.md b/docs/rules/UnnecessaryFinalModifier.md deleted file mode 100644 index 4de8c53f..00000000 --- a/docs/rules/UnnecessaryFinalModifier.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnnecessaryFinalModifier -**Category:** `pmd`
-**Rule Key:** `pmd:UnnecessaryFinalModifier`
- - ------ - -When a class has the final modifier, all the methods are automatically final. diff --git a/docs/rules/UnnecessaryFullyQualifiedName.md b/docs/rules/UnnecessaryFullyQualifiedName.md deleted file mode 100644 index d0bcabbf..00000000 --- a/docs/rules/UnnecessaryFullyQualifiedName.md +++ /dev/null @@ -1,17 +0,0 @@ -# UnnecessaryFullyQualifiedName -**Category:** `pmd`
-**Rule Key:** `pmd:UnnecessaryFullyQualifiedName`
- - ------ - -Import statements allow the use of non-fully qualified names. The use of a fully qualified name -which is covered by an import statement is redundant. Consider using the non-fully qualified name. Example: -
-import java.util.List;
-
-public class Foo {
-   private java.util.List list1; // Unnecessary FQN
-   private List list2; // More appropriate given import of 'java.util.List'
-}
-
diff --git a/docs/rules/UnnecessaryLocalBeforeReturn.md b/docs/rules/UnnecessaryLocalBeforeReturn.md deleted file mode 100644 index d130e7dd..00000000 --- a/docs/rules/UnnecessaryLocalBeforeReturn.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnnecessaryLocalBeforeReturn -**Category:** `pmd`
-**Rule Key:** `pmd:UnnecessaryLocalBeforeReturn`
-> :warning: This rule is **deprecated** in favour of [S1488](https://rules.sonarsource.com/java/RSPEC-1488). - ------ - -Avoid unnecessarily creating local variables diff --git a/docs/rules/UnnecessaryParentheses.md b/docs/rules/UnnecessaryParentheses.md deleted file mode 100644 index 7aec3784..00000000 --- a/docs/rules/UnnecessaryParentheses.md +++ /dev/null @@ -1,15 +0,0 @@ -# UnnecessaryParentheses -**Category:** `pmd`
-**Rule Key:** `pmd:UnnecessaryParentheses`
-> :warning: This rule is **deprecated** in favour of `squid:UselessParenthesesCheck`. - ------ - -Sometimes expressions are wrapped in unnecessary parentheses, making them look like a function call. Example : -
-public class Foo {
-  boolean bar() {
-    return (true);
-  }
-}
-
diff --git a/docs/rules/UnnecessaryReturn.md b/docs/rules/UnnecessaryReturn.md deleted file mode 100644 index 6087ae87..00000000 --- a/docs/rules/UnnecessaryReturn.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnnecessaryReturn -**Category:** `pmd`
-**Rule Key:** `pmd:UnnecessaryReturn`
- - ------ - -Avoid unnecessary return statements diff --git a/docs/rules/UnnecessaryWrapperObjectCreation.md b/docs/rules/UnnecessaryWrapperObjectCreation.md deleted file mode 100644 index da95fe64..00000000 --- a/docs/rules/UnnecessaryWrapperObjectCreation.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnnecessaryWrapperObjectCreation -**Category:** `pmd`
-**Rule Key:** `pmd:UnnecessaryWrapperObjectCreation`
-> :warning: This rule is **deprecated** in favour of [S1158](https://rules.sonarsource.com/java/RSPEC-1158). - ------ - -Parsing method should be called directy instead. diff --git a/docs/rules/UnsynchronizedStaticDateFormatter.md b/docs/rules/UnsynchronizedStaticDateFormatter.md deleted file mode 100644 index 8ee84ff0..00000000 --- a/docs/rules/UnsynchronizedStaticDateFormatter.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnsynchronizedStaticDateFormatter -**Category:** `pmd`
-**Rule Key:** `pmd:UnsynchronizedStaticDateFormatter`
-> :warning: This rule is **deprecated** in favour of [S2156](https://rules.sonarsource.com/java/RSPEC-2156). - ------ - -SimpleDateFormat is not synchronized. Sun recomends separate format instances for each thread. If multiple threads must access a static formatter, the formatter must be synchronized either on method or block level. diff --git a/docs/rules/UnusedFormalParameter.md b/docs/rules/UnusedFormalParameter.md deleted file mode 100644 index 91a07e2d..00000000 --- a/docs/rules/UnusedFormalParameter.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnusedFormalParameter -**Category:** `pmd`
-**Rule Key:** `pmd:UnusedFormalParameter`
-> :warning: This rule is **deprecated** in favour of [S1172](https://rules.sonarsource.com/java/RSPEC-1172). - ------ - -

Avoid passing parameters to methods or constructors and then not using those parameters.

diff --git a/docs/rules/UnusedImports.md b/docs/rules/UnusedImports.md deleted file mode 100644 index 6e5742e4..00000000 --- a/docs/rules/UnusedImports.md +++ /dev/null @@ -1,13 +0,0 @@ -# UnusedImports -**Category:** `pmd`
-**Rule Key:** `pmd:UnusedImports`
-> :warning: This rule is **deprecated** in favour of `squid:UselessImportCheck`. - ------ - -Avoid unused import statements. Example : -
-// this is bad
-import java.io.File;
-public class Foo {}
-  
diff --git a/docs/rules/UnusedImportsWithTypeResolution.md b/docs/rules/UnusedImportsWithTypeResolution.md deleted file mode 100644 index 247cb8c2..00000000 --- a/docs/rules/UnusedImportsWithTypeResolution.md +++ /dev/null @@ -1,13 +0,0 @@ -# UnusedImportsWithTypeResolution -**Category:** `pmd`
-**Rule Key:** `pmd:UnusedImportsWithTypeResolution`
-> :warning: This rule is **deprecated** in favour of `squid:UselessImportCheck`. - ------ - -Avoid unused import statements. This rule will find unused on demand imports, i.e. import com.foo.*. Example: -
-import java.io.*; // not referenced or required
-
-public class Foo {}
-
diff --git a/docs/rules/UnusedLocalVariable.md b/docs/rules/UnusedLocalVariable.md deleted file mode 100644 index 811774be..00000000 --- a/docs/rules/UnusedLocalVariable.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnusedLocalVariable -**Category:** `pmd`
-**Rule Key:** `pmd:UnusedLocalVariable`
-> :warning: This rule is **deprecated** in favour of [S1481](https://rules.sonarsource.com/java/RSPEC-1481). - ------ - -Detects when a local variable is declared and/or assigned, but not used. diff --git a/docs/rules/UnusedModifier.md b/docs/rules/UnusedModifier.md deleted file mode 100644 index 8e5aafba..00000000 --- a/docs/rules/UnusedModifier.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnusedModifier -**Category:** `pmd`
-**Rule Key:** `pmd:UnusedModifier`
- - ------ - -Fields in interfaces are automatically public static final, and methods are public abstract. Classes or interfaces nested in an interface are automatically public and static (all nested interfaces are automatically static). For historical reasons, modifiers which are implied by the context are accepted by the compiler, but are superfluous. diff --git a/docs/rules/UnusedNullCheckInEquals.md b/docs/rules/UnusedNullCheckInEquals.md deleted file mode 100644 index dcb39e69..00000000 --- a/docs/rules/UnusedNullCheckInEquals.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnusedNullCheckInEquals -**Category:** `pmd`
-**Rule Key:** `pmd:UnusedNullCheckInEquals`
- - ------ - -After checking an object reference for null, you should invoke equals() on that object rather than passing it to another object's equals() method. diff --git a/docs/rules/UnusedPrivateField.md b/docs/rules/UnusedPrivateField.md deleted file mode 100644 index d18b94df..00000000 --- a/docs/rules/UnusedPrivateField.md +++ /dev/null @@ -1,8 +0,0 @@ -# UnusedPrivateField -**Category:** `pmd`
-**Rule Key:** `pmd:UnusedPrivateField`
-> :warning: This rule is **deprecated** in favour of [S1068](https://rules.sonarsource.com/java/RSPEC-1068). - ------ - -Detects when a private field is declared and/or assigned a value, but not used. diff --git a/docs/rules/UnusedPrivateMethod.md b/docs/rules/UnusedPrivateMethod.md deleted file mode 100644 index 831bfe72..00000000 --- a/docs/rules/UnusedPrivateMethod.md +++ /dev/null @@ -1,12 +0,0 @@ -# UnusedPrivateMethod -**Category:** `pmd`
-**Rule Key:** `pmd:UnusedPrivateMethod`
-> :warning: This rule is **deprecated** in favour of `squid:UnusedPrivateMethod`. - ------ - -

- Unused Private Method detects when a private method is declared but is unused. This PMD rule should be switched off - and replaced by its equivalent from Squid that is more effective : it generates less false-positives and detects more - dead code. -

diff --git a/docs/rules/UseArrayListInsteadOfVector.md b/docs/rules/UseArrayListInsteadOfVector.md deleted file mode 100644 index fa211e46..00000000 --- a/docs/rules/UseArrayListInsteadOfVector.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseArrayListInsteadOfVector -**Category:** `pmd`
-**Rule Key:** `pmd:UseArrayListInsteadOfVector`
-> :warning: This rule is **deprecated** in favour of [S1149](https://rules.sonarsource.com/java/RSPEC-1149). - ------ - -ArrayList is a much better Collection implementation than Vector. diff --git a/docs/rules/UseArraysAsList.md b/docs/rules/UseArraysAsList.md deleted file mode 100644 index 304d069a..00000000 --- a/docs/rules/UseArraysAsList.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseArraysAsList -**Category:** `pmd`
-**Rule Key:** `pmd:UseArraysAsList`
- - ------ - -The class java.util.Arrays has a asList method that should be use when you want to create a new List from an array of objects. It is faster than executing a loop to cpy all the elements of the array one by one diff --git a/docs/rules/UseAssertEqualsInsteadOfAssertTrue.md b/docs/rules/UseAssertEqualsInsteadOfAssertTrue.md deleted file mode 100644 index 376c962c..00000000 --- a/docs/rules/UseAssertEqualsInsteadOfAssertTrue.md +++ /dev/null @@ -1,17 +0,0 @@ -# UseAssertEqualsInsteadOfAssertTrue -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:UseAssertEqualsInsteadOfAssertTrue`
- - ------ - -This rule detects JUnit assertions in object equality. These assertions should be made by more specific methods, like assertEquals. -
-public class FooTest extends TestCase {
-  void testCode() {
-    Object a, b;
-
-    assertTrue(a.equals(b)); // violation
-    assertEquals("a should equals b", a, b); // good usage
-  }
-}
diff --git a/docs/rules/UseAssertNullInsteadOfAssertTrue.md b/docs/rules/UseAssertNullInsteadOfAssertTrue.md deleted file mode 100644 index fef99aa2..00000000 --- a/docs/rules/UseAssertNullInsteadOfAssertTrue.md +++ /dev/null @@ -1,20 +0,0 @@ -# UseAssertNullInsteadOfAssertTrue -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:UseAssertNullInsteadOfAssertTrue`
- - ------ - -This rule detects JUnit assertions in object references equality. These assertions should be made by more specific methods, like assertNull, assertNotNull. -
-public class FooTest extends TestCase {
-  void testCode() {
-    Object a = doSomething();
-
-    assertTrue(a==null); // violation
-    assertNull(a);  // good usage
-    assertTrue(a != null); // violation
-    assertNotNull(a);  // good usage
-  }
-}
-
diff --git a/docs/rules/UseAssertSameInsteadOfAssertTrue.md b/docs/rules/UseAssertSameInsteadOfAssertTrue.md deleted file mode 100644 index 010e55f4..00000000 --- a/docs/rules/UseAssertSameInsteadOfAssertTrue.md +++ /dev/null @@ -1,18 +0,0 @@ -# UseAssertSameInsteadOfAssertTrue -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:UseAssertSameInsteadOfAssertTrue`
- - ------ - -This rule detects JUnit assertions in object references equality. These assertions should be made by more specific methods, like assertSame, assertNotSame. -
-public class FooTest extends TestCase {
-  void testCode() {
-    Object a, b;
-
-    assertTrue(a==b); // violation
-    assertSame(a, b); // good usage
-  }
-}
-
diff --git a/docs/rules/UseAssertTrueInsteadOfAssertEquals.md b/docs/rules/UseAssertTrueInsteadOfAssertEquals.md deleted file mode 100644 index 2623037e..00000000 --- a/docs/rules/UseAssertTrueInsteadOfAssertEquals.md +++ /dev/null @@ -1,21 +0,0 @@ -# UseAssertTrueInsteadOfAssertEquals -**Category:** `pmd-unit-tests`
-**Rule Key:** `pmd-unit-tests:UseAssertTrueInsteadOfAssertEquals`
- - ------ - -When asserting a value is the same as a boolean literal, use assertTrue/assertFalse, instead of assertEquals. Example: -
-public class MyTestCase extends TestCase {
-	public void testMyCase() {
-		boolean myVar = true;
-		// Ok
-		assertTrue("myVar is true", myVar);
-		// Bad
-		assertEquals("myVar is true", true, myVar);
-		// Bad
-		assertEquals("myVar is false", false, myVar);
-	}
-}
-
diff --git a/docs/rules/UseCollectionIsEmpty.md b/docs/rules/UseCollectionIsEmpty.md deleted file mode 100644 index 11eea16e..00000000 --- a/docs/rules/UseCollectionIsEmpty.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseCollectionIsEmpty -**Category:** `pmd`
-**Rule Key:** `pmd:UseCollectionIsEmpty`
-> :warning: This rule is **deprecated** in favour of [S1155](https://rules.sonarsource.com/java/RSPEC-1155). - ------ - -The isEmpty() method on java.util.Collection is provided to see if a collection has any elements. Comparing the value of size() to 0 merely duplicates existing behavior. diff --git a/docs/rules/UseConcurrentHashMap.md b/docs/rules/UseConcurrentHashMap.md deleted file mode 100644 index a6cb515f..00000000 --- a/docs/rules/UseConcurrentHashMap.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseConcurrentHashMap -**Category:** `pmd`
-**Rule Key:** `pmd:UseConcurrentHashMap`
- - ------ - -Since Java5 brought a new implementation of the Map interface, specially designed for concurrent application. diff --git a/docs/rules/UseCorrectExceptionLogging.md b/docs/rules/UseCorrectExceptionLogging.md deleted file mode 100644 index 0d2d7637..00000000 --- a/docs/rules/UseCorrectExceptionLogging.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseCorrectExceptionLogging -**Category:** `pmd`
-**Rule Key:** `pmd:UseCorrectExceptionLogging`
-> :warning: This rule is **deprecated** in favour of [S1166](https://rules.sonarsource.com/java/RSPEC-1166). - ------ - -To make sure the full stacktrace is printed out, use the logging statement with 2 arguments: a String and a Throwable. diff --git a/docs/rules/UseEqualsToCompareStrings.md b/docs/rules/UseEqualsToCompareStrings.md deleted file mode 100644 index 62835ade..00000000 --- a/docs/rules/UseEqualsToCompareStrings.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseEqualsToCompareStrings -**Category:** `pmd`
-**Rule Key:** `pmd:UseEqualsToCompareStrings`
-> :warning: This rule is **deprecated** in favour of `squid:StringEqualityComparisonCheck`, [S1698](https://rules.sonarsource.com/java/RSPEC-1698). - ------ - -Using "==" or "!=" to compare strings only works if intern version is used on both sides. diff --git a/docs/rules/UseIndexOfChar.md b/docs/rules/UseIndexOfChar.md deleted file mode 100644 index 11ccfd02..00000000 --- a/docs/rules/UseIndexOfChar.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseIndexOfChar -**Category:** `pmd`
-**Rule Key:** `pmd:UseIndexOfChar`
- - ------ - -Use String.indexOf(char) when checking for the index of a single character; it executes faster. diff --git a/docs/rules/UseLocaleWithCaseConversions.md b/docs/rules/UseLocaleWithCaseConversions.md deleted file mode 100644 index a13a6fdb..00000000 --- a/docs/rules/UseLocaleWithCaseConversions.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseLocaleWithCaseConversions -**Category:** `pmd`
-**Rule Key:** `pmd:UseLocaleWithCaseConversions`
- - ------ - -When doing a String.toLowerCase()/toUpperCase() call, use a Locale. This avoids problems with certain locales, i.e. Turkish. diff --git a/docs/rules/UseNotifyAllInsteadOfNotify.md b/docs/rules/UseNotifyAllInsteadOfNotify.md deleted file mode 100644 index 111de85a..00000000 --- a/docs/rules/UseNotifyAllInsteadOfNotify.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseNotifyAllInsteadOfNotify -**Category:** `pmd`
-**Rule Key:** `pmd:UseNotifyAllInsteadOfNotify`
-> :warning: This rule is **deprecated** in favour of [S2446](https://rules.sonarsource.com/java/RSPEC-2446). - ------ - -Thread.notify() awakens a thread monitoring the object. If more than one thread is monitoring, then only one is chosen. The thread chosen is arbitrary; thus it's usually safer to call notifyAll() instead. diff --git a/docs/rules/UseObjectForClearerAPI.md b/docs/rules/UseObjectForClearerAPI.md deleted file mode 100644 index c759da8e..00000000 --- a/docs/rules/UseObjectForClearerAPI.md +++ /dev/null @@ -1,28 +0,0 @@ -# UseObjectForClearerAPI -**Category:** `pmd`
-**Rule Key:** `pmd:UseObjectForClearerAPI`
-> :warning: This rule is **deprecated** in favour of [S00107](https://rules.sonarsource.com/java/RSPEC-107). - ------ - -When you write a public method, you should be thinking in terms of an API. If your method is public, it means other class -will use it, therefore, you want (or need) to offer a comprehensive and evolutive API. If you pass a lot of information -as a simple series of Strings, you may think of using an Object to represent all those information. You'll get a simplier -API (such as doWork(Workload workload), rather than a tedious series of Strings) and more importantly, if you need at some -point to pass extra data, you'll be able to do so by simply modifying or extending Workload without any modification to -your API. Example: -
-public class MyClass {
-  public void connect(String username,
-    String pssd,
-    String databaseName,
-    String databaseAdress)
-    // Instead of those parameters object
-    // would ensure a cleaner API and permit
-    // to add extra data transparently (no code change):
-    // void connect(UserData data);
-    {
-
-  }
-}
-
diff --git a/docs/rules/UseProperClassLoader.md b/docs/rules/UseProperClassLoader.md deleted file mode 100644 index 5e3ba4f0..00000000 --- a/docs/rules/UseProperClassLoader.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseProperClassLoader -**Category:** `pmd`
-**Rule Key:** `pmd:UseProperClassLoader`
- - ------ - -In J2EE getClassLoader() might not work as expected. Use Thread.currentThread().getContextClassLoader() instead. diff --git a/docs/rules/UseStringBufferForStringAppends.md b/docs/rules/UseStringBufferForStringAppends.md deleted file mode 100644 index d971b692..00000000 --- a/docs/rules/UseStringBufferForStringAppends.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseStringBufferForStringAppends -**Category:** `pmd`
-**Rule Key:** `pmd:UseStringBufferForStringAppends`
- - ------ - -Finds usages of += for appending strings. diff --git a/docs/rules/UseStringBufferLength.md b/docs/rules/UseStringBufferLength.md deleted file mode 100644 index a5453b9e..00000000 --- a/docs/rules/UseStringBufferLength.md +++ /dev/null @@ -1,8 +0,0 @@ -# UseStringBufferLength -**Category:** `pmd`
-**Rule Key:** `pmd:UseStringBufferLength`
- - ------ - -Use StringBuffer.length() to determine StringBuffer length rather than using StringBuffer.toString().equals() or StringBuffer.toString().length() ==. diff --git a/docs/rules/UseUtilityClass.md b/docs/rules/UseUtilityClass.md deleted file mode 100644 index 94dc3069..00000000 --- a/docs/rules/UseUtilityClass.md +++ /dev/null @@ -1,11 +0,0 @@ -# UseUtilityClass -**Category:** `pmd`
-**Rule Key:** `pmd:UseUtilityClass`
-> :warning: This rule is **deprecated** in favour of [S1118](https://rules.sonarsource.com/java/RSPEC-1118). - ------ - -For classes that only have static methods, consider making them utility classes. -Note that this doesn't apply to abstract classes, since their subclasses may well include non-static methods. -Also, if you want this class to be a utility class, remember to add a private constructor to prevent instantiation. -(Note, that this use was known before PMD 5.1.0 as UseSingleton). diff --git a/docs/rules/UseVarargs.md b/docs/rules/UseVarargs.md deleted file mode 100644 index 8ea5b5f1..00000000 --- a/docs/rules/UseVarargs.md +++ /dev/null @@ -1,21 +0,0 @@ -# UseVarargs -**Category:** `pmd`
-**Rule Key:** `pmd:UseVarargs`
- - ------ - -Java 5 introduced the varargs parameter declaration for methods and constructors. This syntactic -sugar provides flexibility for users of these methods and constructors, allowing them to avoid -having to deal with the creation of an array. Example: -
-public class Foo {
-   public void foo(String s, Object[] args) {
-      // Do something here...
-   }
-
-   public void bar(String s, Object... args) {
-      // Ahh, varargs tastes much better...
-   }
-}
-
diff --git a/docs/rules/UselessOperationOnImmutable.md b/docs/rules/UselessOperationOnImmutable.md deleted file mode 100644 index d2699060..00000000 --- a/docs/rules/UselessOperationOnImmutable.md +++ /dev/null @@ -1,8 +0,0 @@ -# UselessOperationOnImmutable -**Category:** `pmd`
-**Rule Key:** `pmd:UselessOperationOnImmutable`
- - ------ - -An operation on an Immutable object (BigDecimal or BigInteger) won't change the object itself. The result of the operation is a new object. Therefore, ignoring the operation result is an error. diff --git a/docs/rules/UselessOverridingMethod.md b/docs/rules/UselessOverridingMethod.md deleted file mode 100644 index 89e98839..00000000 --- a/docs/rules/UselessOverridingMethod.md +++ /dev/null @@ -1,8 +0,0 @@ -# UselessOverridingMethod -**Category:** `pmd`
-**Rule Key:** `pmd:UselessOverridingMethod`
-> :warning: This rule is **deprecated** in favour of [S1185](https://rules.sonarsource.com/java/RSPEC-1185). - ------ - -The overriding method merely calls the same method defined in a superclass diff --git a/docs/rules/UselessParentheses.md b/docs/rules/UselessParentheses.md deleted file mode 100644 index 684fab63..00000000 --- a/docs/rules/UselessParentheses.md +++ /dev/null @@ -1,21 +0,0 @@ -# UselessParentheses -**Category:** `pmd`
-**Rule Key:** `pmd:UselessParentheses`
-> :warning: This rule is **deprecated** in favour of `squid:UselessParenthesesCheck`. - ------ - -Useless parentheses should be removed. Example: -
-public class Foo {
-
-   private int _bar1;
-   private Integer _bar2;
-
-   public void setBar(int n) {
-      _bar1 = Integer.valueOf((n)); // here
-      _bar2 = (n); // and here
-   }
-
-}
-
diff --git a/docs/rules/UselessQualifiedThis.md b/docs/rules/UselessQualifiedThis.md deleted file mode 100644 index 1e8ba96d..00000000 --- a/docs/rules/UselessQualifiedThis.md +++ /dev/null @@ -1,37 +0,0 @@ -# UselessQualifiedThis -**Category:** `pmd`
-**Rule Key:** `pmd:UselessQualifiedThis`
- - ------ - -

Look for qualified this usages in the same class.

- -

Examples:

- -
-public class Foo {
-  final Foo otherFoo = Foo.this;  // use "this" directly
-
-  public void doSomething() {
-    final Foo anotherFoo = Foo.this;  // use "this" directly
-  }
-
-  private ActionListener returnListener() {
-    return new ActionListener() {
-      @Override
-      public void actionPerformed(ActionEvent e) {
-        doSomethingWithQualifiedThis(Foo.this);  // This is fine
-      }
-    };
-  }
-
-  private class Foo3 {
-    final Foo myFoo = Foo.this;  // This is fine
-  }
-
-  private class Foo2 {
-    final Foo2 myFoo2 = Foo2.this;  // Use "this" direclty
-  }
-}
-
diff --git a/docs/rules/UselessStringValueOf.md b/docs/rules/UselessStringValueOf.md deleted file mode 100644 index b454af70..00000000 --- a/docs/rules/UselessStringValueOf.md +++ /dev/null @@ -1,8 +0,0 @@ -# UselessStringValueOf -**Category:** `pmd`
-**Rule Key:** `pmd:UselessStringValueOf`
-> :warning: This rule is **deprecated** in favour of [S1153](https://rules.sonarsource.com/java/RSPEC-1153). - ------ - -No need to call String.valueOf to append to a string; just use the valueOf() argument directly. diff --git a/docs/rules/VariableNamingConventions.md b/docs/rules/VariableNamingConventions.md deleted file mode 100644 index ac3ad558..00000000 --- a/docs/rules/VariableNamingConventions.md +++ /dev/null @@ -1,8 +0,0 @@ -# VariableNamingConventions -**Category:** `pmd`
-**Rule Key:** `pmd:VariableNamingConventions`
-> :warning: This rule is **deprecated** in favour of [S00115](https://rules.sonarsource.com/java/RSPEC-115), [S00116](https://rules.sonarsource.com/java/RSPEC-116). - ------ - -A variable naming conventions rule - customize this to your liking. Currently, it checks for final variables that should be fully capitalized and non-final variables that should not include underscores. diff --git a/docs/rules/WhileLoopsMustUseBraces.md b/docs/rules/WhileLoopsMustUseBraces.md deleted file mode 100644 index f84b78fe..00000000 --- a/docs/rules/WhileLoopsMustUseBraces.md +++ /dev/null @@ -1,10 +0,0 @@ -# WhileLoopsMustUseBraces -**Category:** `pmd`
-**Rule Key:** `pmd:WhileLoopsMustUseBraces`
-> :warning: This rule is **deprecated** in favour of [S00121](https://rules.sonarsource.com/java/RSPEC-121). - ------ - -

- Avoid using 'while' statements without using curly braces. -

diff --git a/docs/rules/XPathRule.md b/docs/rules/XPathRule.md deleted file mode 100644 index 406f774e..00000000 --- a/docs/rules/XPathRule.md +++ /dev/null @@ -1,33 +0,0 @@ -# XPathRule -**Category:** `pmd`
-**Rule Key:** `pmd:XPathRule`
- - ------ - -PMD provides a very handy method for creating new rules by writing an XPath query. When the XPath query finds a match, a violation is created. -Let's take a simple example: assume we have a Factory class that must be always declared final. -We'd like to report a violation each time a declaration of Factory is not declared final. Consider the following class: -
-public class a {
-  Factory f1;
-
-  void myMethod() {
-    Factory f2;
-    int a;
-  }
-}
-
-The following expression does the magic we need: -
-//VariableDeclarator
- [../Type/ReferenceType/ClassOrInterfaceType
-  [@Image = 'Factory'] and ..[@Final='false']]
-
-See the XPath rule - tutorial for more information. - -

- This rule is deprecated, please see the documentation on Extending - Coding Rules. -

diff --git a/integration-test/pom.xml b/integration-test/pom.xml index 46623586..cdad522a 100644 --- a/integration-test/pom.xml +++ b/integration-test/pom.xml @@ -2,7 +2,8 @@ pmd + java:8.0.0.0,kotlin:2.0.0.0 + java,kotlin + + + + + maven-clean-plugin + + + + ${basedir}/projects + + **/target/** + + false + + diff --git a/integration-test/projects/pmd-avoid-duplicate-literals/pom.xml b/integration-test/projects/pmd-avoid-duplicate-literals/pom.xml index cd96acdd..b743b0d0 100644 --- a/integration-test/projects/pmd-avoid-duplicate-literals/pom.xml +++ b/integration-test/projects/pmd-avoid-duplicate-literals/pom.xml @@ -5,4 +5,35 @@ com.sonarsource.it.projects pmd-avoid-duplicate-literals 1.0-SNAPSHOT + + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 5.1.0.4751 + + + + + + + + skipSonar + + + skipTestProjects + true + + + + true + + + + + 11 + 11 + diff --git a/integration-test/projects/pmd-extensions/pom.xml b/integration-test/projects/pmd-extensions/pom.xml index dd3f35b2..ee55aab3 100644 --- a/integration-test/projects/pmd-extensions/pom.xml +++ b/integration-test/projects/pmd-extensions/pom.xml @@ -10,4 +10,31 @@ 11 UTF-8 + + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 5.1.0.4751 + + + + + + + + skipSonar + + + skipTestProjects + true + + + + true + + + diff --git a/integration-test/projects/pmd-extensions/src/main/java/pmd/Bar.java b/integration-test/projects/pmd-extensions/src/main/java/pmd/Bar.java index fb8e57ae..41a9580b 100644 --- a/integration-test/projects/pmd-extensions/src/main/java/pmd/Bar.java +++ b/integration-test/projects/pmd-extensions/src/main/java/pmd/Bar.java @@ -1,5 +1,8 @@ package pmd; public class Bar extends Foo { - + public void method() { + // PMD7-MIGRATION: added to force one violation in pmdShouldHaveAccessToExternalLibrariesInItsClasspath: is this testing the correct thing? + if (true) System.out.println("violation on AvoidIfWithoutBrace"); + } } diff --git a/integration-test/projects/pmd-junit-rules/pom.xml b/integration-test/projects/pmd-junit-rules/pom.xml deleted file mode 100644 index cfc06a12..00000000 --- a/integration-test/projects/pmd-junit-rules/pom.xml +++ /dev/null @@ -1,16 +0,0 @@ - - 4.0.0 - - com.sonarsource.it.projects - pmd-junit-rules - 1.0-SNAPSHOT - - - junit - junit - 3.8 - test - - - diff --git a/integration-test/projects/pmd-junit-rules/src/main/java/ProductionCode.java b/integration-test/projects/pmd-junit-rules/src/main/java/ProductionCode.java deleted file mode 100644 index d86b2e31..00000000 --- a/integration-test/projects/pmd-junit-rules/src/main/java/ProductionCode.java +++ /dev/null @@ -1,3 +0,0 @@ -public class ProductionCode { - private int unused; -} diff --git a/integration-test/projects/pmd-junit-rules/src/test/java/ProductionCodeTest.java b/integration-test/projects/pmd-junit-rules/src/test/java/ProductionCodeTest.java deleted file mode 100644 index 8dd97bb0..00000000 --- a/integration-test/projects/pmd-junit-rules/src/test/java/ProductionCodeTest.java +++ /dev/null @@ -1,3 +0,0 @@ -public class ProductionCodeTest extends junit.framework.TestCase { - private int unused; -} diff --git a/integration-test/projects/pmd-kotlin-rules/pom.xml b/integration-test/projects/pmd-kotlin-rules/pom.xml new file mode 100644 index 00000000..81e8e9a2 --- /dev/null +++ b/integration-test/projects/pmd-kotlin-rules/pom.xml @@ -0,0 +1,63 @@ + + 4.0.0 + + com.sonarsource.it.projects + pmd-kotlin-rules + 1.0-SNAPSHOT + + 1.9.0 + UTF-8 + + + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + + + ${project.basedir}/src/main/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + + compile + + + + + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 5.2.0.4988 + + + + + + + + skipSonar + + + skipTestProjects + true + + + + true + + + + diff --git a/integration-test/projects/pmd-kotlin-rules/src/main/kotlin/com/example/KotlinErrors.kt b/integration-test/projects/pmd-kotlin-rules/src/main/kotlin/com/example/KotlinErrors.kt new file mode 100644 index 00000000..5d8881cd --- /dev/null +++ b/integration-test/projects/pmd-kotlin-rules/src/main/kotlin/com/example/KotlinErrors.kt @@ -0,0 +1,19 @@ +package com.example + +class KotlinErrors { + // This function name is too short, which will trigger the FunctionNameTooShort rule + fun fn() { + println("This function name is too short") + } +} + +// This class overrides equals but not hashCode, which will trigger the OverrideBothEqualsAndHashcode rule +class EqualsOnly { + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + return true + } + + // Missing hashCode() override +} \ No newline at end of file diff --git a/integration-test/projects/pmd-test-vs-main-rules/pom.xml b/integration-test/projects/pmd-test-vs-main-rules/pom.xml new file mode 100644 index 00000000..40695185 --- /dev/null +++ b/integration-test/projects/pmd-test-vs-main-rules/pom.xml @@ -0,0 +1,49 @@ + + 4.0.0 + + com.sonarsource.it.projects + pmd-test-vs-main-rules + 1.0-SNAPSHOT + + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 5.2.0.4988 + + + + + + + + junit + junit + 4.13.2 + test + + + + + 11 + 11 + + + + + skipSonar + + + skipTestProjects + true + + + + true + + + + diff --git a/integration-test/projects/pmd-test-vs-main-rules/src/main/java/ProductionCode.java b/integration-test/projects/pmd-test-vs-main-rules/src/main/java/ProductionCode.java new file mode 100644 index 00000000..c43c314d --- /dev/null +++ b/integration-test/projects/pmd-test-vs-main-rules/src/main/java/ProductionCode.java @@ -0,0 +1,8 @@ +public class ProductionCode { + private int unused; + private int used; + + public void makeTwoWhenOne() { + if (used == 1) used = 2; + } +} diff --git a/integration-test/projects/pmd-test-vs-main-rules/src/test/java/ProductionCodeTest.java b/integration-test/projects/pmd-test-vs-main-rules/src/test/java/ProductionCodeTest.java new file mode 100644 index 00000000..07701717 --- /dev/null +++ b/integration-test/projects/pmd-test-vs-main-rules/src/test/java/ProductionCodeTest.java @@ -0,0 +1,13 @@ +public class ProductionCodeTest extends junit.framework.TestCase { + private int unused; + + public void testProductionCode() { + unused = 1; + assertEquals(1, unused); + assertFalse(2 == unused); + } + + public void makeTwoWhenOne() { + if (unused == 1) unused = 2; + } +} diff --git a/integration-test/src/main/java/org/sonar/examples/pmd/MaximumMethodsCountCheck.java b/integration-test/src/main/java/org/sonar/examples/pmd/MaximumMethodsCountCheck.java index d144073d..753ffb31 100644 --- a/integration-test/src/main/java/org/sonar/examples/pmd/MaximumMethodsCountCheck.java +++ b/integration-test/src/main/java/org/sonar/examples/pmd/MaximumMethodsCountCheck.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin Integration Test - * Copyright (C) 2013-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin Integration Test + * Copyright (C) 2013-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,19 +22,20 @@ import java.util.List; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody; + +import net.sourceforge.pmd.lang.java.ast.ASTClassBody; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.properties.NumericConstraints; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.properties.PropertyFactory; -import net.sourceforge.pmd.properties.constraints.NumericConstraints; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; +import net.sourceforge.pmd.reporting.RuleContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class MaximumMethodsCountCheck extends AbstractJavaRule { - private static final Logger LOG = Loggers.get(MaximumMethodsCountCheck.class); + private static final Logger LOG = LoggerFactory.getLogger(MaximumMethodsCountCheck.class); private static final PropertyDescriptor propertyDescriptor = PropertyFactory.intProperty("maxAuthorisedMethodsCount") .desc("Maximum number of methods authorised") @@ -58,10 +59,10 @@ public void end(RuleContext ctx) { } @Override - public Object visit(ASTClassOrInterfaceBody node, Object data) { - List methods = node.findDescendantsOfType(ASTMethodDeclaration.class); + public Object visit(ASTClassBody node, Object data) { + List methods = node.descendants(ASTMethodDeclaration.class).toList(); if (methods.size() > getProperty(propertyDescriptor)) { - addViolation(data, node); + asCtx(data).addViolation(node); } return super.visit(node, data); } diff --git a/integration-test/src/main/java/org/sonar/examples/pmd/PmdExtensionPlugin.java b/integration-test/src/main/java/org/sonar/examples/pmd/PmdExtensionPlugin.java index 01356eb8..b66fba9a 100644 --- a/integration-test/src/main/java/org/sonar/examples/pmd/PmdExtensionPlugin.java +++ b/integration-test/src/main/java/org/sonar/examples/pmd/PmdExtensionPlugin.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin Integration Test - * Copyright (C) 2013-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin Integration Test + * Copyright (C) 2013-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/integration-test/src/main/java/org/sonar/examples/pmd/PmdExtensionRepository.java b/integration-test/src/main/java/org/sonar/examples/pmd/PmdExtensionRepository.java index 90fa64d1..4eb28706 100644 --- a/integration-test/src/main/java/org/sonar/examples/pmd/PmdExtensionRepository.java +++ b/integration-test/src/main/java/org/sonar/examples/pmd/PmdExtensionRepository.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin Integration Test - * Copyright (C) 2013-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin Integration Test + * Copyright (C) 2013-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -23,14 +23,15 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.api.server.rule.RulesDefinitionXmlLoader; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; +import org.sonar.plugins.pmd.rule.RulesDefinitionXmlLoader; + public class PmdExtensionRepository implements RulesDefinition { - private static final Logger LOGGER = Loggers.get(PmdExtensionRepository.class); + private static final Logger LOGGER = LoggerFactory.getLogger(PmdExtensionRepository.class); // Must be the same than the PMD plugin private static final String REPOSITORY_KEY = "pmd"; diff --git a/integration-test/src/main/resources/META-INF/sonar-pmd/scope-index.txt b/integration-test/src/main/resources/META-INF/sonar-pmd/scope-index.txt new file mode 100644 index 00000000..ebc0e775 --- /dev/null +++ b/integration-test/src/main/resources/META-INF/sonar-pmd/scope-index.txt @@ -0,0 +1,3 @@ +# List of classpath resources that define PMD rule scopes for this plugin +# One path per line; paths are resolved via ClassLoader.getResources +org/sonar/examples/pmd/extensions.xml diff --git a/integration-test/src/main/resources/META-INF/sonar-pmd/sonar-pmd-rules-paths.txt b/integration-test/src/main/resources/META-INF/sonar-pmd/sonar-pmd-rules-paths.txt new file mode 100644 index 00000000..8023be54 --- /dev/null +++ b/integration-test/src/main/resources/META-INF/sonar-pmd/sonar-pmd-rules-paths.txt @@ -0,0 +1,3 @@ +# List of classpath resources that define PMD rule xml files for this plugin +# One path per line; paths are resolved via ClassLoader.getResources +org/sonar/examples/pmd/extensions.xml diff --git a/integration-test/src/main/resources/org/sonar/examples/pmd/extensions.xml b/integration-test/src/main/resources/org/sonar/examples/pmd/extensions.xml index 19d2e078..b73ec5a9 100644 --- a/integration-test/src/main/resources/org/sonar/examples/pmd/extensions.xml +++ b/integration-test/src/main/resources/org/sonar/examples/pmd/extensions.xml @@ -29,9 +29,18 @@ Avoid if without using brace org/sonar/examples/pmd/rulesets.xml/AvoidIfWithoutBrace CRITICAL - Avoid if without using brace + Avoid if without using brace + main-sources + + AvoidIfWithoutBraceTest + Avoid if without using brace in test cases + org/sonar/examples/pmd/rulesets.xml/AvoidIfWithoutBraceTest + CRITICAL + Avoid if without using brace in test cases + tests + Avoid if without using brace @@ -43,6 +45,9 @@ ]]> + + + + + + Avoid if without using brace in test code + + + + + + + + + + + + + IOException should never be extended. Either use it, or extend Exception for your own business exceptions. @@ -64,7 +95,7 @@ diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/DefinedJavaVersion.java b/integration-test/src/test/java/com/sonar/it/java/suite/DefinedJavaVersion.java new file mode 100644 index 00000000..af5cd4d7 --- /dev/null +++ b/integration-test/src/test/java/com/sonar/it/java/suite/DefinedJavaVersion.java @@ -0,0 +1,138 @@ +package com.sonar.it.java.suite; + +import org.apache.commons.lang3.SystemProperties; +import org.apache.commons.lang3.math.NumberUtils; + +/** + * Provides the defined Java versions. + * Copied from org.apache.commons.lang3.JavaVersion which didn't keep up with the new Java releases. + * Adds the preview release compared to JavaVersion. + */ +public enum DefinedJavaVersion { + JAVA_1_8(1.8F, "1.8"), + /** @deprecated */ + @Deprecated + JAVA_1_9(9.0F, "9"), + JAVA_9(9.0F, "9"), + JAVA_10(10.0F, "10"), + JAVA_11(11.0F, "11"), + JAVA_12(12.0F, "12"), + JAVA_13(13.0F, "13"), + JAVA_14(14.0F, "14"), + JAVA_15(15.0F, "15"), + JAVA_16(16.0F, "16"), + JAVA_17(17.0F, "17"), + JAVA_18(18.0F, "18"), + JAVA_19(19.0F, "19"), + JAVA_20(20.0F, "20"), + JAVA_21(21.0F, "21"), + JAVA_22(22.0F, "22"), + JAVA_23(23.0F, "23"), + JAVA_24(24.0F, "24"), + JAVA_25(25.0F, "25"), + JAVA_25_PREVIEW(25.5F, "25-preview"), + JAVA_RECENT(maxVersion(), Float.toString(maxVersion())); + + private final float value; + private final String name; + + static DefinedJavaVersion get(String versionStr) { + if (versionStr == null) { + return null; + } else { + switch (versionStr) { + case "1.8": + return JAVA_1_8; + case "9": + return JAVA_9; + case "10": + return JAVA_10; + case "11": + return JAVA_11; + case "12": + return JAVA_12; + case "13": + return JAVA_13; + case "14": + return JAVA_14; + case "15": + return JAVA_15; + case "16": + return JAVA_16; + case "17": + return JAVA_17; + case "18": + return JAVA_18; + case "19": + return JAVA_19; + case "20": + return JAVA_20; + case "21": + return JAVA_21; + case "22": + return JAVA_22; + case "23": + return JAVA_23; + case "24": + return JAVA_24; + case "25": + return JAVA_25; + case "25-preview": + return JAVA_25_PREVIEW; + default: + float v = toFloatVersion(versionStr); + if ((double)v - (double)1.0F < (double)1.0F) { + int firstComma = Math.max(versionStr.indexOf(46), versionStr.indexOf(44)); + int end = Math.max(versionStr.length(), versionStr.indexOf(44, firstComma)); + if (Float.parseFloat(versionStr.substring(firstComma + 1, end)) > 0.9F) { + return JAVA_RECENT; + } + } else if (v > 10.0F) { + return JAVA_RECENT; + } + + return null; + } + } + } + + static DefinedJavaVersion getJavaVersion(String versionStr) { + return get(versionStr); + } + + private static float maxVersion() { + float v = toFloatVersion(SystemProperties.getJavaSpecificationVersion("99.0")); + return v > 0.0F ? v : 99.0F; + } + + static String[] split(String value) { + return value.split("\\."); + } + + private static float toFloatVersion(String value) { + if (!value.contains(".")) { + return NumberUtils.toFloat(value, -1.0F); + } else { + String[] toParse = split(value); + return toParse.length >= 2 ? NumberUtils.toFloat(toParse[0] + '.' + toParse[1], -1.0F) : -1.0F; + } + } + + DefinedJavaVersion(float value, String name) { + this.value = value; + this.name = name; + } + + public boolean atLeast(DefinedJavaVersion requiredVersion) { + return this.value >= requiredVersion.value; + } + + public boolean atMost(DefinedJavaVersion requiredVersion) { + return this.value <= requiredVersion.value; + } + + public String toString() { + return this.name; + } +} + diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java b/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java index acbce946..259e72a6 100644 --- a/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java +++ b/integration-test/src/test/java/com/sonar/it/java/suite/PmdIT.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin Integration Test - * Copyright (C) 2013-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin Integration Test + * Copyright (C) 2013-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,104 +19,187 @@ */ package com.sonar.it.java.suite; -import java.util.ArrayList; -import java.util.List; - import com.sonar.it.java.suite.orchestrator.PmdTestOrchestrator; import com.sonar.orchestrator.build.BuildResult; import com.sonar.orchestrator.build.MavenBuild; -import org.junit.jupiter.api.AfterEach; +import com.sonar.orchestrator.http.HttpException; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import org.sonar.wsclient.issue.Issue; import org.sonar.wsclient.issue.IssueQuery; +import java.util.List; +import java.util.Optional; +import java.util.function.Supplier; +import java.util.stream.Collectors; + import static com.sonar.it.java.suite.TestUtils.keyFor; -import static com.sonar.it.java.suite.TestUtils.keyForTest; import static org.assertj.core.api.Assertions.assertThat; class PmdIT { - private static final PmdTestOrchestrator ORCHESTRATOR = PmdTestOrchestrator.init(); + private static PmdTestOrchestrator ORCHESTRATOR; @BeforeAll static void startSonar() { + ORCHESTRATOR = PmdTestOrchestrator.init(); ORCHESTRATOR.start(); } - @AfterEach - void resetData() { - ORCHESTRATOR.resetData(); - } + @ParameterizedTest + //@EnumSource(value = DefinedJavaVersion.class, mode = EnumSource.Mode.INCLUDE, names = {"JAVA_1_8", "JAVA_17", "JAVA_21", "JAVA_25", "JAVA_25_PREVIEW"}) + @EnumSource(value = DefinedJavaVersion.class, mode = EnumSource.Mode.INCLUDE, names = {"JAVA_1_8", "JAVA_25_PREVIEW"}) + void testPmdExtensionsWithDifferentJavaVersions(DefinedJavaVersion version) { - @Test - void pmdExtensions() { + // given final String projectName = "pmd-extensions"; - MavenBuild build = MavenBuild.create(TestUtils.projectPom(projectName)) + final MavenBuild build = MavenBuild + .create(TestUtils.projectPom(projectName)) .setCleanSonarGoals() + .setProperty("maven.compiler.source", version.toString()) + .setProperty("maven.compiler.target", version.toString()) .setProperty("sonar.java.binaries", "."); - ORCHESTRATOR.associateProjectToQualityProfile(projectName, projectName); - final BuildResult buildResult = ORCHESTRATOR.executeBuild(build); - final String log = buildResult.getLogs(); + try { + ORCHESTRATOR.associateProjectToQualityProfile("pmd-extensions-profile", projectName); + + // when + final BuildResult buildResult = ORCHESTRATOR.executeBuild(build); - assertThat(log).contains("Start MaximumMethodsCountCheck"); - assertThat(log).contains("End MaximumMethodsCountCheck"); + // then + final String log = buildResult.getLogs(); + assertThat(log) + .contains("Start MaximumMethodsCountCheck") + .contains("End MaximumMethodsCountCheck"); - List issues = retrieveIssues(keyFor(projectName, "pmd/", "Errors")); - assertThat(issues).hasSize(3); - List messages = new ArrayList<>(); - for (Issue issue : issues) { - messages.add(issue.message()); + final List issues = retrieveIssues(keyFor(projectName, "src/main/java", "pmd", "Errors", ".java")); + + final List messages = issues + .stream() + .map(Issue::message) + .collect(Collectors.toList()); + + System.out.println("messages: " + messages); + + assertThat(issues) + .hasSize(3); + + assertThat(messages) + .containsOnly( + "Avoid too many methods", + "A catch statement should never catch throwable since it includes errors.", + "Avoid if without using brace" + ); + } catch (HttpException e) { + System.out.println("Failed to associate Project To Quality Profile: " + e.getMessage() + " body: " + e.getBody()); + throw e; + } finally { + // Cleanup + ORCHESTRATOR.resetData(projectName); } - assertThat(messages).containsOnly( - "Avoid too many methods", - "A catch statement should never catch throwable since it includes errors.", - "Avoid if without using brace"); } /** - * SONAR-3346 + * SONAR-1076 */ @Test - void testRuleAvoidDuplicateLiterals() { - final String projectName = "pmd-avoid-duplicate-literals"; - MavenBuild build = MavenBuild.create(TestUtils.projectPom(projectName)) + void testSourcesTestVsMainScopedRules() { + + // given + final String projectName = "pmd-test-vs-main-rules"; + final MavenBuild build = MavenBuild + .create(TestUtils.projectPom(projectName)) .setCleanSonarGoals(); - ORCHESTRATOR.associateProjectToQualityProfile("pmd", projectName); + ORCHESTRATOR.associateProjectToQualityProfile("pmd-test-rule-profile", projectName); + + // when ORCHESTRATOR.executeBuild(build); - List issues = ORCHESTRATOR.retrieveIssues( - IssueQuery.create() - .rules("pmd:AvoidDuplicateLiterals") - .components(keyFor(projectName, "", "AvoidDuplicateLiterals")) - ); - assertThat(issues).hasSize(1); - assertThat(issues.get(0).message()).contains("appears 5 times in this file"); + // then + // (component -> com.sonarsource.it.projects:pmd-test-vs-main-rules:src/test/java/ProductionCodeTest.java) + String testComponentKey = keyFor("pmd-test-vs-main-rules", "src/test/java", "", "ProductionCodeTest", ".java"); + final List testIssues = retrieveIssues(testComponentKey); + + int expectedTestIssuesCount = 2; + assertThat(testIssues) + .withFailMessage(printFailedIssueCountCheck(testIssues, expectedTestIssuesCount)) + .hasSize(expectedTestIssuesCount); + + Optional testIssue1 = testIssues.stream().filter(i -> i.ruleKey().equals("pmd:UnitTestContainsTooManyAsserts")).findFirst(); + assertThat(testIssue1).withFailMessage("expected sources test issue pmd:UnitTestContainsTooManyAsserts not found").isPresent(); + assertThat(testIssue1.get().message()).isEqualTo("Unit tests should not contain more than 1 assert(s)."); + + Optional testIssue2 = testIssues.stream().filter(i -> i.ruleKey().equals("pmd:AvoidIfWithoutBraceTest")).findFirst(); + assertThat(testIssue2).withFailMessage("expected source test only issue pmd:AvoidIfWithoutBraceTest not found").isPresent(); + + + // component -> com.sonarsource.it.projects:pmd-test-vs-main-rules:src/main/java/ProductionCode.java + final List prodIssues = retrieveIssues(keyFor(projectName, "src/main/java", "", "ProductionCode", ".java")); + + int expectedProdIssueCount = 2; + assertThat(prodIssues) + .withFailMessage(printFailedIssueCountCheck(prodIssues, expectedProdIssueCount)) + .hasSize(expectedProdIssueCount); + + Optional prodIssue1 = prodIssues.stream().filter(i -> i.ruleKey().equals("pmd:UnusedPrivateField")).findFirst(); + assertThat(prodIssue1).withFailMessage("expected sources main rule pmd:UnusedPrivateField not found").isPresent(); + assertThat(prodIssue1.get().message()).contains("Avoid unused private fields such as 'unused'."); + + Optional prodIssue2 = prodIssues.stream().filter(i -> i.ruleKey().equals("pmd:AvoidIfWithoutBrace")).findFirst(); + assertThat(prodIssue2).withFailMessage("expected sources main only issue pmd:AvoidIfWithoutBrace not found").isPresent(); + + // Cleanup + ORCHESTRATOR.resetData(projectName); + } + + private static @NotNull Supplier printFailedIssueCountCheck(List prodIssues, int expectedCount) { + String listOfIssueKeys = prodIssues.stream().map(Issue::ruleKey).collect(Collectors.joining(";")); + return () -> "Did not find " + expectedCount + " issues, but " + prodIssues.size() + ": " + listOfIssueKeys; } /** - * SONAR-1076 + * SONAR-3346 */ @Test - void testJunitRules() { - final String projectName = "pmd-junit-rules"; - MavenBuild build = MavenBuild.create(TestUtils.projectPom(projectName)) + void testRuleAvoidDuplicateLiterals() { + + // given + final String projectName = "pmd-avoid-duplicate-literals"; + final MavenBuild build = MavenBuild + .create(TestUtils.projectPom(projectName)) .setCleanSonarGoals(); - ORCHESTRATOR.associateProjectToQualityProfile("pmd-junit", projectName); - ORCHESTRATOR.executeBuild(build); + try { + ORCHESTRATOR.associateProjectToQualityProfile("pmd-backup-profile", projectName); + + // when + ORCHESTRATOR.executeBuild(build); + + // then + String avoidDuplicateLiteralsKey = keyFor(projectName, "src/main/java", "", "AvoidDuplicateLiterals", ".java"); + final List issues = ORCHESTRATOR.retrieveIssues( + IssueQuery.create() + .rules("pmd:AvoidDuplicateLiterals") + .components(avoidDuplicateLiteralsKey) + ); + + assertThat(issues) + .hasSize(1); - List testIssues = retrieveIssues(keyForTest()); - assertThat(testIssues).hasSize(1); - assertThat(testIssues.get(0).message()).matches("This class name ends with '?Test'? but contains no test cases"); - assertThat(testIssues.get(0).ruleKey()).isEqualTo("pmd-unit-tests:TestClassWithoutTestCases"); + assertThat(issues.get(0).message()) + .contains("appears 5 times in this file"); - List prodIssues = retrieveIssues(keyFor(projectName, "", "ProductionCode")); - assertThat(prodIssues).hasSize(1); - assertThat(prodIssues.get(0).message()).contains("Avoid unused private fields such as 'unused'."); - assertThat(prodIssues.get(0).ruleKey()).isEqualTo("pmd:UnusedPrivateField"); + } catch (HttpException e) { + System.out.println("Failed to associate Project To Quality Profile: " + e.getMessage() + " body: " + e.getBody()); + throw e; + } finally { + // Cleanup + ORCHESTRATOR.resetData(projectName); + } } /** @@ -124,27 +207,61 @@ void testJunitRules() { */ @Test void pmdShouldHaveAccessToExternalLibrariesInItsClasspath() { + + // given final String projectName = "pmd-extensions"; - MavenBuild build = MavenBuild.create(TestUtils.projectPom(projectName)) + final MavenBuild build = MavenBuild + .create(TestUtils.projectPom(projectName)) .setCleanPackageSonarGoals(); + try { + ORCHESTRATOR.associateProjectToQualityProfile("pmd-extensions-profile", projectName); - ORCHESTRATOR.associateProjectToQualityProfile(projectName, projectName); - ORCHESTRATOR.executeBuild(build); + // when + ORCHESTRATOR.executeBuild(build); - List issues = retrieveIssues(keyFor(projectName, "pmd/", "Bar")); - assertThat(issues).hasSize(1); + // then + // PMD7-MIGRATION: added to force one violation in pmdShouldHaveAccessToExternalLibrariesInItsClasspath: is this testing the correct thing? + final List issues = retrieveIssues(keyFor(projectName, "src/main/java/", "pmd/", "Errors", ".java")); + + assertThat(issues) + .hasSize(3); + + } catch (HttpException e) { + System.out.println("Failed to associate Project To Quality Profile: " + e.getMessage() + " body: " + e.getBody()); + throw e; + } finally { + // Cleanup + ORCHESTRATOR.resetData(projectName); + } } @Test void pmdShouldRunWithAllRulesEnabled() { + + // given final String projectName = "pmd-extensions"; - MavenBuild build = MavenBuild.create(TestUtils.projectPom(projectName)) + final MavenBuild build = MavenBuild + .create(TestUtils.projectPom(projectName)) .setCleanPackageSonarGoals(); + try { + ORCHESTRATOR.associateProjectToQualityProfile("pmd-all-rules-profile", projectName); - ORCHESTRATOR.associateProjectToQualityProfile("pmd-all-rules", projectName); - ORCHESTRATOR.executeBuild(build); - List issues = retrieveIssues(keyFor(projectName, "pmd/", "Bar")); - assertThat(issues).isNotEmpty(); + // when + ORCHESTRATOR.executeBuild(build); + + // then + final List issues = retrieveIssues(keyFor(projectName, "src/main/java", "pmd", "Bar", ".java")); + + assertThat(issues) + .isNotEmpty(); + + } catch (HttpException e) { + System.out.println("Failed to associate Project To Quality Profile: " + e.getMessage() + " body: " + e.getBody()); + throw e; + } finally { + // Cleanup + ORCHESTRATOR.resetData(projectName); + } } private List retrieveIssues(String componentKey) { diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/PmdKotlinIT.java b/integration-test/src/test/java/com/sonar/it/java/suite/PmdKotlinIT.java new file mode 100644 index 00000000..0ce6f891 --- /dev/null +++ b/integration-test/src/test/java/com/sonar/it/java/suite/PmdKotlinIT.java @@ -0,0 +1,128 @@ +/* + * SonarQube PMD7 Plugin Integration Test + * Copyright (C) 2013-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package com.sonar.it.java.suite; + +import com.sonar.it.java.suite.orchestrator.PmdTestOrchestrator; +import com.sonar.orchestrator.build.BuildResult; +import com.sonar.orchestrator.build.MavenBuild; +import com.sonar.orchestrator.http.HttpException; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.sonar.wsclient.issue.Issue; +import org.sonar.wsclient.issue.IssueQuery; + +import java.util.List; +import java.util.stream.Collectors; + +import static com.sonar.it.java.suite.TestUtils.keyFor; +import static org.assertj.core.api.Assertions.assertThat; + +class PmdKotlinIT { + + private static PmdTestOrchestrator orchestrator; + + @BeforeAll + static void startSonar() { + orchestrator = PmdTestOrchestrator.init(); + orchestrator.start(); + } + + @Test + void testKotlinRules() { + // given + final String projectName = "pmd-kotlin-rules"; + final String suffix = ".kt"; + final String srcDir = "src/main/kotlin"; + + final MavenBuild build = MavenBuild + .create(TestUtils.projectPom(projectName)) + .setCleanSonarGoals(); + + try { + orchestrator.associateProjectToQualityProfile("pmd-kotlin-profile", projectName, "kotlin"); + + // when + final BuildResult buildResult = orchestrator.executeBuild(build); + + // then + final String log = buildResult.getLogs(); + assertThat(log).contains("Kotlin"); + + final List issues = retrieveIssues(keyFor(projectName, srcDir, "com/example", "KotlinErrors", suffix)); + + final List messages = issues + .stream() + .map(Issue::message) + .collect(Collectors.toList()); + + assertThat(issues).hasSize(2); + + assertThat(messages) + .contains( + "Function names should have non-cryptic and clear names.", + "Ensure you override both equals() and hashCode()" + ); + } catch (HttpException e) { + System.out.println("Failed to associate Project To Quality Profile: " + e.getMessage() + " body: " + e.getBody()); + throw e; + } finally { + // Cleanup + orchestrator.resetData(projectName); + } + } + + @Test + void pmdKotlinShouldRunWithAllRulesEnabled() { + // given + final String projectName = "pmd-kotlin-rules"; + final MavenBuild build = MavenBuild + .create(TestUtils.projectPom(projectName)) + .setCleanPackageSonarGoals(); + try { + orchestrator.associateProjectToQualityProfile("pmd-kotlin-all-rules", projectName, "kotlin"); + + // when + final BuildResult buildResult = orchestrator.executeBuild(build); + + // then + final String log = buildResult.getLogs(); + assertThat(log).contains("Kotlin"); + + final List issues = retrieveIssues(keyFor(projectName, "src/main/kotlin", "com/example", "KotlinErrors", ".kt")); + + assertThat(issues).hasSize(2); + Issue functionNameTooShort = issues.stream().filter(i -> i.ruleKey().equals("pmd-kotlin:FunctionNameTooShort")).findFirst().orElseThrow(); + assertThat(functionNameTooShort.severity()).isEqualTo("MAJOR"); + + } catch (HttpException e) { + System.err.println("Failed to associate Project To Quality Profile: " + e.getMessage() + " body: " + e.getBody()); + throw e; + } finally { + // Cleanup + orchestrator.resetData(projectName); + } + } + + private List retrieveIssues(String componentKey) { + final IssueQuery issueQuery = IssueQuery.create(); + issueQuery.urlParams().put("componentKeys", componentKey); + return orchestrator.retrieveIssues(issueQuery); + } +} diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/SanitySonarVersionsIT.java b/integration-test/src/test/java/com/sonar/it/java/suite/SanitySonarVersionsIT.java new file mode 100644 index 00000000..a9693304 --- /dev/null +++ b/integration-test/src/test/java/com/sonar/it/java/suite/SanitySonarVersionsIT.java @@ -0,0 +1,117 @@ +/* + * SonarQube PMD7 Plugin Integration Test + */ +package com.sonar.it.java.suite; + +import com.sonar.it.java.suite.orchestrator.PmdTestOrchestrator; +import com.sonar.orchestrator.build.MavenBuild; +import com.sonar.orchestrator.build.BuildResult; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Sanity check that our integration test suite can start and run against both + * the lowest and highest supported SonarQube versions. + */ +class SanitySonarVersionsIT { + + private static final String SONAR_VERSION_KEY = "test.sonar.version"; + + @ParameterizedTest(name = "sanity on SonarQube {0}") + @Disabled("use the test with all rules enabled") + @ValueSource(strings = { + // Lowest supported SonarQube LTS line + "LATEST_RELEASE[9.9]", + // Highest supported SonarQube current line (see README table) + "LATEST_RELEASE[25.9]" + }) + void sanity_runs_on_lowest_and_highest_supported_versions(String sonarqubeVersion) { + final String previous = System.getProperty(SONAR_VERSION_KEY); + System.setProperty(SONAR_VERSION_KEY, sonarqubeVersion); + + PmdTestOrchestrator orchestrator = null; + try { + orchestrator = PmdTestOrchestrator.init(); + orchestrator.start(); + + final String projectName = "pmd-extensions"; + final MavenBuild build = MavenBuild + .create(TestUtils.projectPom(projectName)) + .setCleanSonarGoals() + // keep analysis minimal for sanity run + .setProperty("sonar.java.binaries", "."); + + orchestrator.associateProjectToQualityProfile("pmd-extensions-profile", projectName); + final BuildResult result = orchestrator.executeBuild(build); // will throw if analysis fails + assertThat(result.getLogs()).contains("[INFO] Sensor PmdSensor [pmd]"); + + // Additionally run a minimal Kotlin project analysis to ensure Kotlin support works + final String kotlinProject = "pmd-kotlin-rules"; + final MavenBuild kotlinBuild = MavenBuild + .create(TestUtils.projectPom(kotlinProject)) + .setCleanSonarGoals(); + orchestrator.associateProjectToQualityProfile("pmd-kotlin-profile", kotlinProject, "kotlin"); + final BuildResult kotlinResult = orchestrator.executeBuild(kotlinBuild); + assertThat(kotlinResult.getLogs()).contains("[INFO] Sensor PmdSensor [pmd]"); + } + finally { + // restore previous property to not affect other tests + if (previous != null) { + System.setProperty(SONAR_VERSION_KEY, previous); + } else { + System.clearProperty(SONAR_VERSION_KEY); + } + if (orchestrator != null) { + try { + orchestrator.stop(); + } catch (Throwable ignored) { + // ignore + } + } + } + } + + @ParameterizedTest(name = "sanity-all-rules on SonarQube {0}") + @ValueSource(strings = { + "LATEST_RELEASE[9.9]", + "LATEST_RELEASE[25.9]" + }) + void sanity_runs_with_all_rules_profile(String sonarqubeVersion) { + final String previous = System.getProperty(SONAR_VERSION_KEY); + System.setProperty(SONAR_VERSION_KEY, sonarqubeVersion); + + PmdTestOrchestrator orchestrator = null; + try { + orchestrator = PmdTestOrchestrator.init(); + orchestrator.start(); + + final String projectName = "pmd-extensions"; + final MavenBuild build = MavenBuild + .create(TestUtils.projectPom(projectName)) + .setCleanSonarGoals() + // keep analysis minimal for sanity run + .setProperty("sonar.java.binaries", "."); + + // Use the profile that enables all PMD rules + orchestrator.associateProjectToQualityProfile("pmd-all-rules-profile", projectName); + final BuildResult result = orchestrator.executeBuild(build); + assertThat(result.getLogs()).contains("[INFO] Sensor PmdSensor [pmd]"); + } finally { + if (previous != null) { + System.setProperty(SONAR_VERSION_KEY, previous); + } else { + System.clearProperty(SONAR_VERSION_KEY); + } + if (orchestrator != null) { + try { + orchestrator.stop(); + } catch (Throwable ignored) { + // ignore + } + } + } + } +} diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/TestUtils.java b/integration-test/src/test/java/com/sonar/it/java/suite/TestUtils.java index 2e528d56..a003069e 100644 --- a/integration-test/src/test/java/com/sonar/it/java/suite/TestUtils.java +++ b/integration-test/src/test/java/com/sonar/it/java/suite/TestUtils.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin Integration Test - * Copyright (C) 2013-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin Integration Test + * Copyright (C) 2013-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,6 +22,7 @@ import java.io.File; import org.apache.commons.io.FileUtils; +import org.jetbrains.annotations.NotNull; class TestUtils { @@ -40,16 +41,28 @@ static File projectPom(String projectName) { return new File(HOME, "projects/" + projectName + "/pom.xml"); } + static String keyFor(String projectKey) { + return "com.sonarsource.it.projects:" + projectKey; + } + static String keyFor(String projectKey, String srcDir, String pkgDir, String cls) { - return "com.sonarsource.it.projects:" + projectKey + ":" + srcDir + pkgDir + cls; + srcDir = ensureEndsWithSlash(srcDir); + pkgDir = ensureEndsWithSlash(pkgDir); + return keyFor(projectKey) + ":" + srcDir + pkgDir + cls; } - static String keyFor(String projectKey, String pkgDir, String cls) { - return keyFor(projectKey, "src/main/java/", pkgDir, cls + ".java"); + private static @NotNull String ensureEndsWithSlash(String srcDir) { + if (!srcDir.isEmpty() && !srcDir.endsWith("/")) { + srcDir = srcDir + "/"; + } + return srcDir; } - static String keyForTest() { - return keyFor("pmd-junit-rules", "src/test/java/", "", "ProductionCodeTest" + ".java"); + static String keyFor(String projectKey, String srcDir, String pkgDir, String cls, String suffix) { + if (!suffix.isEmpty() && !suffix.startsWith(".")) { + suffix = "." + suffix; + } + return keyFor(projectKey, srcDir, pkgDir, cls + suffix); } } diff --git a/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java b/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java index 68a5900e..cb7e1664 100644 --- a/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java +++ b/integration-test/src/test/java/com/sonar/it/java/suite/orchestrator/PmdTestOrchestrator.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin Integration Test - * Copyright (C) 2013-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin Integration Test + * Copyright (C) 2013-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,17 +19,17 @@ */ package com.sonar.it.java.suite.orchestrator; -import java.io.File; -import java.util.List; - -import com.sonar.orchestrator.Orchestrator; import com.sonar.orchestrator.build.BuildResult; import com.sonar.orchestrator.build.MavenBuild; +import com.sonar.orchestrator.junit4.OrchestratorRule; import com.sonar.orchestrator.locator.MavenLocation; import org.sonar.wsclient.SonarClient; import org.sonar.wsclient.issue.Issue; import org.sonar.wsclient.issue.IssueQuery; +import java.io.File; +import java.util.List; + import static com.sonar.orchestrator.container.Server.ADMIN_LOGIN; import static com.sonar.orchestrator.container.Server.ADMIN_PASSWORD; import static com.sonar.orchestrator.locator.FileLocation.byWildcardMavenFilename; @@ -41,30 +41,59 @@ public class PmdTestOrchestrator { private static final String SONAR_JAVA_PLUGIN_VERSION_KEY = "test.sonar.plugin.version.java"; + private static final String SONAR_KOTLIN_PLUGIN_VERSION_KEY = "test.sonar.plugin.version.kotlin"; private static final String SONAR_VERSION_KEY = "test.sonar.version"; private static final String LANGUAGE_KEY = "java"; + private static final String CENTRAL_MAVEN = "https://repo1.maven.org/maven2"; + + static { + // override jfrog as artifactory because it now doesn't have anonymous login anymore + // don't rely on configuration file, less dependencies + // issue see https://community.sonarsource.com/t/orchestrator-adding-support-for-downloading-artifacts-without-jfrog/108867 + if (System.getProperty("orchestrator.artifactory.url") == null) { + System.setProperty("orchestrator.artifactory.url", CENTRAL_MAVEN); + } + System.out.println("NOTICE: Make sure to run './mvnw clean install -DskipTests' before running integration tests to ensure all new changes are available in the test"); + } + private final OrchestratorRule delegate; - private final Orchestrator delegate; - - private PmdTestOrchestrator(Orchestrator delegate) { + private PmdTestOrchestrator(OrchestratorRule delegate) { this.delegate = delegate; } - public void resetData() { - SonarClient client = SonarClient.builder() + public void resetData(String project) { + SonarClient + .builder() .url(delegate.getServer().getUrl()) .login(ADMIN_LOGIN) .password(ADMIN_PASSWORD) .connectTimeoutMilliseconds(300_000) - .readTimeoutMilliseconds(600_000).build(); - client.post("/api/orchestrator/reset"); + .readTimeoutMilliseconds(600_000) + .build() + .post("/api/projects/delete?project=" + deriveProjectKey(project)); } public void start() { delegate.start(); } + public void stop() { + try { + // OrchestratorRule typically exposes stop(); if not, close() will be called by JUnit rule, but here we drive it manually. + delegate.stop(); + } catch (Throwable t) { + // ignore stop failures to avoid masking test results + System.out.println("WARN: Failed to stop orchestrator cleanly: " + t.getMessage()); + } + } + public BuildResult executeBuild(MavenBuild build) { + // use this to enable debug: build.setDebugLogs(true) + // avoid this: [DEBUG] Plugins not loaded because they are optional: [java, pmd] + // and the following: Cannot invoke "org.sonar.core.platform.ExplodedPlugin.getPluginInfo()" because the return value of "java.util.Map.get(Object)" is null + // sonar.plugins.downloadOnlyRequired turned to default "true" in SonarQube 10.5": https://sonarsource.atlassian.net/browse/SONAR-22074 + // update: fixed by specifying required plugins in the plugin manifests! + // use this to override: build.setProperty("sonar.plugins.downloadOnlyRequired", "false") return delegate.executeBuild(build); } @@ -76,36 +105,62 @@ public List retrieveIssues(IssueQuery query) { } public void associateProjectToQualityProfile(String profile, String project) { - final String projectKey = String.format("com.sonarsource.it.projects:%s", project); + associateProjectToQualityProfile(profile, project, LANGUAGE_KEY); + } + + public void associateProjectToQualityProfile(String profile, String project, String language) { + final String projectKey = deriveProjectKey(project); delegate.getServer().provisionProject(projectKey, project); - delegate.getServer().associateProjectToQualityProfile(projectKey, LANGUAGE_KEY, profile); + delegate.getServer().associateProjectToQualityProfile(projectKey, language, profile); } public static PmdTestOrchestrator init() { - final Orchestrator build = Orchestrator - .builderEnv() - .setSonarVersion(determineSonarqubeVersion()) - .addPlugin(MavenLocation.create( - "org.sonarsource.java", - "sonar-java-plugin", - determineJavaPluginVersion() - )) - .addPlugin(byWildcardMavenFilename(new File("../sonar-pmd-plugin/target"), "sonar-pmd-plugin-*.jar")) - .addPlugin(byWildcardMavenFilename(new File("./target"), "integration-test-*.jar")) - .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-junit-rules.xml")) - .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-extensions-profile.xml")) - .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-backup.xml")) - .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-all-rules.xml")) - .build(); - - return new PmdTestOrchestrator(build); + try { + final OrchestratorRule orchestrator = OrchestratorRule + .builderEnv() + .useDefaultAdminCredentialsForBuilds(true) + .setSonarVersion(determineSonarqubeVersion()) + .addPlugin(MavenLocation.create( + "org.sonarsource.java", + "sonar-java-plugin", + determineJavaPluginVersion() + )) + .addPlugin(MavenLocation.create( + "org.sonarsource.kotlin", + "sonar-kotlin-plugin", + determineKotlinPluginVersion() + )) + .addPlugin(byWildcardMavenFilename(new File("../sonar-pmd-plugin/target"), "sonar-pmd-plugin-*.jar")) + .addPlugin(byWildcardMavenFilename(new File("./target"), "integration-test-*.jar")) + .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-extensions-profile.xml")) + .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-backup.xml")) + .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-all-rules.xml")) + .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-test-rule.xml")) + .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-kotlin-profile.xml")) + .restoreProfileAtStartup(ofClasspath("/com/sonar/it/java/PmdTest/pmd-kotlin-all-rules.xml")) + .build(); + + return new PmdTestOrchestrator(orchestrator); + } + catch(Exception e) { + System.out.println("ERROR: " + e); + throw new RuntimeException(e); + } + } + + private static String deriveProjectKey(String projectName) { + return String.format("com.sonarsource.it.projects:%s", projectName); } private static String determineJavaPluginVersion() { - return System.getProperty(SONAR_JAVA_PLUGIN_VERSION_KEY, "DEV"); + return System.getProperty(SONAR_JAVA_PLUGIN_VERSION_KEY, "LATEST_RELEASE[8.9]"); // use 8.9 to test with SQ 9.9 + } + + private static String determineKotlinPluginVersion() { + return System.getProperty(SONAR_KOTLIN_PLUGIN_VERSION_KEY, "LATEST_RELEASE[2.23]"); } private static String determineSonarqubeVersion() { - return System.getProperty(SONAR_VERSION_KEY, "LATEST_RELEASE[6.7]"); + return System.getProperty(SONAR_VERSION_KEY, "LATEST_RELEASE[25.3]"); // use SQ 9.9.4 to test with old version } } diff --git a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-all-rules.xml b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-all-rules.xml index 99dbbdf0..4a43310e 100644 --- a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-all-rules.xml +++ b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-all-rules.xml @@ -1,132 +1,175 @@ - pmd-all-rules + pmd-all-rules-profile java pmd AbstractClassWithoutAbstractMethod MAJOR - + pmd AbstractClassWithoutAnyMethod - MAJOR - + BLOCKER + pmd - AbstractNaming + AccessorClassGeneration MAJOR - - - strict - true - - + pmd - AccessorClassGeneration + AccessorMethodGeneration MAJOR - + pmd AddEmptyString MAJOR - + pmd AppendCharacterWithChar - MINOR - + MAJOR + pmd ArrayIsStoredDirectly - CRITICAL - + MAJOR + + + allowPrivate + true + + pmd AssignmentInOperand MAJOR - + + + allowIf + false + + + allowFor + false + + + allowWhile + false + + + allowIncrementDecrement + false + + + allowDoWhile + false + + + allowSwitch + false + + pmd AssignmentToNonFinalStatic MAJOR - + pmd AtLeastOneConstructor - MAJOR - + MINOR + + + ignoredAnnotations + lombok.Data,lombok.Value,lombok.Builder,lombok.NoArgsConstructor,lombok.RequiredArgsConstructor,lombok.AllArgsConstructor + + pmd AvoidAccessibilityAlteration MAJOR - + pmd AvoidArrayLoops MAJOR - + pmd AvoidAssertAsIdentifier - MAJOR - + CRITICAL + pmd AvoidBranchingStatementAsLastInLoop + CRITICAL + + + checkBreakLoopTypes + for,do,while + + + checkContinueLoopTypes + for,do,while + + + checkReturnLoopTypes + for,do,while + + + + + pmd + AvoidCalendarDateCreation MAJOR - + pmd AvoidCallingFinalize MAJOR - + pmd AvoidCatchingGenericException MAJOR - + pmd AvoidCatchingNPE MAJOR - + pmd AvoidCatchingThrowable - CRITICAL - - - - pmd - AvoidConstantsInterface MAJOR - + pmd AvoidDecimalLiteralsInBigDecimalConstructor MAJOR - + pmd @@ -143,7 +186,7 @@ pmd AvoidDollarSigns MINOR - + pmd @@ -154,145 +197,183 @@ maxDuplicateLiterals 4 - - skipAnnotations - false - minimumLength 3 - separator - , + skipAnnotations + false pmd AvoidEnumAsIdentifier - MAJOR - + CRITICAL + pmd AvoidFieldNameMatchingMethodName MAJOR - + pmd AvoidFieldNameMatchingTypeName MAJOR - + pmd - AvoidFinalLocalVariable - MAJOR - + AvoidFileStream + BLOCKER + pmd AvoidInstanceofChecksInCatchClause - MINOR - + MAJOR + pmd AvoidInstantiatingObjectsInLoops - MINOR - + MAJOR + pmd AvoidLiteralsInIfCondition MAJOR - + + + ignoreMagicNumbers + -1,0 + + + ignoreExpressions + true + + pmd AvoidLosingExceptionInformation - MAJOR - + CRITICAL + pmd - AvoidMultipleUnaryOperators + AvoidMessageDigestField MAJOR - + pmd - AvoidPrefixingMethodParameters - MAJOR - + AvoidMultipleUnaryOperators + CRITICAL + pmd AvoidPrintStackTrace MAJOR - + pmd AvoidProtectedFieldInFinalClass - MAJOR - + MINOR + pmd AvoidProtectedMethodInFinalClassNotExtending + MINOR + + + + pmd + AvoidReassigningCatchVariables MAJOR - + pmd - AvoidReassigningParameters + AvoidReassigningLoopVariables MAJOR - + + + foreachReassign + deny + + + forReassign + deny + + + + + pmd + AvoidReassigningParameters + CRITICAL + pmd AvoidRethrowingException MAJOR - + pmd AvoidStringBufferField MAJOR - + pmd AvoidSynchronizedAtMethodLevel MAJOR - + + + + pmd + AvoidSynchronizedStatement + MAJOR + pmd AvoidThreadGroup - CRITICAL - + MAJOR + pmd AvoidThrowingNewInstanceOfSameException MAJOR - + pmd AvoidThrowingNullPointerException - MAJOR - + BLOCKER + pmd AvoidThrowingRawExceptionTypes + BLOCKER + + + + pmd + AvoidUncheckedExceptionsInSignatures MAJOR - + pmd @@ -301,7 +382,7 @@ checkAddressTypes - IPv4|IPv6|IPv4 mapped IPv6 + IPv4,IPv6,IPv4 mapped IPv6 @@ -309,48 +390,35 @@ pmd AvoidUsingNativeCode MAJOR - + pmd AvoidUsingOctalValues MAJOR - - - - pmd - AvoidUsingShortType - MAJOR - + + + strict + false + + pmd AvoidUsingVolatile - MAJOR - - - - pmd - BadComparison - MAJOR - - - - pmd - BeanMembersShouldSerialize - MAJOR - + CRITICAL + pmd BigIntegerInstantiation MAJOR - + pmd BooleanGetMethodName - MAJOR + MINOR checkParameterizedMethods @@ -358,190 +426,338 @@ - - pmd - BooleanInstantiation - MAJOR - - pmd BrokenNullCheck CRITICAL - - - - pmd - ByteInstantiation - MAJOR - + pmd CallSuperFirst MAJOR - + pmd CallSuperInConstructor MINOR - + pmd CallSuperLast MAJOR - + pmd CheckResultSet MAJOR - + pmd CheckSkipResult - MINOR - + MAJOR + pmd ClassCastExceptionWithToArray MAJOR - + pmd ClassNamingConventions MAJOR - + + + classPattern + [A-Z][a-zA-Z0-9]* + + + abstractClassPattern + [A-Z][a-zA-Z0-9]* + + + interfacePattern + [A-Z][a-zA-Z0-9]* + + + enumPattern + [A-Z][a-zA-Z0-9]* + + + annotationPattern + [A-Z][a-zA-Z0-9]* + + + utilityClassPattern + [A-Z][a-zA-Z0-9]* + + + testClassPattern + ^Test.*$|^[A-Z][a-zA-Z0-9]*Test(s|Case)?$ + + pmd ClassWithOnlyPrivateConstructorsShouldBeFinal - MAJOR - + BLOCKER + pmd CloneMethodMustBePublic MAJOR - + pmd CloneMethodMustImplementCloneable MAJOR - - - - pmd - CloneMethodMustImplementCloneableWithTypeResolution - MAJOR - + pmd CloneMethodReturnTypeMustMatchClassName MAJOR - - - - pmd - CloneThrowsCloneNotSupportedException - MAJOR - + pmd CloseResource - CRITICAL + MAJOR types - Connection,Statement,ResultSet + java.lang.AutoCloseable,java.sql.Connection,java.sql.Statement,java.sql.ResultSet + + + closeAsDefaultTarget + true + + + allowedResourceTypes + java.io.ByteArrayOutputStream,java.io.ByteArrayInputStream,java.io.StringWriter,java.io.CharArrayWriter,java.util.stream.Stream,java.util.stream.IntStream,java.util.stream.LongStream,java.util.stream.DoubleStream + + + closeNotInFinally + false + + + + pmd + CognitiveComplexity + MAJOR + - closeTargets - close + reportLevel + 15 pmd CollapsibleIfStatements - MINOR - + MAJOR + pmd - CommentContent - MINOR - + CollectionTypeMismatch + MAJOR + pmd - CommentDefaultAccessModifier + CommentContent MAJOR - + + + forbiddenRegex + idiot|jerk + + pmd - CommentRequired + CommentDefaultAccessModifier MINOR - + + + ignoredAnnotations + android.support.annotation.VisibleForTesting,co.elastic.clients.util.VisibleForTesting,com.google.common.annotations.VisibleForTesting,org.junit.jupiter.api.AfterAll,org.junit.jupiter.api.AfterEach,org.junit.jupiter.api.BeforeAll,org.junit.jupiter.api.BeforeEach,org.junit.jupiter.api.RepeatedTest,org.junit.jupiter.api.Test,org.junit.jupiter.api.TestFactory,org.junit.jupiter.api.TestTemplate,org.junit.jupiter.api.extension.RegisterExtension,org.junit.jupiter.params.ParameterizedTest,org.testng.annotations.AfterClass,org.testng.annotations.AfterGroups,org.testng.annotations.AfterMethod,org.testng.annotations.AfterSuite,org.testng.annotations.AfterTest,org.testng.annotations.BeforeClass,org.testng.annotations.BeforeGroups,org.testng.annotations.BeforeMethod,org.testng.annotations.BeforeSuite,org.testng.annotations.BeforeTest,org.testng.annotations.Test + + + regex + \/\*\s*(default|package)\s*\*\/ + + + checkTopLevelTypes + false + + pmd - CommentSize - MINOR + CommentRequired + MAJOR - maxLineLength - 80 + methodWithOverrideCommentRequirement + Ignored + + accessorCommentRequirement + Ignored + + + classCommentRequirement + Required + + + fieldCommentRequirement + Required + + + publicMethodCommentRequirement + Required + + + protectedMethodCommentRequirement + Required + + + enumCommentRequirement + Required + + + serialVersionUIDCommentRequired + Ignored + + + serialPersistentFieldsCommentRequired + Ignored + + + + + pmd + CommentSize + MAJOR + maxLines 6 + + maxLineLength + 80 + pmd CompareObjectsWithEquals MAJOR - + pmd - ConfusingTernary + ComparisonWithNaN MAJOR - + pmd - ConsecutiveAppendsShouldReuse + ConfusingArgumentToVarargsMethod MAJOR - + pmd - ConsecutiveLiteralAppends + ConfusingTernary MINOR - threshold + ignoreElseIf + false + + + + + pmd + ConsecutiveAppendsShouldReuse + MAJOR + + + + pmd + ConsecutiveLiteralAppends + MAJOR + + + threshold 1 pmd - ConstructorCallsOverridableMethod + ConstantsInInterface MAJOR - + + + ignoreIfHasMethods + true + + + + + pmd + ConstructorCallsOverridableMethod + BLOCKER + + + + pmd + ControlStatementBraces + MINOR + + + checkIfElseStmt + true + + + checkSingleIfStmt + true + + + checkWhileStmt + true + + + checkForStmt + true + + + checkDoWhileStmt + true + + + checkCaseStmt + false + + + allowEmptyLoop + false + + pmd @@ -571,208 +787,149 @@ pmd - DataflowAnomalyAnalysis + DanglingJavadoc MAJOR - - - maxViolations - 100 - - - maxPaths - 1000 - - + pmd - DefaultLabelNotLastInSwitchStmt + DataClass MAJOR - + pmd - DefaultPackage - MINOR - + DefaultLabelNotLastInSwitch + MAJOR + + + + pmd + DetachedTestCase + MAJOR + pmd DoNotCallGarbageCollectionExplicitly CRITICAL - + pmd - DoNotCallSystemExit + DoNotExtendJavaLangError MAJOR - + pmd - DoNotExtendJavaLangError + DoNotExtendJavaLangThrowable MAJOR - + pmd DoNotHardCodeSDCard MAJOR - + pmd - DoNotThrowExceptionInFinally + DoNotTerminateVM MAJOR - + pmd - DoNotUseThreads - MAJOR - + DoNotThrowExceptionInFinally + MINOR + pmd - DontCallThreadRun + DoNotUseThreads MAJOR - + pmd - DontImportJavaLang + DontCallThreadRun MINOR - + pmd DontImportSun MINOR - + pmd DontUseFloatTypeForLoopIndices MAJOR - + pmd - DoubleCheckedLocking + DoubleBraceInitialization MAJOR - + pmd - DuplicateImports - MINOR - + DoubleCheckedLocking + BLOCKER + pmd EmptyCatchBlock - CRITICAL + MAJOR allowCommentedBlocks false + + allowExceptionNameRegex + ^(ignored|expected)$ + pmd - EmptyFinalizer - MAJOR - - - - pmd - EmptyFinallyBlock - CRITICAL - - - - pmd - EmptyIfStmt - CRITICAL - + EmptyControlStatement + MINOR + + + allowCommentedBlocks + false + + pmd - EmptyInitializer + EmptyFinalizer MAJOR - + pmd EmptyMethodInAbstractClassShouldBeAbstract MAJOR - - - - pmd - EmptyStatementBlock - MAJOR - - - - pmd - EmptyStatementNotInLoop - MAJOR - - - - pmd - EmptyStaticInitializer - MAJOR - - - - pmd - EmptySwitchStatements - MAJOR - - - - pmd - EmptySynchronizedBlock - CRITICAL - - - - pmd - EmptyTryBlock - MAJOR - - - - pmd - EmptyWhileStmt - CRITICAL - + pmd EqualsNull - CRITICAL - + BLOCKER + pmd ExceptionAsFlowControl MAJOR - - - - pmd - ExcessiveClassLength - MAJOR - - - minimum - 1000 - - + pmd @@ -785,17 +942,6 @@ - - pmd - ExcessiveMethodLength - MAJOR - - - minimum - 100 - - - pmd ExcessiveParameterList @@ -818,11 +964,17 @@ + + pmd + ExhaustiveSwitchHasDefault + MAJOR + + pmd ExtendsObject MINOR - + pmd @@ -830,308 +982,551 @@ MINOR - ignoreEnumDeclarations + ignoreAnonymousClassDeclarations true - ignoreAnonymousClassDeclarations + ignoreInterfaceDeclarations + false + + + ignoreEnumDeclarations true + + pmd + FieldNamingConventions + MAJOR + + + publicConstantPattern + [A-Z][A-Z_0-9]* + + + constantPattern + [A-Z][A-Z_0-9]* + + + enumConstantPattern + [A-Z][A-Z_0-9]* + + + finalFieldPattern + [a-z][a-zA-Z0-9]* + + + staticFieldPattern + [a-z][a-zA-Z0-9]* + + + defaultFieldPattern + [a-z][a-zA-Z0-9]* + + + exclusions + serialVersionUID,serialPersistentFields + + + pmd FinalFieldCouldBeStatic - MINOR - + MAJOR + + + + pmd + FinalParameterInAbstractMethod + MAJOR + pmd FinalizeDoesNotCallSuperFinalize MAJOR - + pmd FinalizeOnlyCallsSuperFinalize MAJOR - + pmd FinalizeOverloaded MAJOR - + pmd FinalizeShouldBeProtected MAJOR - + + + + pmd + ForLoopCanBeForeach + MAJOR + pmd ForLoopShouldBeWhileLoop MINOR - + pmd - ForLoopsMustUseBraces + ForLoopVariableCount MAJOR - + + + maximumVariables + 1 + + pmd - GenericsNaming + FormalParameterNamingConventions MAJOR - + + + methodParameterPattern + [a-z][a-zA-Z0-9]* + + + finalMethodParameterPattern + [a-z][a-zA-Z0-9]* + + + lambdaParameterPattern + [a-z][a-zA-Z0-9]* + + + explicitLambdaParameterPattern + [a-z][a-zA-Z0-9]* + + pmd - GodClass - MAJOR - + GenericsNaming + MINOR + pmd - GuardDebugLogging + GodClass MAJOR - + pmd GuardLogStatement - MAJOR - + CRITICAL + + + logLevels + trace,debug,info,warn,error,log,finest,finer,fine,info,warning,severe + + + guardsMethods + isTraceEnabled,isDebugEnabled,isInfoEnabled,isWarnEnabled,isErrorEnabled,isLoggable + + pmd - GuardLogStatementJavaUtil + HardCodedCryptoKey MAJOR - + pmd IdempotentOperations MAJOR - + pmd - IfElseStmtsMustUseBraces - MAJOR - + IdenticalCatchBranches + MINOR + pmd - IfStmtsMustUseBraces + ImmutableField MAJOR - + pmd - ImmutableField - MAJOR - + ImplicitFunctionalInterface + CRITICAL + pmd - ImportFromSamePackage - MINOR - + ImplicitSwitchFallThrough + MAJOR + pmd InefficientEmptyStringCheck MAJOR - + pmd InefficientStringBuffering MAJOR - + pmd - InstantiationToGetClass + InsecureCryptoIv MAJOR - + + + + pmd + InstantiationToGetClass + MINOR + pmd InsufficientStringBufferDeclaration MAJOR - + pmd - IntegerInstantiation + InvalidJavaBean MAJOR - + + + ensureSerialization + false + + + packages + org.example.beans + + pmd - JumbledIncrementer - MAJOR - + InvalidLogMessageFormat + MINOR + pmd - LawOfDemeter + JUnit4SuitesShouldUseSuiteAnnotation MAJOR - + pmd - LocalHomeNamingConvention + JUnit5TestShouldBePackagePrivate MAJOR - + pmd - LocalInterfaceSessionNamingConvention + JUnitSpelling MAJOR - + pmd - LocalVariableCouldBeFinal - MINOR - + JUnitStaticSuite + MAJOR + pmd - LoggerIsNotStaticFinal + JUnitUseExpected MAJOR - + pmd - LogicInversion - MINOR - + JumbledIncrementer + MAJOR + + + + pmd + LambdaCanBeMethodReference + MINOR + + + ignoreIfMayNPE + false + + + ignoreIfReceiverIsMethod + true + + pmd - LongInstantiation + LawOfDemeter MAJOR - + + + trustRadius + 1 + + pmd - LongVariable + LinguisticNaming + MINOR + + + ignoredAnnotations + java.lang.Override + + + checkBooleanMethod + true + + + checkGetters + true + + + checkSetters + true + + + checkPrefixedTransformMethods + true + + + checkTransformMethods + false + + + booleanMethodPrefixes + is,has,can,have,will,should + + + transformMethodNames + to,as + + + checkFields + true + + + checkVariables + true + + + booleanFieldPrefixes + is,has,can,have,will,should + + + + + pmd + LiteralsFirstInComparisons + MAJOR + + + + pmd + LocalHomeNamingConvention + MINOR + + + + pmd + LocalInterfaceSessionNamingConvention + MINOR + + + + pmd + LocalVariableCouldBeFinal + MINOR + + + ignoreForEachDecl + false + + + + + pmd + LocalVariableNamingConventions MAJOR - minimum - 17 + localVarPattern + [a-z][a-zA-Z0-9]* + + + finalVarPattern + [a-z][a-zA-Z0-9]* + + + catchParameterPattern + [a-z][a-zA-Z0-9]* pmd - LooseCoupling + LogicInversion MAJOR - + + + + pmd + LongVariable + MINOR + + + minimum + 17 + + pmd - LooseCouplingWithTypeResolution + LooseCoupling MAJOR - + + + allowedTypes + java.util.Properties + + pmd LoosePackageCoupling MAJOR - + pmd MDBAndSessionBeanNamingConvention - MAJOR - + MINOR + pmd MethodArgumentCouldBeFinal MINOR - + pmd MethodNamingConventions MAJOR - + + + methodPattern + [a-z][a-zA-Z0-9]* + + + staticPattern + [a-z][a-zA-Z0-9]* + + + nativePattern + [a-z][a-zA-Z0-9]* + + + junit3TestPattern + test[A-Z0-9][a-zA-Z0-9]* + + + junit4TestPattern + [a-z][a-zA-Z0-9]* + + + junit5TestPattern + [a-z][a-zA-Z0-9]* + + pmd MethodReturnsInternalArray - CRITICAL - - - - pmd - MethodWithSameNameAsEnclosingClass MAJOR - + pmd - MisleadingVariableName + MethodWithSameNameAsEnclosingClass MAJOR - + pmd MisplacedNullCheck - CRITICAL - + MAJOR + pmd - MissingBreakInSwitch - CRITICAL - + MissingOverride + MAJOR + pmd MissingSerialVersionUID MAJOR - + pmd MissingStaticMethodInNonInstantiatableClass MAJOR - + + + annotations + org.springframework.beans.factory.annotation.Autowired,javax.inject.Inject,com.google.inject.Inject,lombok.Builder + + pmd - ModifiedCyclomaticComplexity + ModifierOrder MAJOR - showMethodsComplexity - true - - - reportLevel - 10 - - - showClassesComplexity - true + typeAnnotations + anywhere pmd MoreThanOneLogger + CRITICAL + + + + pmd + MutableStaticState MAJOR - + pmd @@ -1139,142 +1534,146 @@ MAJOR - minimum + reportLevel 200 pmd - NcssConstructorCount + NcssCount MAJOR - minimum - 100 + methodReportLevel + 60 + + + classReportLevel + 1500 pmd - NcssMethodCount - MAJOR - - - minimum - 100 - - + NoPackage + MINOR + pmd - NcssTypeCount + NonCaseLabelInSwitch MAJOR - - - minimum - 1500 - - + pmd - NoPackage + NonExhaustiveSwitch MAJOR - + pmd - NonCaseLabelInSwitchStatement + NonSerializableClass MAJOR - + + + checkAbstractTypes + false + + pmd NonStaticInitializer MAJOR - + pmd NonThreadSafeSingleton MAJOR - - checkNonStaticFields - false - checkNonStaticMethods true + + checkNonStaticFields + false + pmd NullAssignment MAJOR - + pmd OneDeclarationPerLine - MAJOR - + MINOR + + + strictMode + false + + pmd OnlyOneReturn MINOR - + pmd OptimizableToArrayCall MAJOR - + pmd - OverrideBothEqualsAndHashcode - BLOCKER - + OverrideBothEqualsAndHashCodeOnComparable + MAJOR + pmd - PackageCase + OverrideBothEqualsAndHashcode MAJOR - + pmd - PositionLiteralsFirstInCaseInsensitiveComparisons - MAJOR - + PackageCase + MINOR + pmd - PositionLiteralsFirstInComparisons - MAJOR - + PrematureDeclaration + MINOR + pmd - PrematureDeclaration + PreserveStackTrace MAJOR - + pmd - PreserveStackTrace + PrimitiveWrapperInstantiation MAJOR - + pmd ProperCloneImplementation CRITICAL - + pmd @@ -1285,55 +1684,81 @@ staticLoggerName LOG + + loggerName + log + + + loggerClass + org.apache.commons.logging.Log + pmd RedundantFieldInitializer MAJOR - + pmd - RemoteInterfaceNamingConvention + RelianceOnDefaultCharset MAJOR - + + + + pmd + RemoteInterfaceNamingConvention + MINOR + pmd RemoteSessionInterfaceNamingConvention - MAJOR - + MINOR + pmd ReplaceEnumerationWithIterator MAJOR - + pmd ReplaceHashtableWithMap MAJOR - + + + + pmd + ReplaceJavaUtilCalendar + MAJOR + + + + pmd + ReplaceJavaUtilDate + MAJOR + pmd ReplaceVectorWithList MAJOR - + pmd - ReturnEmptyArrayRatherThanNull - MINOR - + ReturnEmptyCollectionRatherThanNull + BLOCKER + pmd ReturnFromFinallyBlock MAJOR - + pmd @@ -1346,16 +1771,10 @@ - - pmd - ShortInstantiation - MAJOR - - pmd ShortMethodName - MAJOR + MINOR minimum @@ -1366,7 +1785,7 @@ pmd ShortVariable - MAJOR + MINOR minimum @@ -1378,12 +1797,6 @@ pmd SignatureDeclareThrowsException MAJOR - - - - pmd - SignatureDeclareThrowsExceptionWithTypeResolution - MAJOR IgnoreJUnitCompletely @@ -1395,122 +1808,102 @@ pmd SimpleDateFormatNeedsLocale MAJOR - + + + + pmd + SimplifiableTestAssertion + MAJOR + pmd SimplifiedTernary MAJOR - + pmd SimplifyBooleanExpressions MAJOR - + pmd SimplifyBooleanReturns - MINOR - + MAJOR + pmd SimplifyConditional MAJOR - - - - pmd - SimplifyStartsWith - MINOR - + pmd SingleMethodSingleton CRITICAL - + pmd SingletonClassReturningNewInstance - MAJOR - + CRITICAL + pmd SingularField - MINOR - + MAJOR + + + ignoredAnnotations + java.lang.Deprecated,javafx.fxml.FXML,lombok.Getter,lombok.Setter,lombok.experimental.Delegate + + pmd StaticEJBFieldShouldBeFinal MAJOR - - - - pmd - StdCyclomaticComplexity - MAJOR - - - showMethodsComplexity - true - - - reportLevel - 10 - - - showClassesComplexity - true - - + pmd StringBufferInstantiationWithChar - MAJOR - + MINOR + pmd StringInstantiation - MAJOR - + CRITICAL + pmd StringToString MAJOR - - - - pmd - SuspiciousConstantFieldName - MAJOR - + pmd SuspiciousEqualsMethodName CRITICAL - + pmd SuspiciousHashcodeMethodName MAJOR - + pmd SuspiciousOctalEscape MAJOR - + pmd @@ -1525,20 +1918,25 @@ pmd - SwitchStmtsShouldHaveDefault - MAJOR - + SystemPrintln + CRITICAL + pmd - SystemPrintln + TestClassWithoutTestCases MAJOR - + + + testClassPattern + ^(?:.*\.)?Test[^\.]*$|^(?:.*\.)?.*Tests?$|^(?:.*\.)?.*TestCase$ + + pmd - TooFewBranchesForASwitchStatement - MINOR + TooFewBranchesForSwitch + MAJOR minimumNumberCaseForASwitch @@ -1571,7 +1969,7 @@ pmd TooManyStaticImports - MAJOR + MINOR maximumStaticImports @@ -1579,6 +1977,17 @@ + + pmd + TypeParameterNamingConventions + MINOR + + + typeParameterNamePattern + [A-Z] + + + pmd UncommentedEmptyConstructor @@ -1594,365 +2003,482 @@ pmd UncommentedEmptyMethodBody MAJOR - + pmd UnconditionalIfStatement - CRITICAL - + MAJOR + pmd - UnnecessaryCaseChange - MINOR - + UnitTestAssertionsShouldIncludeMessage + MAJOR + pmd - UnnecessaryConstructor + UnitTestContainsTooManyAsserts MAJOR - + + + maximumAsserts + 1 + + pmd - UnnecessaryConversionTemporary + UnitTestShouldIncludeAssert MAJOR - + pmd - UnnecessaryFinalModifier - INFO - + UnitTestShouldUseAfterAnnotation + MAJOR + pmd - UnnecessaryFullyQualifiedName + UnitTestShouldUseBeforeAnnotation MAJOR - + pmd - UnnecessaryLocalBeforeReturn + UnitTestShouldUseTestAnnotation MAJOR - + + + testClassPattern + Test + + pmd - UnnecessaryParentheses + UnnecessaryAnnotationValueElement MINOR - + + + java7Compatibility + false + + pmd - UnnecessaryReturn + UnnecessaryBooleanAssertion + MAJOR + + + + pmd + UnnecessaryBoxing MINOR - + pmd - UnnecessaryWrapperObjectCreation + UnnecessaryCaseChange MAJOR - + pmd - UnsynchronizedStaticDateFormatter - MAJOR - + UnnecessaryCast + MINOR + pmd - UnusedFormalParameter + UnnecessaryConstructor + MINOR + + + ignoredAnnotations + javax.inject.Inject,com.google.inject.Inject,org.springframework.beans.factory.annotation.Autowired + + + + + pmd + UnnecessaryConversionTemporary MAJOR - + pmd - UnusedImports - INFO - + UnnecessaryFullyQualifiedName + MINOR + + + reportStaticMethods + true + + + reportStaticFields + true + + pmd - UnusedImportsWithTypeResolution - INFO - + UnnecessaryImport + MINOR + pmd - UnusedLocalVariable - MAJOR - + UnnecessaryLocalBeforeReturn + MINOR + + + statementOrderMatters + true + + pmd - UnusedModifier - INFO - + UnnecessaryModifier + MINOR + pmd - UnusedNullCheckInEquals - MAJOR - + UnnecessaryReturn + MINOR + pmd - UnusedPrivateField - MAJOR - + UnnecessarySemicolon + MINOR + pmd - UnusedPrivateMethod + UnnecessaryVarargsArrayCreation MAJOR - + pmd - UseArrayListInsteadOfVector + UnnecessaryWarningSuppression MAJOR - + pmd - UseArraysAsList + UnsynchronizedStaticFormatter MAJOR - + + + allowMethodLevelSynchronization + false + + pmd - UseCollectionIsEmpty - MINOR - + UnusedAssignment + MAJOR + + + checkUnusedPrefixIncrement + false + + + reportUnusedVariables + false + + pmd - UseConcurrentHashMap + UnusedFormalParameter MAJOR - + + + checkAll + false + + pmd - UseCorrectExceptionLogging + UnusedLocalVariable MAJOR - + pmd - UseEqualsToCompareStrings + UnusedNullCheckInEquals MAJOR - + pmd - UseIndexOfChar + UnusedPrivateField MAJOR - + + + ignoredFieldNames + serialVersionUID,serialPersistentFields + + pmd - UseLocaleWithCaseConversions + UnusedPrivateMethod MAJOR - + + + ignoredAnnotations + java.lang.Deprecated,jakarta.annotation.PostConstruct,jakarta.annotation.PreDestroy,lombok.EqualsAndHashCode.Include + + pmd - UseNotifyAllInsteadOfNotify + UseArrayListInsteadOfVector MAJOR - + pmd - UseObjectForClearerAPI - MINOR - + UseArraysAsList + MAJOR + pmd - UseProperClassLoader - CRITICAL - + UseCollectionIsEmpty + MAJOR + pmd - UseStringBufferForStringAppends + UseConcurrentHashMap MAJOR - + pmd - UseStringBufferLength - MINOR - + UseCorrectExceptionLogging + MAJOR + pmd - UseUtilityClass - MAJOR - + UseDiamondOperator + MINOR + pmd - UseVarargs + UseEnumCollections MAJOR - + pmd - UselessOperationOnImmutable - CRITICAL - + UseEqualsToCompareStrings + MAJOR + pmd - UselessOverridingMethod - MAJOR + UseExplicitTypes + MINOR - ignoreAnnotations + allowLiterals + false + + + allowCtors + false + + + allowCasts + false + + + allowLoopVariable false pmd - UselessParentheses - INFO - + UseIOStreamsWithApacheCommonsFileItem + MAJOR + pmd - UselessQualifiedThis + UseIndexOfChar MAJOR - + pmd - UselessStringValueOf - MINOR - + UseLocaleWithCaseConversions + MAJOR + pmd - VariableNamingConventions + UseNotifyAllInsteadOfNotify MAJOR - + pmd - WhileLoopsMustUseBraces + UseObjectForClearerAPI MAJOR - + - pmd-unit-tests - JUnit4SuitesShouldUseSuiteAnnotation + pmd + UseProperClassLoader MAJOR - + - pmd-unit-tests - JUnit4TestShouldUseAfterAnnotation - MAJOR - + pmd + UseShortArrayInitializer + MINOR + - pmd-unit-tests - JUnit4TestShouldUseBeforeAnnotation + pmd + UseStandardCharsets MAJOR - + - pmd-unit-tests - JUnit4TestShouldUseTestAnnotation + pmd + UseStringBufferForStringAppends MAJOR - + - pmd-unit-tests - JUnitAssertionsShouldIncludeMessage - MINOR - - - - pmd-unit-tests - JUnitSpelling + pmd + UseStringBufferLength MAJOR - + - pmd-unit-tests - JUnitStaticSuite + pmd + UseTryWithResources MAJOR - + + + closeMethods + close,closeQuietly + + - pmd-unit-tests - JUnitTestContainsTooManyAsserts - MAJOR + pmd + UseUnderscoresInNumericLiterals + MINOR - maximumAsserts - 1 + acceptableDecimalLength + 4 - pmd-unit-tests - JUnitTestsShouldIncludeAssert + pmd + UseUtilityClass MAJOR - + - pmd-unit-tests - JUnitUseExpected + pmd + UseVarargs + MINOR + + + + pmd + UselessOperationOnImmutable MAJOR - + - pmd-unit-tests - SimplifyBooleanAssertion + pmd + UselessOverridingMethod + MAJOR + + + ignoreAnnotations + false + + + + + pmd + UselessParentheses MINOR - + + + ignoreClarifying + true + + + ignoreBalancing + true + + - pmd-unit-tests - TestClassWithoutTestCases + pmd + UselessPureMethodCall MAJOR - + - pmd-unit-tests - UnnecessaryBooleanAssertion + pmd + UselessQualifiedThis MINOR - + - pmd-unit-tests - UseAssertEqualsInsteadOfAssertTrue - MINOR - + pmd + UselessStringValueOf + MAJOR + - pmd-unit-tests - UseAssertNullInsteadOfAssertTrue + pmd + VariableCanBeInlined MINOR - + + + statementOrderMatters + true + + - pmd-unit-tests - UseAssertSameInsteadOfAssertTrue - MINOR - + pmd + WhileLoopWithLiteralBoolean + MAJOR + - pmd-unit-tests - UseAssertTrueInsteadOfAssertEquals - MINOR - + pmd + XPathRule + MAJOR + diff --git a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-backup.xml b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-backup.xml index d6ee367c..7fb4e46b 100644 --- a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-backup.xml +++ b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-backup.xml @@ -1,6 +1,6 @@ - pmd + pmd-backup-profile java @@ -9,4 +9,4 @@ MINOR - \ No newline at end of file + diff --git a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-extensions-profile.xml b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-extensions-profile.xml index 37b144b4..4d04be7e 100644 --- a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-extensions-profile.xml +++ b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-extensions-profile.xml @@ -1,6 +1,6 @@ - pmd-extensions + pmd-extensions-profile java diff --git a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-junit-rules.xml b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-junit-rules.xml deleted file mode 100644 index f84e0f20..00000000 --- a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-junit-rules.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - pmd-junit - java - - - pmd - UnusedPrivateField - MAJOR - - - pmd-unit-tests - TestClassWithoutTestCases - MAJOR - - - \ No newline at end of file diff --git a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-all-rules.xml b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-all-rules.xml new file mode 100644 index 00000000..ea1391c6 --- /dev/null +++ b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-all-rules.xml @@ -0,0 +1,17 @@ + + + pmd-kotlin-all-rules + kotlin + + + pmd-kotlin + FunctionNameTooShort + MAJOR + + + pmd-kotlin + OverrideBothEqualsAndHashcode + MAJOR + + + diff --git a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-profile.xml b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-profile.xml new file mode 100644 index 00000000..c50b5369 --- /dev/null +++ b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-kotlin-profile.xml @@ -0,0 +1,17 @@ + + + pmd-kotlin-profile + kotlin + + + pmd-kotlin + FunctionNameTooShort + CRITICAL + + + pmd-kotlin + OverrideBothEqualsAndHashcode + MAJOR + + + diff --git a/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-test-rule.xml b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-test-rule.xml new file mode 100644 index 00000000..10700f93 --- /dev/null +++ b/integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-test-rule.xml @@ -0,0 +1,31 @@ + + + pmd-test-rule-profile + java + + + pmd + UnitTestContainsTooManyAsserts + MAJOR + + + maximumAsserts + 1 + + + + + pmd + UnusedPrivateField + MAJOR + + + pmd + AvoidIfWithoutBrace + + + pmd + AvoidIfWithoutBraceTest + + + diff --git a/mvnw b/mvnw new file mode 100755 index 00000000..19529ddf --- /dev/null +++ b/mvnw @@ -0,0 +1,259 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.3.2 +# +# Optional ENV vars +# ----------------- +# JAVA_HOME - location of a JDK home dir, required when download maven via java source +# MVNW_REPOURL - repo url base for downloading maven distribution +# MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +# MVNW_VERBOSE - true: enable verbose log; debug: trace the mvnw script; others: silence the output +# ---------------------------------------------------------------------------- + +set -euf +[ "${MVNW_VERBOSE-}" != debug ] || set -x + +# OS specific support. +native_path() { printf %s\\n "$1"; } +case "$(uname)" in +CYGWIN* | MINGW*) + [ -z "${JAVA_HOME-}" ] || JAVA_HOME="$(cygpath --unix "$JAVA_HOME")" + native_path() { cygpath --path --windows "$1"; } + ;; +esac + +# set JAVACMD and JAVACCMD +set_java_home() { + # For Cygwin and MinGW, ensure paths are in Unix format before anything is touched + if [ -n "${JAVA_HOME-}" ]; then + if [ -x "$JAVA_HOME/jre/sh/java" ]; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + JAVACCMD="$JAVA_HOME/jre/sh/javac" + else + JAVACMD="$JAVA_HOME/bin/java" + JAVACCMD="$JAVA_HOME/bin/javac" + + if [ ! -x "$JAVACMD" ] || [ ! -x "$JAVACCMD" ]; then + echo "The JAVA_HOME environment variable is not defined correctly, so mvnw cannot run." >&2 + echo "JAVA_HOME is set to \"$JAVA_HOME\", but \"\$JAVA_HOME/bin/java\" or \"\$JAVA_HOME/bin/javac\" does not exist." >&2 + return 1 + fi + fi + else + JAVACMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v java + )" || : + JAVACCMD="$( + 'set' +e + 'unset' -f command 2>/dev/null + 'command' -v javac + )" || : + + if [ ! -x "${JAVACMD-}" ] || [ ! -x "${JAVACCMD-}" ]; then + echo "The java/javac command does not exist in PATH nor is JAVA_HOME set, so mvnw cannot run." >&2 + return 1 + fi + fi +} + +# hash string like Java String::hashCode +hash_string() { + str="${1:-}" h=0 + while [ -n "$str" ]; do + char="${str%"${str#?}"}" + h=$(((h * 31 + $(LC_CTYPE=C printf %d "'$char")) % 4294967296)) + str="${str#?}" + done + printf %x\\n $h +} + +verbose() { :; } +[ "${MVNW_VERBOSE-}" != true ] || verbose() { printf %s\\n "${1-}"; } + +die() { + printf %s\\n "$1" >&2 + exit 1 +} + +trim() { + # MWRAPPER-139: + # Trims trailing and leading whitespace, carriage returns, tabs, and linefeeds. + # Needed for removing poorly interpreted newline sequences when running in more + # exotic environments such as mingw bash on Windows. + printf "%s" "${1}" | tr -d '[:space:]' +} + +# parse distributionUrl and optional distributionSha256Sum, requires .mvn/wrapper/maven-wrapper.properties +while IFS="=" read -r key value; do + case "${key-}" in + distributionUrl) distributionUrl=$(trim "${value-}") ;; + distributionSha256Sum) distributionSha256Sum=$(trim "${value-}") ;; + esac +done <"${0%/*}/.mvn/wrapper/maven-wrapper.properties" +[ -n "${distributionUrl-}" ] || die "cannot read distributionUrl property in ${0%/*}/.mvn/wrapper/maven-wrapper.properties" + +case "${distributionUrl##*/}" in +maven-mvnd-*bin.*) + MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ + case "${PROCESSOR_ARCHITECTURE-}${PROCESSOR_ARCHITEW6432-}:$(uname -a)" in + *AMD64:CYGWIN* | *AMD64:MINGW*) distributionPlatform=windows-amd64 ;; + :Darwin*x86_64) distributionPlatform=darwin-amd64 ;; + :Darwin*arm64) distributionPlatform=darwin-aarch64 ;; + :Linux*x86_64*) distributionPlatform=linux-amd64 ;; + *) + echo "Cannot detect native platform for mvnd on $(uname)-$(uname -m), use pure java version" >&2 + distributionPlatform=linux-amd64 + ;; + esac + distributionUrl="${distributionUrl%-bin.*}-$distributionPlatform.zip" + ;; +maven-mvnd-*) MVN_CMD=mvnd.sh _MVNW_REPO_PATTERN=/maven/mvnd/ ;; +*) MVN_CMD="mvn${0##*/mvnw}" _MVNW_REPO_PATTERN=/org/apache/maven/ ;; +esac + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +[ -z "${MVNW_REPOURL-}" ] || distributionUrl="$MVNW_REPOURL$_MVNW_REPO_PATTERN${distributionUrl#*"$_MVNW_REPO_PATTERN"}" +distributionUrlName="${distributionUrl##*/}" +distributionUrlNameMain="${distributionUrlName%.*}" +distributionUrlNameMain="${distributionUrlNameMain%-bin}" +MAVEN_USER_HOME="${MAVEN_USER_HOME:-${HOME}/.m2}" +MAVEN_HOME="${MAVEN_USER_HOME}/wrapper/dists/${distributionUrlNameMain-}/$(hash_string "$distributionUrl")" + +exec_maven() { + unset MVNW_VERBOSE MVNW_USERNAME MVNW_PASSWORD MVNW_REPOURL || : + exec "$MAVEN_HOME/bin/$MVN_CMD" "$@" || die "cannot exec $MAVEN_HOME/bin/$MVN_CMD" +} + +if [ -d "$MAVEN_HOME" ]; then + verbose "found existing MAVEN_HOME at $MAVEN_HOME" + exec_maven "$@" +fi + +case "${distributionUrl-}" in +*?-bin.zip | *?maven-mvnd-?*-?*.zip) ;; +*) die "distributionUrl is not valid, must match *-bin.zip or maven-mvnd-*.zip, but found '${distributionUrl-}'" ;; +esac + +# prepare tmp dir +if TMP_DOWNLOAD_DIR="$(mktemp -d)" && [ -d "$TMP_DOWNLOAD_DIR" ]; then + clean() { rm -rf -- "$TMP_DOWNLOAD_DIR"; } + trap clean HUP INT TERM EXIT +else + die "cannot create temp dir" +fi + +mkdir -p -- "${MAVEN_HOME%/*}" + +# Download and Install Apache Maven +verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +verbose "Downloading from: $distributionUrl" +verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +# select .zip or .tar.gz +if ! command -v unzip >/dev/null; then + distributionUrl="${distributionUrl%.zip}.tar.gz" + distributionUrlName="${distributionUrl##*/}" +fi + +# verbose opt +__MVNW_QUIET_WGET=--quiet __MVNW_QUIET_CURL=--silent __MVNW_QUIET_UNZIP=-q __MVNW_QUIET_TAR='' +[ "${MVNW_VERBOSE-}" != true ] || __MVNW_QUIET_WGET='' __MVNW_QUIET_CURL='' __MVNW_QUIET_UNZIP='' __MVNW_QUIET_TAR=v + +# normalize http auth +case "${MVNW_PASSWORD:+has-password}" in +'') MVNW_USERNAME='' MVNW_PASSWORD='' ;; +has-password) [ -n "${MVNW_USERNAME-}" ] || MVNW_USERNAME='' MVNW_PASSWORD='' ;; +esac + +if [ -z "${MVNW_USERNAME-}" ] && command -v wget >/dev/null; then + verbose "Found wget ... using wget" + wget ${__MVNW_QUIET_WGET:+"$__MVNW_QUIET_WGET"} "$distributionUrl" -O "$TMP_DOWNLOAD_DIR/$distributionUrlName" || die "wget: Failed to fetch $distributionUrl" +elif [ -z "${MVNW_USERNAME-}" ] && command -v curl >/dev/null; then + verbose "Found curl ... using curl" + curl ${__MVNW_QUIET_CURL:+"$__MVNW_QUIET_CURL"} -f -L -o "$TMP_DOWNLOAD_DIR/$distributionUrlName" "$distributionUrl" || die "curl: Failed to fetch $distributionUrl" +elif set_java_home; then + verbose "Falling back to use Java to download" + javaSource="$TMP_DOWNLOAD_DIR/Downloader.java" + targetZip="$TMP_DOWNLOAD_DIR/$distributionUrlName" + cat >"$javaSource" <<-END + public class Downloader extends java.net.Authenticator + { + protected java.net.PasswordAuthentication getPasswordAuthentication() + { + return new java.net.PasswordAuthentication( System.getenv( "MVNW_USERNAME" ), System.getenv( "MVNW_PASSWORD" ).toCharArray() ); + } + public static void main( String[] args ) throws Exception + { + setDefault( new Downloader() ); + java.nio.file.Files.copy( java.net.URI.create( args[0] ).toURL().openStream(), java.nio.file.Paths.get( args[1] ).toAbsolutePath().normalize() ); + } + } + END + # For Cygwin/MinGW, switch paths to Windows format before running javac and java + verbose " - Compiling Downloader.java ..." + "$(native_path "$JAVACCMD")" "$(native_path "$javaSource")" || die "Failed to compile Downloader.java" + verbose " - Running Downloader.java ..." + "$(native_path "$JAVACMD")" -cp "$(native_path "$TMP_DOWNLOAD_DIR")" Downloader "$distributionUrl" "$(native_path "$targetZip")" +fi + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +if [ -n "${distributionSha256Sum-}" ]; then + distributionSha256Result=false + if [ "$MVN_CMD" = mvnd.sh ]; then + echo "Checksum validation is not supported for maven-mvnd." >&2 + echo "Please disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + elif command -v sha256sum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | sha256sum -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + elif command -v shasum >/dev/null; then + if echo "$distributionSha256Sum $TMP_DOWNLOAD_DIR/$distributionUrlName" | shasum -a 256 -c >/dev/null 2>&1; then + distributionSha256Result=true + fi + else + echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available." >&2 + echo "Please install either command, or disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." >&2 + exit 1 + fi + if [ $distributionSha256Result = false ]; then + echo "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised." >&2 + echo "If you updated your Maven version, you need to update the specified distributionSha256Sum property." >&2 + exit 1 + fi +fi + +# unzip and move +if command -v unzip >/dev/null; then + unzip ${__MVNW_QUIET_UNZIP:+"$__MVNW_QUIET_UNZIP"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -d "$TMP_DOWNLOAD_DIR" || die "failed to unzip" +else + tar xzf${__MVNW_QUIET_TAR:+"$__MVNW_QUIET_TAR"} "$TMP_DOWNLOAD_DIR/$distributionUrlName" -C "$TMP_DOWNLOAD_DIR" || die "failed to untar" +fi +printf %s\\n "$distributionUrl" >"$TMP_DOWNLOAD_DIR/$distributionUrlNameMain/mvnw.url" +mv -- "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" "$MAVEN_HOME" || [ -d "$MAVEN_HOME" ] || die "fail to move MAVEN_HOME" + +clean || : +exec_maven "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 00000000..b150b91e --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,149 @@ +<# : batch portion +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.3.2 +@REM +@REM Optional ENV vars +@REM MVNW_REPOURL - repo url base for downloading maven distribution +@REM MVNW_USERNAME/MVNW_PASSWORD - user and password for downloading maven +@REM MVNW_VERBOSE - true: enable verbose log; others: silence the output +@REM ---------------------------------------------------------------------------- + +@IF "%__MVNW_ARG0_NAME__%"=="" (SET __MVNW_ARG0_NAME__=%~nx0) +@SET __MVNW_CMD__= +@SET __MVNW_ERROR__= +@SET __MVNW_PSMODULEP_SAVE=%PSModulePath% +@SET PSModulePath= +@FOR /F "usebackq tokens=1* delims==" %%A IN (`powershell -noprofile "& {$scriptDir='%~dp0'; $script='%__MVNW_ARG0_NAME__%'; icm -ScriptBlock ([Scriptblock]::Create((Get-Content -Raw '%~f0'))) -NoNewScope}"`) DO @( + IF "%%A"=="MVN_CMD" (set __MVNW_CMD__=%%B) ELSE IF "%%B"=="" (echo %%A) ELSE (echo %%A=%%B) +) +@SET PSModulePath=%__MVNW_PSMODULEP_SAVE% +@SET __MVNW_PSMODULEP_SAVE= +@SET __MVNW_ARG0_NAME__= +@SET MVNW_USERNAME= +@SET MVNW_PASSWORD= +@IF NOT "%__MVNW_CMD__%"=="" (%__MVNW_CMD__% %*) +@echo Cannot start maven from wrapper >&2 && exit /b 1 +@GOTO :EOF +: end batch / begin powershell #> + +$ErrorActionPreference = "Stop" +if ($env:MVNW_VERBOSE -eq "true") { + $VerbosePreference = "Continue" +} + +# calculate distributionUrl, requires .mvn/wrapper/maven-wrapper.properties +$distributionUrl = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionUrl +if (!$distributionUrl) { + Write-Error "cannot read distributionUrl property in $scriptDir/.mvn/wrapper/maven-wrapper.properties" +} + +switch -wildcard -casesensitive ( $($distributionUrl -replace '^.*/','') ) { + "maven-mvnd-*" { + $USE_MVND = $true + $distributionUrl = $distributionUrl -replace '-bin\.[^.]*$',"-windows-amd64.zip" + $MVN_CMD = "mvnd.cmd" + break + } + default { + $USE_MVND = $false + $MVN_CMD = $script -replace '^mvnw','mvn' + break + } +} + +# apply MVNW_REPOURL and calculate MAVEN_HOME +# maven home pattern: ~/.m2/wrapper/dists/{apache-maven-,maven-mvnd--}/ +if ($env:MVNW_REPOURL) { + $MVNW_REPO_PATTERN = if ($USE_MVND) { "/org/apache/maven/" } else { "/maven/mvnd/" } + $distributionUrl = "$env:MVNW_REPOURL$MVNW_REPO_PATTERN$($distributionUrl -replace '^.*'+$MVNW_REPO_PATTERN,'')" +} +$distributionUrlName = $distributionUrl -replace '^.*/','' +$distributionUrlNameMain = $distributionUrlName -replace '\.[^.]*$','' -replace '-bin$','' +$MAVEN_HOME_PARENT = "$HOME/.m2/wrapper/dists/$distributionUrlNameMain" +if ($env:MAVEN_USER_HOME) { + $MAVEN_HOME_PARENT = "$env:MAVEN_USER_HOME/wrapper/dists/$distributionUrlNameMain" +} +$MAVEN_HOME_NAME = ([System.Security.Cryptography.MD5]::Create().ComputeHash([byte[]][char[]]$distributionUrl) | ForEach-Object {$_.ToString("x2")}) -join '' +$MAVEN_HOME = "$MAVEN_HOME_PARENT/$MAVEN_HOME_NAME" + +if (Test-Path -Path "$MAVEN_HOME" -PathType Container) { + Write-Verbose "found existing MAVEN_HOME at $MAVEN_HOME" + Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" + exit $? +} + +if (! $distributionUrlNameMain -or ($distributionUrlName -eq $distributionUrlNameMain)) { + Write-Error "distributionUrl is not valid, must end with *-bin.zip, but found $distributionUrl" +} + +# prepare tmp dir +$TMP_DOWNLOAD_DIR_HOLDER = New-TemporaryFile +$TMP_DOWNLOAD_DIR = New-Item -Itemtype Directory -Path "$TMP_DOWNLOAD_DIR_HOLDER.dir" +$TMP_DOWNLOAD_DIR_HOLDER.Delete() | Out-Null +trap { + if ($TMP_DOWNLOAD_DIR.Exists) { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } + } +} + +New-Item -Itemtype Directory -Path "$MAVEN_HOME_PARENT" -Force | Out-Null + +# Download and Install Apache Maven +Write-Verbose "Couldn't find MAVEN_HOME, downloading and installing it ..." +Write-Verbose "Downloading from: $distributionUrl" +Write-Verbose "Downloading to: $TMP_DOWNLOAD_DIR/$distributionUrlName" + +$webclient = New-Object System.Net.WebClient +if ($env:MVNW_USERNAME -and $env:MVNW_PASSWORD) { + $webclient.Credentials = New-Object System.Net.NetworkCredential($env:MVNW_USERNAME, $env:MVNW_PASSWORD) +} +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 +$webclient.DownloadFile($distributionUrl, "$TMP_DOWNLOAD_DIR/$distributionUrlName") | Out-Null + +# If specified, validate the SHA-256 sum of the Maven distribution zip file +$distributionSha256Sum = (Get-Content -Raw "$scriptDir/.mvn/wrapper/maven-wrapper.properties" | ConvertFrom-StringData).distributionSha256Sum +if ($distributionSha256Sum) { + if ($USE_MVND) { + Write-Error "Checksum validation is not supported for maven-mvnd. `nPlease disable validation by removing 'distributionSha256Sum' from your maven-wrapper.properties." + } + Import-Module $PSHOME\Modules\Microsoft.PowerShell.Utility -Function Get-FileHash + if ((Get-FileHash "$TMP_DOWNLOAD_DIR/$distributionUrlName" -Algorithm SHA256).Hash.ToLower() -ne $distributionSha256Sum) { + Write-Error "Error: Failed to validate Maven distribution SHA-256, your Maven distribution might be compromised. If you updated your Maven version, you need to update the specified distributionSha256Sum property." + } +} + +# unzip and move +Expand-Archive "$TMP_DOWNLOAD_DIR/$distributionUrlName" -DestinationPath "$TMP_DOWNLOAD_DIR" | Out-Null +Rename-Item -Path "$TMP_DOWNLOAD_DIR/$distributionUrlNameMain" -NewName $MAVEN_HOME_NAME | Out-Null +try { + Move-Item -Path "$TMP_DOWNLOAD_DIR/$MAVEN_HOME_NAME" -Destination $MAVEN_HOME_PARENT | Out-Null +} catch { + if (! (Test-Path -Path "$MAVEN_HOME" -PathType Container)) { + Write-Error "fail to move MAVEN_HOME" + } +} finally { + try { Remove-Item $TMP_DOWNLOAD_DIR -Recurse -Force | Out-Null } + catch { Write-Warning "Cannot remove $TMP_DOWNLOAD_DIR" } +} + +Write-Output "MVN_CMD=$MAVEN_HOME/bin/$MVN_CMD" diff --git a/pom.xml b/pom.xml index 33a28be8..ec96eb25 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,9 @@ + + + + SonarSource SA and others + mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + 7.17.0 + 6.0.0 + 5.20.0 + 3.27.6 + 3.19.0 + 2.0.1 + 33.5.0-jre + 2.0.6.1 - 1.18.0.372 - + 1.23.0.740 + 25.10.0.114319 + 13.2.0.3137 + 8.19.0.40387 + 2.7.1.392 + 5.6.2.2625 + 5.1 UTF-8 - 1.8 - 1.8 - false - ${skipTests} - ${skipTests} + 11 + + 3.6.2 + 3.5.4 + 3.5.4 + 3.1.1 + 3.3.1 + 3.12.0 + 3.2.8 + 3.5.0 + 5.2.0.4988 + 0.8.14 + 1.7.3 + + UTF-8 + sonar-pmd-plugin/target/site/jacoco/jacoco.xml + 3.1.4 + 3.1.4 + 3.14.1 + 3.3.1 + 2.0.17 + 2.20.0 + + sonar-pmd-lib + sonar-pmd-plugin + integration-test + + - org.sonarsource.sonarqube + org.sonarsource.api.plugin sonar-plugin-api - provided - 7.7 + ${sonar-plugin-api.version} + + + org.sonarsource.sonarqube + sonar-plugin-api-impl + ${sonar-plugin-api-impl.version} + + + org.sonarsource.orchestrator + sonar-orchestrator + ${sonar-orchestrator.version} + + + org.sonarsource.orchestrator + sonar-orchestrator-junit4 + ${sonar-orchestrator.version} + test - xml-apis - xml-apis + + org.slf4j + slf4j-api - org.sonarsource.orchestrator - sonar-orchestrator - 3.26.0.2111 - test + org.codehaus.sonar + sonar-ws-client + ${sonar-ws-client.version} + provided @@ -111,18 +160,10 @@ pmd-java ${pmd.version} - - junit - junit - com.beust jcommander - - net.java.dev.javacc - javacc - com.google.code.gson gson @@ -133,6 +174,11 @@ + + org.apache.commons + commons-lang3 + ${commons-lang3.version} + @@ -146,19 +192,7 @@ org.junit.jupiter - junit-jupiter-api - ${junit.jupiter.version} - test - - - org.junit.jupiter - junit-jupiter-engine - ${junit.jupiter.version} - test - - - org.junit.vintage - junit-vintage-engine + junit-jupiter ${junit.jupiter.version} test @@ -173,53 +207,162 @@ + + org.apache.maven.plugins + maven-resources-plugin + ${maven-resources-plugin.version} + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + + org.apache.maven.plugins + maven-install-plugin + ${maven-install-plugin.version} + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + + org.apache.maven.plugins + maven-gpg-plugin + ${maven.gpg.plugin.version} + org.sonarsource.sonar-packaging-maven-plugin sonar-packaging-maven-plugin ${version.sonar-packaging.plugin} - 6.6 - java:4.15.0.12310 + 9.9 + + maven-clean-plugin + ${maven.cleanup.plugin.version} + + + org.apache.maven.plugins + maven-enforcer-plugin + ${maven.enforcer.plugin.version} + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven.surefire.plugin.version} + + + org.codehaus.mojo + flatten-maven-plugin + ${flatten.maven.plugin.version} + + + org.sonarsource.scanner.maven + sonar-maven-plugin + ${sonar.maven.plugin.version} + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 11 + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + ${sonar.maven.plugin.version} + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-maven-and-java + + enforce + + + + + 3.8 + + + [17,22) + + + + + + + + org.sonarsource.sonar-packaging-maven-plugin + sonar-packaging-maven-plugin + true + + + + + + ${buildNumber} + + ${timestamp} + + + + org.apache.maven.plugins maven-surefire-plugin - 2.22.2 random - integration-test - ${skip.surefire.tests} + none org.apache.maven.plugins maven-failsafe-plugin - 2.22.2 + ${maven.failsafe.plugin.version} -server - ${skip.failsafe.tests} + integration-test - verify integration-test + verify + + org.sonatype.central + central-publishing-maven-plugin + 0.9.0 + true + + false + + integration-test + + + org.apache.maven.plugins maven-release-plugin - 2.5.3 + ${maven.release.plugin.version} @{project.version} @@ -227,7 +370,7 @@ org.apache.maven.plugins maven-source-plugin - 3.2.1 + ${maven.source.plugin.version} attach-sources @@ -240,10 +383,12 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.1.1 + ${maven.javadoc.plugin.version} true 8 + false + all,-missing @@ -254,24 +399,74 @@ + + org.apache.maven.plugins + maven-install-plugin + ${maven-install-plugin.version} + + ${project.build.directory}/flattened-pom.xml + + + + org.apache.maven.plugins + maven-deploy-plugin + ${maven-deploy-plugin.version} + + ${project.build.directory}/flattened-pom.xml + + + + + org.codehaus.mojo + flatten-maven-plugin + + oss + true + target/flattened-pom.xml + + resolve + resolve + resolve + interpolate + + + + + + flatten + prepare-package + + flatten + + + + + flatten.clean + clean + + clean + + + + flatten.deploy + deploy + + flatten + + + + - release-sign-artifacts - - - performRelease - true - - + release org.apache.maven.plugins maven-gpg-plugin - 1.6 sign-artifacts @@ -281,26 +476,16 @@ + + + --pinentry-mode + loopback + + - - - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ - - - - - sonar-pmd-plugin - integration-test - diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 00000000..bbcadd45 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,79 @@ +# Generator Scripts + +This directory contains scripts and configuration files used for generating and maintaining the SonarQube PMD plugin. + +## Scripts + +### pmd7_rules_xml_generator.groovy + +This script generates XML rule files for PMD 7. It: +- Processes rule definitions from PMD JARs +- Converts Markdown documentation to HTML +- Generates rules-java.xml and rules-kotlin.xml files +- Uses rule alternatives defined in JSON files + +Usage: This script is typically executed during the build process to generate up-to-date rule definitions. + +From the project root directory: + +```commandline +./mvnw clean generate-resources -Pgenerate-pmd-rules -pl sonar-pmd-plugin -am +``` + +Notes: +- The -am (also-make) flag is the Maven-native way to ensure dependent modules (like sonar-pmd-lib) are built in the reactor when you build only sonar-pmd-plugin with -pl. + +### generate_release_notes.groovy + +This script compares two PMD rule XML files (an old version and a new version) and generates a Markdown report highlighting: +1. Rules that have been removed +2. Rules that have been added +3. Rules that remain unchanged + +Usage: +``` +./generate_release_notes.groovy [options] +``` + +Options: +- `-o, --old `: Old rules XML file path +- `-n, --new `: New rules XML file path +- `-r, --report `: Output report file path +- `-v, --version `: Version to use in the title +- `-ov, --oldversion `: Old version to use for old rules file name +- `-h, --help`: Show usage information + +## Configuration Files + +### renamed-java-rules.json + +This file contains a mapping of renamed Java rules in PMD. It includes: +- The language (Java) +- A count of renamed rules +- A list of rules with their old name, new reference name, and category + +**Warning:** This file should not be modified manually as it is generated by the build process. + +### rule-alternatives-java.json + +This file contains a mapping of PMD Java rules to their equivalent SonarQube rules. For each PMD rule, it provides: +- The SonarQube rule key (e.g., "java:S1694") +- A link to the SonarQube rule documentation + +### old-rules-$version.xml + +These files contain XML definitions of PMD rules from specific versions. They are used as reference files for the generate_release_notes.groovy script to compare with newer rule definitions. + +**Warning:** These files should not be modified manually as they are copied from previous versions of the plugin. + +## Scripts for Testing + +### create_highly_compressed_jar.groovy + +This script creates a highly compressed Jar file to test zip bomb detection. +The generated jar is moved to `../sonar-pmd-lib/src/test/resources/` + +### create_java_rule_extractor_test_jar.groovy + +This script creates a Jar file containing two test classes for the Java rule extractor. +The generated jar is moved to `../sonar-pmd-lib/src/test/resources/` diff --git a/scripts/create_highly_compressed_jar.groovy b/scripts/create_highly_compressed_jar.groovy new file mode 100755 index 00000000..5d5001eb --- /dev/null +++ b/scripts/create_highly_compressed_jar.groovy @@ -0,0 +1,22 @@ +#!/usr/bin/env groovy +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream +import java.nio.charset.StandardCharsets + +// Build the text: "compress-this" repeated 1000 times, separated by dashes +def content = (['compress-this'] * 1000).join('-') + +// Create a ZIP (JAR) file containing a single content.txt entry +def outputName = (args && args.length > 0) ? args[0] : 'test-highly-compressed.jar' +new ZipOutputStream(new FileOutputStream(outputName)).withCloseable { zos -> + zos.putNextEntry(new ZipEntry('content.txt')) + zos.write(content.getBytes(StandardCharsets.UTF_8)) + zos.closeEntry() +} + +println "Created ${outputName} containing content.txt" + +// Move file to sonar-pmd-lib/src/test/resources +def moveToFile = new File('../sonar-pmd-lib/src/test/resources/' + outputName) +new File(outputName).renameTo(moveToFile) +println "Moved to: $moveToFile" \ No newline at end of file diff --git a/scripts/create_java_rule_extractor_test_jar.groovy b/scripts/create_java_rule_extractor_test_jar.groovy new file mode 100755 index 00000000..79270f59 --- /dev/null +++ b/scripts/create_java_rule_extractor_test_jar.groovy @@ -0,0 +1,148 @@ +#!/usr/bin/env groovy +@Grab('org.apache.ant:ant:1.10.15') +@Grab('org.apache.ant:ant-launcher:1.10.15') +@Grab('org.apache.groovy:groovy-groovysh:4.0.26') +// We’ll resolve PMD dependencies programmatically to build a proper Ant classpath + +import groovy.grape.Grape +import org.apache.tools.ant.Project +import org.apache.tools.ant.taskdefs.Javac +import org.apache.tools.ant.taskdefs.Jar +import org.apache.tools.ant.types.Path +import org.apache.tools.ant.types.FileSet + +import java.nio.file.Files +import java.nio.file.Path as NioPath +import java.nio.file.StandardOpenOption + +// 1) Resolve PMD Java + transitives to ensure AbstractJavaRule is available at compile time +// Pin to a PMD 7.x version. Adjust if needed to match your environment. +final Map coords = [group: 'net.sourceforge.pmd', module: 'pmd-java', version: '7.17.0'] +final List resolvedUris = (List) Grape.resolve( + [autoDownload: true, transitive: true, classLoader: this.class.classLoader], + coords +) +final List resolvedJars = resolvedUris.collect { new File(it) } + +// 2) Prepare workspace +final File outputJar = new File('test-java-rule-extractor.jar') +final NioPath workDir = Files.createTempDirectory('rule-jar-build-') +final File srcDir = workDir.resolve('src').toFile() +final File classesDir = workDir.resolve('classes').toFile() +srcDir.mkdirs() +classesDir.mkdirs() + +// 3) Write two Java rules: one with properties, one without +final String pkg = 'com.example.rules' +final File pkgDir = new File(srcDir, pkg.replace('.', File.separator)) +pkgDir.mkdirs() + +final String withPropsJava = """\ +package ${pkg}; + +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; +import net.sourceforge.pmd.properties.PropertyDescriptor; +import net.sourceforge.pmd.properties.PropertyFactory; + +public class WithPropsRule extends AbstractJavaRule { + + private static final PropertyDescriptor STR_PROP = + PropertyFactory.stringProperty("strProp") + .desc("A sample string property") + .defaultValue("default") + .build(); + + private static final PropertyDescriptor INT_PROP = + PropertyFactory.intProperty("intProp") + .desc("A sample integer property") + .defaultValue(42) + .build(); + + private static final PropertyDescriptor BOOL_PROP = + PropertyFactory.booleanProperty("boolProp") + .desc("A sample boolean property") + .defaultValue(true) + .build(); + + private static final PropertyDescriptor> LIST_STR_PROP = + PropertyFactory.stringListProperty("listStrProp") + .desc("A sample list of strings") + .emptyDefaultValue() + .build(); + + public WithPropsRule() { + definePropertyDescriptor(STR_PROP); + definePropertyDescriptor(INT_PROP); + definePropertyDescriptor(BOOL_PROP); + definePropertyDescriptor(LIST_STR_PROP); + } +} +""".stripIndent() + +final String withoutPropsJava = """\ +package ${pkg}; + +import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule; + +public class WithoutPropsRule extends AbstractJavaRule { + // Intentionally no properties +} +""".stripIndent() + +Files.writeString(pkgDir.toPath().resolve('WithPropsRule.java'), withPropsJava, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING) +Files.writeString(pkgDir.toPath().resolve('WithoutPropsRule.java'), withoutPropsJava, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING) + +// 4) Ant project and classpath +Project antProject = new Project() +antProject.init() + +Path cp = new Path(antProject) +resolvedJars.each { jar -> + cp.createPathElement().setPath(jar.absolutePath) +} + +// 5) Compile sources with --release 17 (avoids module-path warning) +Javac javac = new Javac() +javac.setProject(antProject) +javac.setSrcdir(new Path(antProject, srcDir.absolutePath)) +javac.setDestdir(classesDir) +javac.setIncludeantruntime(false) +javac.setClasspath(cp) +// Use "release" instead of source/target to align with JDK 17 modules cleanly +try { + javac.setRelease('17') +} catch (Throwable ignore) { + // Fallback if running on an older Ant: set source/target + javac.setSource('17') + javac.setTarget('17') +} +javac.execute() + +// 6) Create JAR +if (outputJar.exists()) { + outputJar.delete() +} +Jar jar = new Jar() +jar.setProject(antProject) +jar.setDestFile(outputJar) +FileSet fs = new FileSet() +fs.setDir(classesDir) +jar.addFileset(fs) +jar.execute() + +println "Created JAR: ${outputJar.absolutePath}" +println "Contains:" +new File(classesDir, pkg.replace('.', File.separator)).eachFile { f -> + if (f.name.endsWith('.class')) { + println " - ${pkg}.${f.name.replace('.class','')}" + } +} + +// Move file to sonar-pmd-lib/src/test/resources +def moveToFile = new File('../sonar-pmd-lib/src/test/resources/' + outputJar.name) +new File(outputJar.absolutePath).renameTo(moveToFile) +println "Moved to: $moveToFile" + +// Uncomment to remove the temp workspace after build +//Files.walk(workDir).sorted(Comparator.reverseOrder()).forEach { println "$it" } +Files.walk(workDir).sorted(Comparator.reverseOrder()).forEach { println "delete: $it"; it.toFile().delete() } \ No newline at end of file diff --git a/scripts/generate_pmd_all_rules_profile_for_test.groovy b/scripts/generate_pmd_all_rules_profile_for_test.groovy new file mode 100755 index 00000000..5368b648 --- /dev/null +++ b/scripts/generate_pmd_all_rules_profile_for_test.groovy @@ -0,0 +1,96 @@ +#!/usr/bin/env groovy +/** + * Generates a SonarQube quality profile XML (pmd-all-rules.xml) that enables all PMD rules from the + * plugin's rules-java.xml. This uses default rule severities and does not set any parameters (defaults apply). + * + * Usage: + * groovy scripts/generate_pmd_all_rules_profile.groovy [outputPath] + * Defaults: + * - Reads rules from: sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-java.xml + * - Writes to: integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-all-rules.xml + */ +import groovy.xml.MarkupBuilder +import groovy.xml.XmlParser + +// Determine project root based on the script location. +// When run as a script, codeSource.location points to the script file (or compiled class); handle both cases. +def scriptLocation = this.class.protectionDomain?.codeSource?.location +File scriptFile +try { + scriptFile = scriptLocation ? new File(scriptLocation.toURI()) : null +} catch (Exception ignored) { + scriptFile = null +} +File scriptDir = (scriptFile != null && scriptFile.exists()) ? (scriptFile.isFile() ? scriptFile.parentFile : scriptFile) : new File(".").canonicalFile +// scripts/.. -> project root +File projectRoot = scriptDir.parentFile ?: new File(".").canonicalFile + +File rulesFile = new File(projectRoot, "sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-java.xml") +File defaultOut = new File(projectRoot, "integration-test/src/test/resources/com/sonar/it/java/PmdTest/pmd-all-rules.xml") + +File outFile = (this.args && this.args.length > 0) ? new File(this.args[0]) : defaultOut + +if (!rulesFile.isFile()) { + System.err.println("Could not find rules file: " + rulesFile) + System.exit(1) +} + +println "Reading rules from: ${rulesFile.canonicalPath}" +println "Writing profile to: ${outFile.canonicalPath}" + +def root = new XmlParser(false, false).parse(rulesFile) + +def ruleDefs = [] +root.rule.each { r -> + def key = r.key?.text()?.trim() + def severity = r.severity?.text()?.trim() + if (key) { + // collect parameters with default values + def params = [] + r.param.each { p -> + def pKey = p.key?.text()?.trim() + def pDef = p.defaultValue?.text() + if (pKey && pDef != null && pDef.toString().trim().length() > 0) { + params << [key: pKey, value: pDef.toString().trim()] + } + } + ruleDefs << [key: key, severity: (severity ?: 'MAJOR'), params: params] + } +} + +// sort for stable output +ruleDefs.sort { it.key } + +outFile.parentFile.mkdirs() + +def sw = new StringWriter() +def xml = new MarkupBuilder(sw) +xml.mkp.xmlDeclaration(version: '1.0', encoding: 'UTF-8') +xml.profile { + name('pmd-all-rules-profile') + language('java') + rules { + ruleDefs.each { rd -> + rule { + repositoryKey('pmd') + key(rd.key) + priority(rd.severity) + if (rd.params && rd.params.size() > 0) { + parameters { + rd.params.each { param -> + parameter { + key(param.key) + value(param.value) + } + } + } + } else { + parameters {} + } + } + } + } +} + +outFile.text = sw.toString() + System.lineSeparator() +println "Generated ${ruleDefs.size()} rules into ${outFile}" \ No newline at end of file diff --git a/scripts/generate_release_notes.groovy b/scripts/generate_release_notes.groovy new file mode 100755 index 00000000..c5e13e88 --- /dev/null +++ b/scripts/generate_release_notes.groovy @@ -0,0 +1,366 @@ +#!/usr/bin/env groovy + +/** + * PMD Rules Release Notes Generator + * + * This script compares two PMD rule XML files (typically an old version and a new version) + * and generates a Markdown report highlighting: + * 1. Rules that have been removed (present in old file but not in new file) + * 2. Rules that have been added (present in new file but not in old file) + * 3. Rules that remain unchanged (present in both files) + * + * Usage: + * ./generate_release_notes.groovy [options] + * + * Options: + * -o, --old Old rules XML file path (default: scripts/old-rules-$oldVersion.xml) + * -n, --new New rules XML file path (default: sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-java.xml) + * -r, --report Output report file path (default: docs/pmd_release_notes_$version.md) + * -v, --version Version to use in the title + * -ov, --oldversion Old version to use for old rules file name + * -h, --help Show usage information + */ + +import groovy.xml.XmlSlurper +import groovy.cli.commons.CliBuilder +import groovy.json.JsonSlurper + +// Parse command line arguments +def cli = new CliBuilder(usage: 'generate_release_notes.groovy [options]') +cli.with { + o(longOpt: 'old', args: 1, argName: 'file', 'Old rules XML file path') + n(longOpt: 'new', args: 1, argName: 'file', 'New rules XML file path') + r(longOpt: 'report', args: 1, argName: 'file', 'Output report file path') + v(longOpt: 'version', args: 1, argName: 'version', 'Version to use in the title') + ov(longOpt: 'oldversion', args: 1, argName: 'ver', 'Old version to use for old rules file name') + h(longOpt: 'help', 'Show usage information') +} + +def options = cli.parse(args) +if (options.h) { + cli.usage() + return +} + +// Define file paths (use command line args if provided, otherwise use defaults) +def oldVersion = options.ov ?: "UNKNOWN" +def version = options.v ?: "UNKNOWN" +def oldRulesPath = options.o ?: "scripts/old-rules-${oldVersion}.xml" +def newRulesPath = options.n ?: "sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-java.xml" +def outputPath = options.r ?: "docs/pmd_release_notes_${version}.md" + +// Validate file paths +def oldRulesFile = new File(oldRulesPath) +def newRulesFile = new File(newRulesPath) + +if (!oldRulesFile.exists()) { + println "Error: Old rules file not found at ${oldRulesPath}" + System.exit(1) +} + +if (!newRulesFile.exists()) { + println "Error: New rules file not found at ${newRulesPath}" + System.exit(1) +} + +// Create a writer for the output file +def writer + +try { + // Ensure the directory exists + def outputFile = new File(outputPath) + def parentDir = outputFile.getParentFile() + if (parentDir != null && !parentDir.exists()) { + println "Creating directory: ${parentDir.absolutePath}" + parentDir.mkdirs() + } + + writer = outputFile.newWriter() +} catch (Exception e) { + println "Error creating output file: ${e.message}" + System.exit(1) +} + +// Parse XML files +def oldRulesXml +def newRulesXml + +try { + oldRulesXml = new XmlSlurper().parse(oldRulesFile) + newRulesXml = new XmlSlurper().parse(newRulesFile) +} catch (Exception e) { + writer.close() + println "Error parsing XML files: ${e.message}" + System.exit(1) +} + +// Extract rule keys from old rules (same format as new rules: elements) +def oldRules = [] +oldRulesXml.rule.each { rule -> + // Extract category from internalKey if available + def internalKey = rule.internalKey.text() + def category = "" + if (internalKey) { + def parts = internalKey.split('/') + if (parts.length >= 3) { + category = parts[2].split('\\.')[0] + } + } + + // Keep field names compatible with downstream logic: + // - configKey used later for old vs new internal key comparison -> set to internalKey + oldRules << [ + key: rule.key.text(), + configKey: internalKey, + severity: rule.severity.text(), + status: rule.status.text(), + category: category + ] +} + +// Extract rule keys from new rules (they are elements) +def newRules = [] +newRulesXml.rule.each { rule -> + // Extract category from internalKey if available + def internalKey = rule.internalKey.text() + def category = "" + if (internalKey) { + def parts = internalKey.split('/') + if (parts.length >= 3) { + category = parts[2].split('\\.')[0] + } + } + + newRules << [ + key: rule.key.text(), + internalKey: internalKey, + severity: rule.severity.text(), + name: rule.name.text(), + status: rule.status.text(), + category: category + ] +} + +// Function to map severity to SonarQube display values +def mapSeverity(severity) { + switch (severity) { + case "BLOCKER": return "Blocker" + case "CRITICAL": return "High" + case "MAJOR": return "Medium" + case "MINOR": return "Low" + case "INFO": return "Info" + default: return severity + } +} + +// Function to map status values +def mapStatus(status) { + switch (status) { + case "DEPRECATED": return "Deprecated" + default: return status + } +} + +// Function to extract alternative rule references from rule-alternatives-java.json file +def extractAlternativeRule(ruleKey) { + def alternativesFile = new File("scripts/rule-alternatives-java.json") + if (!alternativesFile.exists()) { + return "" + } + + try { + def jsonSlurper = new JsonSlurper() + def alternativesData = jsonSlurper.parse(alternativesFile) + def alternatives = alternativesData.ruleAlternatives[ruleKey] + + if (alternatives) { + def result = [] + alternatives.each { alt -> + result << "[${alt.key}](${alt.link})" + } + return result.join(", ") + } + } catch (Exception e) { + println "Warning: Error reading alternatives from JSON file: ${e.message}" + } + + return "" +} + +// Get sets of rule keys for comparison +def oldRuleKeys = oldRules.collect { it.key } +def newRuleKeys = newRules.collect { it.key } + +// Find rules that are in old but not in new +def removedRules = oldRules.findAll { !newRuleKeys.contains(it.key) } + +// Find rules that are in new but not in old +def addedRules = newRules.findAll { !oldRuleKeys.contains(it.key) } + +// Find rules that exist in both +def commonRuleKeys = oldRuleKeys.intersect(newRuleKeys) +def commonRules = commonRuleKeys.collect { key -> + def oldRule = oldRules.find { it.key == key } + def newRule = newRules.find { it.key == key } + def alternative = extractAlternativeRule(key) + [ + key: key, + oldConfigKey: oldRule.configKey, + newInternalKey: newRule.internalKey, + oldSeverity: oldRule.severity, + newSeverity: newRule.severity, + name: newRule.name, + oldStatus: oldRule.status, + newStatus: newRule.status, + alternative: alternative, + category: newRule.category, // Use the category from the new rule + isUpdated: mapSeverity(oldRule.severity) != mapSeverity(newRule.severity) || + (oldRule.status ?: 'Active') != (newRule.status ?: 'Active') + ] +} + +// Split common rules into updated and unchanged +def updatedRules = commonRules.findAll { it.isUpdated } +def unchangedRules = commonRules.findAll { !it.isUpdated } + +// Initialize and populate renamedRules variable before it's used in the summary +def renamedRules = [] + +// Check for renamed rules information +def oldRulesDir = new File(oldRulesPath).getParentFile() ?: new File(".") +def renamedJavaRulesFile = new File(oldRulesDir, "renamed-java-rules.json") +def renamedKotlinRulesFile = new File(oldRulesDir, "renamed-kotlin-rules.json") + +// Special handling for GuardLogStatementJavaUtil which is renamed to GuardLogStatement +// but not via the deprecated and ref way as the others +def guardLogStatementJavaUtil = removedRules.find { it.key == "GuardLogStatementJavaUtil" } +def guardLogStatement = addedRules.find { it.key == "GuardLogStatement" } + +if (guardLogStatementJavaUtil && guardLogStatement) { + // Add to renamed rules + renamedRules << [ + name: "GuardLogStatementJavaUtil", + ref: "GuardLogStatement", + category: guardLogStatement.category ?: "bestpractices" + ] + + // Remove from removed and added rules to avoid duplication + removedRules.removeIf { it.key == "GuardLogStatementJavaUtil" } + addedRules.removeIf { it.key == "GuardLogStatement" } + + println "Special handling: GuardLogStatementJavaUtil renamed to GuardLogStatement" +} + +// Read renamed Java rules if file exists +if (renamedJavaRulesFile.exists()) { + try { + def jsonSlurper = new JsonSlurper() + def renamedJavaRules = jsonSlurper.parse(renamedJavaRulesFile) + renamedRules.addAll(renamedJavaRules.rules) + println "Found ${renamedJavaRules.count} renamed Java rules" + } catch (Exception e) { + println "Warning: Error reading renamed Java rules file: ${e.message}" + } +} + +// Read renamed Kotlin rules if file exists +if (renamedKotlinRulesFile.exists()) { + try { + def jsonSlurper = new JsonSlurper() + def renamedKotlinRules = jsonSlurper.parse(renamedKotlinRulesFile) + renamedRules.addAll(renamedKotlinRules.rules) + println "Found ${renamedKotlinRules.count} renamed Kotlin rules" + } catch (Exception e) { + println "Warning: Error reading renamed Kotlin rules file: ${e.message}" + } +} + +// Generate report +writer.writeLine("# PMD Rules Release Notes for version $version") +writer.writeLine("_Do not edit this generated file._") +writer.writeLine("\n## Summary") +writer.writeLine("- Total rules in old version ($oldVersion): ${oldRules.size()}") +writer.writeLine("- Total rules in new version ($version): ${newRules.size()}") +writer.writeLine("- Rules added: ${addedRules.size()}") +writer.writeLine("- Rules removed: ${removedRules.size()}") +writer.writeLine("- Rules unchanged: ${unchangedRules.size()}") +writer.writeLine("- Rules updated: ${updatedRules.size()}") +writer.writeLine("- Rules renamed: ${renamedRules.size()}") + +writer.writeLine("\n## Added Rules") +if (addedRules.isEmpty()) { + writer.writeLine("No new rules were added.") +} else { + writer.writeLine("The following rules have been added in the new version:\n") + writer.writeLine("| Rule Key | Name | Severity | Category |") + writer.writeLine("|----------|------|----------|----------|") + addedRules.sort { it.key }.each { rule -> + writer.writeLine("| ${rule.key} | ${rule.name} | ${mapSeverity(rule.severity)} | ${rule.category ?: ''} |") + } +} + +writer.writeLine("\n## Updated Rules") +if (updatedRules.isEmpty()) { + writer.writeLine("No rules have been updated between versions.") +} else { + writer.writeLine("The following rules have been updated in the new version:\n") + writer.writeLine("| Rule Key | Name | Old Severity | New Severity | Old Status | New Status | Alternatives | Category |") + writer.writeLine("|----------|------|--------------|--------------|------------|------------|--------------|----------|") + updatedRules.sort { it.key }.each { rule -> + def oldSeverityDisplay = mapSeverity(rule.oldSeverity) == mapSeverity(rule.newSeverity) ? "" : mapSeverity(rule.oldSeverity) + def newSeverityDisplay = mapSeverity(rule.oldSeverity) == mapSeverity(rule.newSeverity) ? "" : mapSeverity(rule.newSeverity) + def oldStatusDisplay = mapStatus(rule.oldStatus ?: 'Active') == mapStatus(rule.newStatus ?: 'Active') ? "" : mapStatus(rule.oldStatus ?: 'Active') + writer.writeLine("| ${rule.key} | ${rule.name} | ${oldSeverityDisplay} | ${newSeverityDisplay} | ${oldStatusDisplay} | ${mapStatus(rule.newStatus) ?: 'Active'} | ${rule.alternative} | ${rule.category ?: ''} |") + } +} + +writer.writeLine("\n## Unchanged Rules") +if (unchangedRules.isEmpty()) { + writer.writeLine("No rules remain unchanged between versions.") +} else { + writer.writeLine("The following rules exist in both versions with no changes:\n") + writer.writeLine("| Rule Key | Name | Severity | Status | Alternatives | Category |") + writer.writeLine("|----------|------|----------|--------|--------------|----------|") + unchangedRules.sort { it.key }.each { rule -> + writer.writeLine("| ${rule.key} | ${rule.name} | ${mapSeverity(rule.newSeverity)} | ${mapStatus(rule.newStatus) ?: 'Active'} | ${rule.alternative} | ${rule.category ?: ''} |") + } +} + +// Renamed rules have already been processed before generating the summary + + +// Add renamed rules section if any renamed rules were found +if (!renamedRules.isEmpty()) { + writer.writeLine("\n## Renamed Rules") + writer.writeLine("The following rules have new names:\n") + writer.writeLine("| Rule name | New rule name | Category |") + writer.writeLine("|-----------|---------------|----------|") + renamedRules.sort { it.name }.each { rule -> + writer.writeLine("| ${rule.name} | ${rule.ref} | ${rule.category} |") + } +} + +writer.writeLine("\n## Removed Rules") +if (removedRules.isEmpty()) { + writer.writeLine("No rules were removed.") +} else { + writer.writeLine("The following rules have been removed in the new version:") + writer.writeLine("\n| Rule Key | Priority | Status | Category |") + writer.writeLine("|----------|----------|--------|----------|") + removedRules.sort { it.key }.each { rule -> + writer.writeLine("| ${rule.key} | ${mapSeverity(rule.severity)} | ${mapStatus(rule.status) ?: 'Active'} | ${rule.category ?: ''} |") + } +} + +writer.writeLine("\nReport generated on ${new Date()}") + +// Close the writer +try { + writer.close() + // Print a message to the console + println "Release notes generated in ${outputPath}" +} catch (Exception e) { + println "Warning: Error closing output file: ${e.message}" + // Still inform the user that the report was generated + println "Release notes generated in ${outputPath}" +} diff --git a/scripts/old-rules-4.1.0.xml b/scripts/old-rules-4.1.0.xml new file mode 100644 index 00000000..bdca88e3 --- /dev/null +++ b/scripts/old-rules-4.1.0.xml @@ -0,0 +1,7582 @@ + + + + AbstractClassWithoutAbstractMethod + Abstract class without abstract method + category/java/bestpractices.xml/AbstractClassWithoutAbstractMethod + MAJOR + Title of issues: This abstract class does not have any abstract methods +

The abstract class does not contain any abstract methods. An abstract class suggests +an incomplete implementation, which is to be completed by subclasses implementing the +abstract methods. If the class is intended to be used as a base class only (not to be instantiated +directly) a protected constructor can be provided to prevent direct instantiation.

+

Example

+

 public abstract class Foo {
+   void int method1() { ... }
+   void int method2() { ... }
+   // consider using abstract methods or removing
+   // the abstract modifier and adding protected constructors
+ }

+

Alternative rule: java:S1694

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + AbstractClassWithoutAnyMethod + Abstract class without any method + category/java/design.xml/AbstractClassWithoutAnyMethod + BLOCKER + Title of issues: No abstract method which means that the keyword is most likely used to prevent instantiation. Use a private or protected constructor instead. +

If an abstract class does not provide any methods, it may be acting as a simple data container +that is not meant to be instantiated. In this case, it is probably better to use a private or +protected constructor in order to prevent instantiation than make the class misleadingly abstract.

+

Example

+

 public abstract class Example {
+     String field;
+     int otherField;
+ }

+

Alternative rule: java:S1694

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + AccessorClassGeneration + Accessor class generation + category/java/bestpractices.xml/AccessorClassGeneration + MAJOR + Title of issues: Avoid instantiation through private constructors from outside of the constructor's class. +

Instantiation by way of private constructors from outside the constructor's class often causes the +generation of an accessor. A factory method, or non-privatization of the constructor can eliminate this +situation. The generated class file is actually an interface. It gives the accessing class the ability +to invoke a new hidden package scope constructor that takes the interface as a supplementary parameter. +This turns a private constructor effectively into one with package scope, and is challenging to discern.

+

Note: This rule is only executed for Java 10 or lower. +Since Java 11, JEP 181: Nest-Based Access Control has been implemented. This +means that in Java 11 and above accessor classes are not generated anymore.

+

Example

+

 public class Outer {
+  void method(){
+   Inner ic = new Inner();//Causes generation of accessor class
+  }
+  public class Inner {
+   private Inner(){}
+  }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + AccessorMethodGeneration + Accessor method generation + category/java/bestpractices.xml/AccessorMethodGeneration + MAJOR + Title of issues: Consider giving this member package visibility to access it from {0} without a synthetic accessor method +

When accessing private fields / methods from another class, the Java compiler will generate accessor methods +with package-private visibility. This adds overhead, and to the dex method count on Android. This situation can +be avoided by changing the visibility of the field / method from private to package-private.

+

Note: This rule is only executed for Java 10 or lower. +Since Java 11, JEP 181: Nest-Based Access Control has been implemented. This +means that in Java 11 and above accessor classes are not generated anymore.

+

Example

+

 public class OuterClass {
+     private int counter;
+     /* package */ int id;
+
+     public class InnerClass {
+         InnerClass() {
+             OuterClass.this.counter++; // wrong accessor method will be generated
+         }
+
+         public int getOuterClassId() {
+             return OuterClass.this.id; // id is package-private, no accessor method needed
+         }
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + AddEmptyString + Add empty string + category/java/performance.xml/AddEmptyString + MAJOR + Title of issues: Do not add empty strings +

The conversion of literals to strings by concatenating them with empty strings is inefficient. +It is much better to use one of the type-specific toString() methods instead or String.valueOf().

+

Example

+

 String s = "" + 123;                // inefficient
+ String t = Integer.toString(456);   // preferred approach

+

Full documentation

]]>
+ pmd + performance +
+ + AppendCharacterWithChar + Append character with char + category/java/performance.xml/AppendCharacterWithChar + MAJOR + Title of issues: Avoid appending characters as strings in StringBuffer.append. +

Avoid concatenating characters as strings in StringBuffer/StringBuilder.append methods.

+

Example

+

 StringBuffer sb = new StringBuffer();
+ sb.append("a");     // avoid this
+
+ StringBuffer sb = new StringBuffer();
+ sb.append('a');     // use this instead

+

Full documentation

]]>
+ pmd + performance +
+ + ArrayIsStoredDirectly + Array is stored directly + category/java/bestpractices.xml/ArrayIsStoredDirectly + MAJOR + Title of issues: The user-supplied array '{0}' is stored directly. +

Constructors and methods receiving arrays should clone objects and store the copy. +This prevents future changes from the user from affecting the original array.

+

Example

+

 public class Foo {
+     private String [] x;
+         public void foo (String [] param) {
+         // Don't do this, make a copy of the array at least
+         this.x=param;
+     }
+ }

+

Alternative rule: java:S2384

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + AssignmentInOperand + Assignment in operand + category/java/errorprone.xml/AssignmentInOperand + MAJOR + Title of issues: Avoid assignments in operands +

Avoid assignments in operands; this can make code more complicated and harder to read.

+

Example

+

 public void bar() {
+     int x = 2;
+     if ((x = getX()) == 3) {
+       System.out.println("3!");
+     }
+ }

+

Alternative rule: java:S1121

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AssignmentToNonFinalStatic + Assignment to non final static + category/java/errorprone.xml/AssignmentToNonFinalStatic + MAJOR + Title of issues: Possible unsafe assignment to non-final static field '{0}' in a constructor. +

Identifies a possible unsafe usage of a static field.

+

Example

+

 public class StaticField {
+    static int x;
+    public FinalFields(int y) {
+     x = y; // unsafe
+    }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + AtLeastOneConstructor + At least one constructor + category/java/codestyle.xml/AtLeastOneConstructor + MAJOR + Title of issues: Each class should declare at least one constructor +

Each non-static class should declare at least one constructor. +Classes with solely static members are ignored, refer to UseUtilityClassRule to detect those.

+

Example

+

 public class Foo {
+    // missing constructor
+   public void doSomething() { ... }
+   public void doOtherThing { ... }
+ }

+

Alternative rules: java:S1118, java:S1258

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + AvoidAccessibilityAlteration + Avoid accessibility alteration + category/java/errorprone.xml/AvoidAccessibilityAlteration + MAJOR + Title of issues: You should not modify visibility of constructors, methods or fields using setAccessible() +

Methods such as getDeclaredConstructors(), getDeclaredMethods(), and getDeclaredFields() also +return private constructors, methods and fields. These can be made accessible by calling setAccessible(true). +This gives access to normally protected data which violates the principle of encapsulation.

+

This rule detects calls to setAccessible and finds possible accessibility alterations. +If the call to setAccessible is wrapped within a PrivilegedAction, then the access alteration +is assumed to be deliberate and is not reported.

+

Note that with Java 17 the Security Manager, which is used for PrivilegedAction execution, +is deprecated: JEP 411: Deprecate the Security Manager for Removal. +For future-proof code, deliberate access alteration should be suppressed using the usual +suppression methods (e.g. by using @SuppressWarnings annotation).

+

Example

+

 import java.lang.reflect.Constructor;
+ import java.lang.reflect.Field;
+ import java.lang.reflect.Method;
+ import java.security.AccessController;
+ import java.security.PrivilegedAction;
+
+ public class Violation {
+     private void invalidSetAccessCalls() throws NoSuchMethodException, SecurityException {
+         Constructor<?> constructor = this.getClass().getDeclaredConstructor(String.class);
+         // call to forbidden setAccessible
+         constructor.setAccessible(true);
+
+         Method privateMethod = this.getClass().getDeclaredMethod("aPrivateMethod");
+         // call to forbidden setAccessible
+         privateMethod.setAccessible(true);
+
+         // deliberate accessibility alteration
+         String privateField = AccessController.doPrivileged(new PrivilegedAction<String>() {
+             @Override
+             public String run() {
+                 try {
+                     Field field = Violation.class.getDeclaredField("aPrivateField");
+                     field.setAccessible(true);
+                     return (String) field.get(null);
+                 } catch (ReflectiveOperationException | SecurityException e) {
+                     throw new RuntimeException(e);
+                 }
+             }
+         });
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + AvoidArrayLoops + Avoid array loops + category/java/performance.xml/AvoidArrayLoops + MAJOR + Title of issues: Arrays.copyOf or System.arraycopy are more efficient +

Instead of manually copying data between two arrays, use the more efficient Arrays.copyOf +or System.arraycopy method instead.

+

To copy only part of the array, use Arrays.copyOfRange or System.arraycopy.

+

If you want to copy/move elements inside the _same_ array (e.g. shift the elements), use System.arraycopy.

+

Examples

+

Example 1

+

 class Scratch {
+     void copy_a_to_b() {
+         int[] a = new int[10];
+         int[] b = new int[10];
+         for (int i = 0; i < a.length; i++) {
+             b[i] = a[i];
+         }
+         // equivalent
+         b = Arrays.copyOf(a, a.length);
+         // equivalent
+         System.arraycopy(a, 0, b, 0, a.length);
+
+         int[] c = new int[10];
+         // this will not trigger the rule
+         for (int i = 0; i < c.length; i++) {
+             b[i] = a[c[i]];
+         }
+     }
+ }

+

Example 2

+

 class Scratch {
+     void shift_left(int[] a) {
+         for (int i = 0; i < a.length - 1; i++) {
+             a[i] = a[i + 1];
+         }
+         // equivalent
+         System.arraycopy(a, 1, a, 0, a.length - 1);
+     }
+     void shift_right(int[] a) {
+         for (int i = a.length - 1; i > 0; i--) {
+             a[i] = a[i - 1];
+         }
+         // equivalent
+         System.arraycopy(a, 0, a, 1, a.length - 1);
+     }
+ }

+

Full documentation

]]>
+ pmd + performance +
+ + AvoidAssertAsIdentifier + Avoid assert as identifier + category/java/errorprone.xml/AvoidAssertAsIdentifier + CRITICAL + Title of issues: Avoid using assert as an identifier; it became a reserved word in JDK 1.4 +

Use of the term assert will conflict with newer versions of Java since it is a reserved word.

+

Since Java 1.4, the token assert became a reserved word and using it as an identifier will +result in a compilation failure for Java 1.4 and later. This rule is therefore only useful +for old Java code before Java 1.4. It can be used to identify problematic code prior to a Java update.

+

Example

+

 public class A {
+     public class Foo {
+         String assert = "foo";
+     }
+ }

+

Alternative rule: java:S1190

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidBranchingStatementAsLastInLoop + Avoid branching statement as last in loop + category/java/errorprone.xml/AvoidBranchingStatementAsLastInLoop + CRITICAL + Title of issues: Avoid using a branching statement as the last in a loop. +

Using a branching statement as the last part of a loop may be a bug, and/or is confusing. +Ensure that the usage is not a bug, or consider using another approach.

+

Example

+

 // unusual use of branching statement in a loop
+ for (int i = 0; i < 10; i++) {
+     if (i*i <= 25) {
+         continue;
+     }
+     break;
+ }
+
+ // this makes more sense...
+ for (int i = 0; i < 10; i++) {
+     if (i*i > 25) {
+         break;
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + AvoidCalendarDateCreation + Avoid calendar date creation + category/java/performance.xml/AvoidCalendarDateCreation + MAJOR + Title of issues: A Calendar is used to get the current time, this is expensive. +

Problem: java.util.Calendar is a heavyweight object and expensive to create. It should only be used, if +calendar calculations are needed.

+

Solution: Use new Date(), Java 8+ java.time.LocalDateTime.now() or ZonedDateTime.now().

+

Example

+

 import java.time.LocalDateTime;
+ import java.util.Calendar;
+ import java.util.Date;
+
+ public class DateStuff {
+     private Date bad1() {
+         return Calendar.getInstance().getTime(); // now
+     }
+     private Date good1a() {
+         return new Date(); // now
+     }
+     private LocalDateTime good1b() {
+         return LocalDateTime.now();
+     }
+     private long bad2() {
+         return Calendar.getInstance().getTimeInMillis();
+     }
+     private long good2() {
+         return System.currentTimeMillis();
+     }
+ }

+

Full documentation

]]>
+ pmd + performance +
+ + AvoidCallingFinalize + Avoid calling finalize + category/java/errorprone.xml/AvoidCallingFinalize + MAJOR + Title of issues: Avoid calling finalize() explicitly +

The method Object.finalize() is called by the garbage collector on an object when garbage collection determines +that there are no more references to the object. It should not be invoked by application logic.

+

Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

+

Example

+

 void foo() {
+     Bar b = new Bar();
+     b.finalize();
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + AvoidCatchingGenericException + Avoid catching generic exception + category/java/design.xml/AvoidCatchingGenericException + MAJOR + Title of issues: Avoid catching generic exceptions such as NullPointerException, RuntimeException, Exception in try-catch block +

Avoid catching generic exceptions such as NullPointerException, RuntimeException, Exception in try-catch block.

+

Example

+

 package com.igate.primitive;
+
+ public class PrimitiveType {
+
+     public void downCastPrimitiveType() {
+         try {
+             System.out.println(" i [" + i + "]");
+         } catch(Exception e) {
+             e.printStackTrace();
+         } catch(RuntimeException e) {
+             e.printStackTrace();
+         } catch(NullPointerException e) {
+             e.printStackTrace();
+         }
+     }
+ }

+

Alternative rule: java:S2221

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + AvoidCatchingNPE + Avoid catching NPE + category/java/errorprone.xml/AvoidCatchingNPE + MAJOR + Title of issues: Avoid catching NullPointerException; consider removing the cause of the NPE. +

Code should never throw NullPointerExceptions under normal circumstances. A catch block may hide the +original error, causing other, more subtle problems later on.

+

Example

+

 public class Foo {
+     void bar() {
+         try {
+             // do something
+         } catch (NullPointerException npe) {
+         }
+     }
+ }

+

Alternative rule: java:S1696

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidCatchingThrowable + Avoid catching throwable + category/java/errorprone.xml/AvoidCatchingThrowable + MAJOR + Title of issues: A catch statement should never catch throwable since it includes errors. +

Catching Throwable errors is not recommended since its scope is very broad. It includes runtime issues such as +OutOfMemoryError that should be exposed and managed separately.

+

Example

+

 public void bar() {
+     try {
+         // do something
+     } catch (Throwable th) {  // should not catch Throwable
+         th.printStackTrace();
+     }
+ }

+

Alternative rule: java:S1181

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidDecimalLiteralsInBigDecimalConstructor + Avoid decimal literals in big decimal constructor + category/java/errorprone.xml/AvoidDecimalLiteralsInBigDecimalConstructor + MAJOR + Title of issues: Avoid creating BigDecimal with a decimal (float/double) literal. Use a String literal +

One might assume that the result of "new BigDecimal(0.1)" is exactly equal to 0.1, but it is actually +equal to .1000000000000000055511151231257827021181583404541015625. +This is because 0.1 cannot be represented exactly as a double (or as a binary fraction of any finite +length). Thus, the long value that is being passed in to the constructor is not exactly equal to 0.1, +appearances notwithstanding.

+

The (String) constructor, on the other hand, is perfectly predictable: 'new BigDecimal("0.1")' is +exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the +(String) constructor be used in preference to this one.

+

Example

+

 BigDecimal bd = new BigDecimal(1.123);       // loss of precision, this would trigger the rule
+
+ BigDecimal bd = new BigDecimal("1.123");     // preferred approach
+
+ BigDecimal bd = new BigDecimal(12);          // preferred approach, ok for integer values

+

Alternative rule: java:S2111

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidDeeplyNestedIfStmts + Avoid deeply nested if stmts + category/java/design.xml/AvoidDeeplyNestedIfStmts + MAJOR + Title of issues: Deeply nested if..then statements are hard to read +

Avoid creating deeply nested if-then statements since they are harder to read and error-prone to maintain.

+

Example

+

 public class Foo {
+   public void bar(int x, int y, int z) {
+     if (x>y) {
+       if (y>z) {
+         if (z==x) {
+          // !! too deep
+         }
+       }
+     }
+   }
+ }

+

Alternative rule: java:S134

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + AvoidDollarSigns + Avoid dollar signs + category/java/codestyle.xml/AvoidDollarSigns + MAJOR + Title of issues: Avoid using dollar signs in variable/method/class/interface names +

Avoid using dollar signs in variable/method/class/interface names.

+

Example

+

 public class Fo$o {  // not a recommended name
+ }

+

Alternative rules: java:S114, java:S115, java:S116, java:S117

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + AvoidDuplicateLiterals + Avoid duplicate literals + category/java/errorprone.xml/AvoidDuplicateLiterals + MAJOR + Title of issues: The String literal {0} appears {1} times in this file; the first occurrence is on line {2} +

Code containing duplicate String literals can usually be improved by declaring the String as a constant field.

+

Example

+

 private void bar() {
+      buz("Howdy");
+      buz("Howdy");
+      buz("Howdy");
+      buz("Howdy");
+ }
+ private void buz(String x) {}

+

Alternative rule: java:S1192

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidEnumAsIdentifier + Avoid enum as identifier + category/java/errorprone.xml/AvoidEnumAsIdentifier + CRITICAL + Title of issues: Avoid using enum as an identifier; it's a reserved word in JDK 1.5 +

Use of the term enum will conflict with newer versions of Java since it is a reserved word.

+

Since Java 1.5, the token enum became a reserved word and using it as an identifier will +result in a compilation failure for Java 1.5 and later. This rule is therefore only useful +for old Java code before Java 1.5. It can be used to identify problematic code prior to a Java update.

+

Example

+

 public class A {
+     public class Foo {
+         String enum = "foo";
+     }
+ }

+

Alternative rule: java:S1190

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidFieldNameMatchingMethodName + Avoid field name matching method name + category/java/errorprone.xml/AvoidFieldNameMatchingMethodName + MAJOR + Title of issues: Field {0} has the same name as a method +

It can be confusing to have a field name with the same name as a method. While this is permitted, +having information (field) and actions (method) is not clear naming. Developers versed in +Smalltalk often prefer this approach as the methods denote accessor methods.

+

Example

+

 public class Foo {
+     Object bar;
+     // bar is data or an action or both?
+     void bar() {
+     }
+ }

+

Alternative rule: java:S1845

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidFieldNameMatchingTypeName + Avoid field name matching type name + category/java/errorprone.xml/AvoidFieldNameMatchingTypeName + MAJOR + Title of issues: 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.

+

Example

+

 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
+ }

+

Alternative rule: java:S1700

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidFileStream + Avoid file stream + category/java/performance.xml/AvoidFileStream + BLOCKER + Title of issues: Avoid instantiating FileInputStream, FileOutputStream, FileReader, or FileWriter +

The FileInputStream and FileOutputStream classes contains a finalizer method which will cause garbage +collection pauses. +See JDK-8080225 for details.

+

The FileReader and FileWriter constructors instantiate FileInputStream and FileOutputStream, +again causing garbage collection issues while finalizer methods are called.

+
  • Use Files.newInputStream(Paths.get(fileName)) instead of new FileInputStream(fileName).
  • Use Files.newOutputStream(Paths.get(fileName)) instead of new FileOutputStream(fileName).
  • Use Files.newBufferedReader(Paths.get(fileName)) instead of new FileReader(fileName).
  • Use Files.newBufferedWriter(Paths.get(fileName)) instead of new FileWriter(fileName).
+

Please note, that the java.nio API does not throw a FileNotFoundException anymore, instead +it throws a NoSuchFileException. If your code dealt explicitly with a FileNotFoundException, +then this needs to be adjusted. Both exceptions are subclasses of IOException, so catching +that one covers both.

+

Example

+

 // these instantiations cause garbage collection pauses, even if properly closed
+
+     FileInputStream fis = new FileInputStream(fileName);
+     FileOutputStream fos = new FileOutputStream(fileName);
+     FileReader fr = new FileReader(fileName);
+     FileWriter fw = new FileWriter(fileName);
+
+     // the following instantiations help prevent Garbage Collection pauses, no finalization
+
+     try(InputStream is = Files.newInputStream(Paths.get(fileName))) {
+     }
+     try(OutputStream os = Files.newOutputStream(Paths.get(fileName))) {
+     }
+     try(BufferedReader br = Files.newBufferedReader(Paths.get(fileName), StandardCharsets.UTF_8)) {
+     }
+     try(BufferedWriter wr = Files.newBufferedWriter(Paths.get(fileName), StandardCharsets.UTF_8)) {
+     }

+

Full documentation

]]>
+ pmd + performance +
+ + AvoidInstanceofChecksInCatchClause + Avoid instanceof checks in catch clause + category/java/errorprone.xml/AvoidInstanceofChecksInCatchClause + MAJOR + Title of issues: An instanceof check is being performed on the caught exception. Create a separate catch clause for this exception type. +

Each caught exception type should be handled in its own catch clause.

+

Example

+

 try { // Avoid this
+     // do something
+ } catch (Exception ee) {
+     if (ee instanceof IOException) {
+         cleanup();
+     }
+ }
+
+ try {  // Prefer this:
+     // do something
+ } catch (IOException ee) {
+     cleanup();
+ }

+

Alternative rule: java:S1193

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidInstantiatingObjectsInLoops + Avoid instantiating objects in loops + category/java/performance.xml/AvoidInstantiatingObjectsInLoops + MAJOR + Title of issues: Avoid instantiating new objects inside loops +

New objects created within loops should be checked to see if they can created outside them and reused.

+

Example

+

 public class Something {
+     public static void main( String as[] ) {
+         for (int i = 0; i < 10; i++) {
+             Foo f = new Foo(); // Avoid this whenever you can it's really expensive
+         }
+     }
+ }

+

Full documentation

]]>
+ pmd + performance +
+ + AvoidLiteralsInIfCondition + Avoid literals in if condition + category/java/errorprone.xml/AvoidLiteralsInIfCondition + MAJOR + Title of issues: Avoid using literals in if statements +

Avoid using hard-coded literals in conditional statements. By declaring them as static variables +or private members with descriptive names maintainability is enhanced. By default, the literals "-1" and "0" are ignored. +More exceptions can be defined with the property "ignoreMagicNumbers".

+

The rule doesn't consider deeper expressions by default, but this can be enabled via the property ignoreExpressions. +With this property set to false, if-conditions like i == 1 + 5 are reported as well. Note that in that case, +the property ignoreMagicNumbers is not taken into account, if there are multiple literals involved in such an expression.

+

Example

+

 private static final int MAX_NUMBER_OF_REQUESTS = 10;
+
+ public void checkRequests() {
+
+     if (i == 10) {                        // magic number, buried in a method
+       doSomething();
+     }
+
+     if (i == MAX_NUMBER_OF_REQUESTS) {    // preferred approach
+       doSomething();
+     }
+
+     if (aString.indexOf('.') != -1) {}     // magic number -1, by default ignored
+     if (aString.indexOf('.') >= 0) { }     // alternative approach
+
+     if (aDouble > 0.0) {}                  // magic number 0.0
+     if (aDouble >= Double.MIN_VALUE) {}    // preferred approach
+
+     // with rule property "ignoreExpressions" set to "false"
+     if (i == pos + 5) {}  // violation: magic number 5 within an (additive) expression
+     if (i == pos + SUFFIX_LENGTH) {} // preferred approach
+     if (i == 5 && "none".equals(aString)) {} // 2 violations: magic number 5 and literal "none"
+ }

+

Alternative rule: java:S109

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative + + ignoreMagicNumbers + + -1,0 + STRING + + + ignoreExpressions + + true + BOOLEAN + +
+ + AvoidLosingExceptionInformation + Avoid losing exception information + category/java/errorprone.xml/AvoidLosingExceptionInformation + CRITICAL + Title of issues: Avoid statements in a catch block that invoke accessors on the exception without using the information +

Statements in a catch block that invoke accessors on the exception without using the information +only add to code size. Either remove the invocation, or use the return result.

+

Example

+

 public void bar() {
+     try {
+         // do something
+     } catch (SomeException se) {
+         se.getMessage();
+     }
+ }

+

Alternative rule: java:S1166

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidMessageDigestField + Avoid message digest field + category/java/bestpractices.xml/AvoidMessageDigestField + MAJOR + Title of issues: You shouldn't declare field of MessageDigest type, because unsynchronized access could cause problems +

Declaring a MessageDigest instance as a field make this instance directly available to multiple threads. + Such sharing of MessageDigest instances should be avoided if possible since it leads to wrong results + if the access is not synchronized correctly. + Just create a new instance and use it locally, where you need it. + Creating a new instance is easier than synchronizing access to a shared instance.

+

Example

+

 import java.security.MessageDigest;
+ public class AvoidMessageDigestFieldExample {
+     private final MessageDigest sharedMd;
+     public AvoidMessageDigestFieldExample() throws Exception {
+         sharedMd = MessageDigest.getInstance("SHA-256");
+     }
+     public byte[] calculateHashShared(byte[] data) {
+         // sharing a MessageDigest like this without synchronizing access
+         // might lead to wrong results
+         sharedMd.reset();
+         sharedMd.update(data);
+         return sharedMd.digest();
+     }
+
+     // better
+     public byte[] calculateHash(byte[] data) throws Exception {
+         MessageDigest md = MessageDigest.getInstance("SHA-256");
+         md.update(data);
+         return md.digest();
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + AvoidMultipleUnaryOperators + Avoid multiple unary operators + category/java/errorprone.xml/AvoidMultipleUnaryOperators + CRITICAL + Title of issues: Using multiple unary operators may be a bug, and/or is confusing. +

The use of multiple unary operators may be problematic, and/or confusing. +Ensure that the intended usage is not a bug, or consider simplifying the expression.

+

Example

+

 // These are typo bugs, or at best needlessly complex and confusing:
+ int i = - -1;
+ int j = + - +1;
+ int z = ~~2;
+ boolean b = !!true;
+ boolean c = !!!true;
+
+ // These are better:
+ int i = 1;
+ int j = -1;
+ int z = 2;
+ boolean b = true;
+ boolean c = false;
+
+ // And these just make your brain hurt:
+ int i = ~-2;
+ int j = -~7;

+

Alternative rule: java:S881

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidPrintStackTrace + Avoid print stack trace + category/java/bestpractices.xml/AvoidPrintStackTrace + MAJOR + Title of issues: Avoid printStackTrace(); use a logger call instead. +

Avoid printStackTrace(); use a logger call instead.

+

Example

+

 class Foo {
+     void bar() {
+         try {
+             // do something
+         } catch (Exception e) {
+             e.printStackTrace();
+         }
+     }
+ }

+

Alternative rule: java:S1148

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + AvoidProtectedFieldInFinalClass + Avoid protected field in final class + category/java/codestyle.xml/AvoidProtectedFieldInFinalClass + MAJOR + Title of issues: Avoid protected fields in a final class. Change to private or package access. +

Do not use protected fields in final classes since they cannot be subclassed. +Clarify your intent by using private or package access modifiers instead.

+

Example

+

 public final class Bar {
+   private int x;
+   protected int y;  // bar cannot be subclassed, so is y really private or package visible?
+   Bar() {}
+ }

+

Alternative rule: java:S2156

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + AvoidProtectedMethodInFinalClassNotExtending + Avoid protected method in final class not extending + category/java/codestyle.xml/AvoidProtectedMethodInFinalClassNotExtending + MAJOR + Title of issues: Avoid protected methods in a final class that doesn't extend anything other than Object. Change to private or package access. +

Do not use protected methods in most final classes since they cannot be subclassed. This should +only be allowed in final classes that extend other classes with protected methods (whose +visibility cannot be reduced). Clarify your intent by using private or package access modifiers instead.

+

Example

+

 public final class Foo {
+   private int bar() {}
+   protected int baz() {} // Foo cannot be subclassed, and doesn't extend anything, so is baz() really private or package visible?
+ }

+

Alternative rule: java:S2156

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + AvoidReassigningCatchVariables + Avoid reassigning catch variables + category/java/bestpractices.xml/AvoidReassigningCatchVariables + MAJOR + Title of issues: Avoid reassigning caught exception '{0}' +

Reassigning exception variables caught in a catch statement should be avoided because of:

+

1) If it is needed, multi catch can be easily added and code will still compile.

+

2) Following the principle of least surprise we want to make sure that a variable caught in a catch statement +is always the one thrown in a try block.

+

Example

+

 public class Foo {
+     public void foo() {
+         try {
+             // do something
+         } catch (Exception e) {
+             e = new NullPointerException(); // not recommended
+         }
+
+         try {
+             // do something
+         } catch (MyException | ServerException e) {
+             e = new RuntimeException(); // won't compile
+         }
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + AvoidReassigningLoopVariables + Avoid reassigning loop variables + category/java/bestpractices.xml/AvoidReassigningLoopVariables + MAJOR + Title of issues: Avoid reassigning the loop control variable '{0}' +

Reassigning loop variables can lead to hard-to-find bugs. Prevent or limit how these variables can be changed.

+

In foreach-loops, configured by the foreachReassign property:

+

In for-loops, configured by the forReassign property:

+
  • deny: Report any reassignment of the loop variable in the loop body. _This is the default._
  • allow: Don't check the loop variable.
  • firstOnly: Report any reassignments of the loop variable, except as the first statement in the loop body. _This is useful if some kind of normalization or clean-up of the value before using is permitted, but any other change of the variable is not._
+
  • deny: Report any reassignment of the control variable in the loop body. _This is the default._
  • allow: Don't check the control variable.
  • skip: Report any reassignments of the control variable, except conditional increments/decrements (++, --, +=, -=). _This prevents accidental reassignments or unconditional increments of the control variable._
+

Example

+

 public class Foo {
+   private void foo() {
+     for (String s : listOfStrings()) {
+       s = s.trim(); // OK, when foreachReassign is "firstOnly" or "allow"
+       doSomethingWith(s);
+
+       s = s.toUpper(); // OK, when foreachReassign is "allow"
+       doSomethingElseWith(s);
+     }
+
+     for (int i=0; i < 10; i++) {
+       if (check(i)) {
+         i++; // OK, when forReassign is "skip" or "allow"
+       }
+
+       i = 5;  // OK, when forReassign is "allow"
+
+       doSomethingWith(i);
+     }
+   }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + AvoidReassigningParameters + Avoid reassigning parameters + category/java/bestpractices.xml/AvoidReassigningParameters + CRITICAL + Title of issues: Avoid reassigning parameters such as '{0}' +

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.

+

Example

+

 public class Hello {
+   private void greet(String name) {
+     name = name.trim();
+     System.out.println("Hello " + name);
+
+     // preferred
+     String trimmedName = name.trim();
+     System.out.println("Hello " + trimmedName);
+   }
+ }

+

Alternative rule: java:S1226

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + AvoidRethrowingException + Avoid rethrowing exception + category/java/design.xml/AvoidRethrowingException + MAJOR + Title of issues: A catch statement that catches an exception only to rethrow it should be avoided. +

Catch blocks that merely rethrow a caught exception only add to code size and runtime complexity.

+

Example

+

 public void bar() {
+     try {
+         // do something
+     }  catch (SomeException se) {
+        throw se;
+     }
+ }

+

Alternative rule: java:S1166

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + AvoidStringBufferField + Avoid string buffer field + category/java/bestpractices.xml/AvoidStringBufferField + MAJOR + Title of issues: StringBuffers can grow quite a lot, and so may become a source of memory leak (if the owning class has a long life time). +

StringBuffers/StringBuilders can grow considerably, and so may become a source of memory leaks +if held within objects with long lifetimes.

+

Example

+

 public class Foo {
+     private StringBuffer buffer;    // potential memory leak as an instance variable;
+ }

+

Alternative rule: java:S1149

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + AvoidSynchronizedAtMethodLevel + Avoid synchronized at method level + category/java/multithreading.xml/AvoidSynchronizedAtMethodLevel + MAJOR + Title of issues: Use block level locking rather than method level synchronization +

Method-level synchronization will pin virtual threads and can cause performance problems. Additionally, it can cause +problems when new code is added to the method. Block-level ReentrantLock helps to ensure that only the code that +needs mutual exclusion will be locked.

+

Example

+

 public class Foo {
+     // Try to avoid this:
+     synchronized void foo() {
+         // code, that doesn't need synchronization
+         // ...
+         // code, that requires synchronization
+         if (!sharedData.has("bar")) {
+             sharedData.add("bar");
+         }
+         // more code, that doesn't need synchronization
+         // ...
+     }
+     // Prefer this:
+     Lock instanceLock = new ReentrantLock();
+
+     void bar() {
+         // code, that doesn't need synchronization
+         // ...
+         try {
+             instanceLock.lock();  // or instanceLock.tryLock(long time, TimeUnit unit)
+             if (!sharedData.has("bar")) {
+                 sharedData.add("bar");
+             }
+         } finally {
+             instanceLock.unlock();
+         }
+         // more code, that doesn't need synchronization
+         // ...
+     }
+
+     // Try to avoid this for static methods:
+     static synchronized void fooStatic() {
+     }
+
+     // Prefer this:
+     private static Lock CLASS_LOCK = new ReentrantLock();
+
+     static void barStatic() {
+         // code, that doesn't need synchronization
+         // ...
+         try {
+             CLASS_LOCK.lock();
+             // code, that requires synchronization
+         } finally {
+             CLASS_LOCK.unlock();
+         }
+         // more code, that doesn't need synchronization
+         // ...
+     }
+ }

+

Full documentation

]]>
+ pmd + multithreading +
+ + AvoidSynchronizedStatement + Avoid synchronized statement + category/java/multithreading.xml/AvoidSynchronizedStatement + MAJOR + Title of issues: Use ReentrantLock rather than synchronization +

Synchronization will pin virtual threads and can cause performance problems.

+

Example

+

 public class Foo {
+     // Try to avoid this:
+     void foo() {
+         // code that doesn't need mutual exclusion
+         synchronized(this) {
+             // code that requires mutual exclusion
+         }
+         // more code that doesn't need mutual exclusion
+     }
+     // Prefer this:
+     Lock instanceLock = new ReentrantLock();
+
+     void foo() {
+         // code that doesn't need mutual exclusion
+         try {
+             instanceLock.lock();  // or instanceLock.tryLock(long time, TimeUnit unit)
+             // code that requires mutual exclusion
+         } finally {
+             instanceLock.unlock();
+         }
+         // more code that doesn't need mutual exclusion
+     }
+ }

+

Full documentation

]]>
+ pmd + multithreading +
+ + AvoidThreadGroup + Avoid thread group + category/java/multithreading.xml/AvoidThreadGroup + MAJOR + Title of issues: Avoid using java.lang.ThreadGroup; it is not thread safe +

Avoid using java.lang.ThreadGroup; although it is intended to be used in a threaded environment +it contains methods that are not thread-safe.

+

Example

+

 public class Bar {
+     void buz() {
+         ThreadGroup tg = new ThreadGroup("My threadgroup");
+         tg = new ThreadGroup(tg, "my thread group");
+         tg = Thread.currentThread().getThreadGroup();
+         tg = System.getSecurityManager().getThreadGroup();
+     }
+ }

+

Full documentation

]]>
+ pmd + multithreading +
+ + AvoidThrowingNewInstanceOfSameException + Avoid throwing new instance of same exception + category/java/design.xml/AvoidThrowingNewInstanceOfSameException + MAJOR + Title of issues: A catch statement that catches an exception only to wrap it in a new instance of the same type of exception and throw it should be avoided +

Catch blocks that merely rethrow a caught exception wrapped inside a new instance of the same type only add to +code size and runtime complexity.

+

Example

+

 public void bar() {
+     try {
+         // do something
+     } catch (SomeException se) {
+         // harmless comment
+         throw new SomeException(se);
+     }
+ }

+

Alternative rule: java:S1166

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + AvoidThrowingNullPointerException + Avoid throwing null pointer exception + category/java/design.xml/AvoidThrowingNullPointerException + BLOCKER + Title of issues: Avoid throwing null pointer exceptions. +

Avoid throwing NullPointerExceptions manually. These are confusing because most people will assume that the +virtual machine threw it. To avoid a method being called with a null parameter, you may consider +using an IllegalArgumentException instead, making it clearly seen as a programmer-initiated exception. +However, there are better ways to handle this:

+

>Effective Java, 3rd Edition, Item 72: Favor the use of standard exceptions +> +>Arguably, every erroneous method invocation boils down to an illegal argument or state, +but other exceptions are standardly used for certain kinds of illegal arguments and states. +If a caller passes null in some parameter for which null values are prohibited, convention dictates that +NullPointerException be thrown rather than IllegalArgumentException.

+

To implement that, you are encouraged to use java.util.Objects.requireNonNull() +(introduced in Java 1.7). This method is designed primarily for doing parameter +validation in methods and constructors with multiple parameters.

+

Your parameter validation could thus look like the following: +

 public class Foo {
+     private String exampleValue;
+
+     void setExampleValue(String exampleValue) {
+       // check, throw and assignment in a single standard call
+       this.exampleValue = Objects.requireNonNull(exampleValue, "exampleValue must not be null!");
+     }
+   }

+

Example

+

 public class Foo {
+     void bar() {
+         throw new NullPointerException();
+     }
+ }

+

Alternative rule: java:S1695

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + AvoidThrowingRawExceptionTypes + Avoid throwing raw exception types + category/java/design.xml/AvoidThrowingRawExceptionTypes + BLOCKER + Title of issues: Avoid throwing raw exception types. +

Avoid throwing certain exception types. Rather than throw a raw RuntimeException, Throwable, +Exception, or Error, use a subclassed exception or error instead.

+

Example

+

 public class Foo {
+     public void bar() throws Exception {
+         throw new Exception();
+     }
+ }

+

Alternative rule: java:S112

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + AvoidUncheckedExceptionsInSignatures + Avoid unchecked exceptions in signatures + category/java/design.xml/AvoidUncheckedExceptionsInSignatures + MAJOR + Title of issues: A method or constructor should not explicitly declare unchecked exceptions in its 'throws' clause +

Reports unchecked exceptions in the throws clause of a method or constructor. +Java doesn't force the caller to handle an unchecked exception, +so it's unnecessary except for documentation. A better practice is to document the +exceptional cases with a @throws Javadoc tag, which allows being more descriptive.

+

Example

+

 public void foo() throws RuntimeException {
+ }

+

Full documentation

]]>
+ pmd + design +
+ + AvoidUsingHardCodedIP + Avoid using hard coded IP + category/java/bestpractices.xml/AvoidUsingHardCodedIP + MAJOR + Title of issues: Do not hard code the IP address ${variableName} +

Application with hard-coded IP addresses can become impossible to deploy in some cases. +Externalizing IP adresses is preferable.

+

Example

+

 public class Foo {
+     private String ip = "127.0.0.1";     // not recommended
+ }

+

Alternative rule: java:S1313

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + AvoidUsingNativeCode + Avoid using native code + category/java/codestyle.xml/AvoidUsingNativeCode + CRITICAL + Title of issues: The use of native code is not recommended. +

Unnecessary reliance on Java Native Interface (JNI) calls directly reduces application portability +and increases the maintenance burden.

+

Example

+

 public class SomeJNIClass {
+
+      public SomeJNIClass() {
+          System.loadLibrary("nativelib");
+      }
+
+      static {
+          System.loadLibrary("nativelib");
+      }
+
+      public void invalidCallsInMethod() throws SecurityException, NoSuchMethodException {
+          System.loadLibrary("nativelib");
+      }
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + AvoidUsingOctalValues + Avoid using octal values + category/java/errorprone.xml/AvoidUsingOctalValues + MAJOR + Title of issues: Do not start a literal by 0 unless it's an octal value +

Integer literals should not start with zero since this denotes that the rest of literal will be +interpreted as an octal value.

+

Example

+

 int i = 012;    // set i with 10 not 12
+ int j = 010;    // set j with 8 not 10
+ k = i * j;      // set k with 80 not 120

+

Alternative rule: java:S1314

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + AvoidUsingVolatile + Avoid using volatile + category/java/multithreading.xml/AvoidUsingVolatile + CRITICAL + Title of issues: Use of modifier volatile is not recommended. +

Use of the keyword 'volatile' is generally used to fine tune a Java application, and therefore, requires +a good expertise of the Java Memory Model. Moreover, its range of action is somewhat misknown. Therefore, +the volatile keyword should not be used for maintenance purpose and portability.

+

Example

+

 public class ThrDeux {
+   private volatile String var1; // not suggested
+   private          String var2; // preferred
+ }

+

Full documentation

]]>
+ pmd + multithreading +
+ + BigIntegerInstantiation + Big integer instantiation + category/java/performance.xml/BigIntegerInstantiation + MAJOR + Title of issues: Don't create instances of already existing BigInteger and BigDecimal (ZERO, ONE, TEN) +

Don't create instances of already existing BigInteger (BigInteger.ZERO, BigInteger.ONE), +for Java 1.5 onwards, BigInteger.TEN and BigDecimal (BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN) and +for Java 9 onwards BigInteger.TWO.

+

Example

+

 BigInteger bi1 = new BigInteger("1");    // reference BigInteger.ONE instead
+ BigInteger bi2 = new BigInteger("0");    // reference BigInteger.ZERO instead
+ BigInteger bi3;
+ bi3 = new BigInteger("0");               // reference BigInteger.ZERO instead
+
+ BigDecimal bd1 = new BigDecimal(0);      // reference BigDecimal.ZERO instead
+ BigDecimal bd2 = new BigDecimal("0.") ;  // reference BigDecimal.ZERO instead
+ BigDecimal bd3 = new BigDecimal(10);     // reference BigDecimal.TEN instead

+

Full documentation

]]>
+ pmd + performance +
+ + BooleanGetMethodName + Boolean get method name + category/java/codestyle.xml/BooleanGetMethodName + MINOR + Title of issues: A 'getX()' method which returns a boolean or Boolean should be named 'isX()' +

Methods that return boolean or Boolean results should be named as predicate statements to denote this. + I.e., 'isReady()', 'hasValues()', 'canCommit()', 'willFail()', etc. Avoid the use of the 'get' prefix for these methods.

+

Example

+

 public boolean getFoo();            // bad
+ public Boolean getFoo();            // bad
+ public boolean isFoo();             // ok
+ public Boolean isFoo();             // ok
+ public boolean getFoo(boolean bar); // ok, unless checkParameterizedMethods=true

+

Full documentation

]]>
+ pmd + codestyle + + checkParameterizedMethods + + false + BOOLEAN + +
+ + BrokenNullCheck + Broken null check + category/java/errorprone.xml/BrokenNullCheck + CRITICAL + Title of issues: This expression will throw a NullPointerException +

The null check is broken since it will throw a NullPointerException itself. +It is likely that you used || instead of && or vice versa.

+

Example

+

 public String bar(String string) {
+   // should be &&
+     if (string!=null || !string.equals(""))
+         return string;
+   // should be ||
+     if (string==null && string.equals(""))
+         return string;
+ }

+

Alternative rule: java:S1697

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + CallSuperFirst + Call super first + category/java/errorprone.xml/CallSuperFirst + MAJOR + Title of issues: super should be called at the start of the method +

Super should be called at the start of the method

+

Example

+

 import android.app.Activity;
+ import android.os.Bundle;
+
+ public class DummyActivity extends Activity {
+     public void onCreate(Bundle bundle) {
+         // missing call to super.onCreate(bundle)
+         foo();
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + CallSuperInConstructor + Call super in constructor + category/java/codestyle.xml/CallSuperInConstructor + MAJOR + Title of issues: It is a good practice to call super() in a constructor +

It is a good practice to call super() in a constructor. If super() is not called but +another constructor (such as an overloaded constructor) is called, this rule will not report it.

+

Example

+

 public class Foo extends Bar{
+   public Foo() {
+    // call the constructor of Bar
+    super();
+   }
+  public Foo(int code) {
+   // do something with code
+    this();
+    // no problem with this
+   }
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + CallSuperLast + Call super last + category/java/errorprone.xml/CallSuperLast + MAJOR + Title of issues: super should be called at the end of the method +

Super should be called at the end of the method

+

Example

+

 import android.app.Activity;
+
+ public class DummyActivity extends Activity {
+     public void onPause() {
+         foo();
+         // missing call to super.onPause()
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + CheckResultSet + Check result set + category/java/bestpractices.xml/CheckResultSet + MAJOR + Title of issues: Always check the return of one of the navigation method (next,previous,first,last) of a ResultSet. +

Always check the return values of navigation methods (next, previous, first, last) of a ResultSet. +If the value return is 'false', it should be handled properly.

+

Example

+

 Statement stat = conn.createStatement();
+ ResultSet rst = stat.executeQuery("SELECT name FROM person");
+ rst.next();     // what if it returns false? bad form
+ String firstName = rst.getString(1);
+
+ Statement stat = conn.createStatement();
+ ResultSet rst = stat.executeQuery("SELECT name FROM person");
+ if (rst.next()) {    // result is properly examined and used
+     String firstName = rst.getString(1);
+     } else  {
+         // handle missing data
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + CheckSkipResult + Check skip result + category/java/errorprone.xml/CheckSkipResult + MAJOR + Title of issues: Check the value returned by the skip() method of an InputStream to see if the requested number of bytes has been skipped. +

The skip() method may skip a smaller number of bytes than requested. Check the returned value to find out if it was the case or not.

+

Example

+

 public class Foo {
+
+    private FileInputStream _s = new FileInputStream("file");
+
+    public void skip(int n) throws IOException {
+       _s.skip(n); // You are not sure that exactly n bytes are skipped
+    }
+
+    public void skipExactly(int n) throws IOException {
+       while (n != 0) {
+          long skipped = _s.skip(n);
+          if (skipped == 0)
+             throw new EOFException();
+          n -= skipped;
+       }
+    }

+

Alternative rule: java:S2674

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + ClassCastExceptionWithToArray + Class cast exception with to array + category/java/errorprone.xml/ClassCastExceptionWithToArray + MAJOR + Title of issues: This usage of the Collection.toArray() method will throw a ClassCastException. +

When deriving an array of a specific class from your Collection, one should provide an array of +the same class as the parameter of the toArray() method. Doing otherwise will result +in a ClassCastException.

+

Example

+

 Collection c = new ArrayList();
+ Integer obj = new Integer(1);
+ c.add(obj);
+
+     // this would trigger the rule (and throw a ClassCastException if executed)
+ Integer[] a = (Integer [])c.toArray();
+
+    // this is fine and will not trigger the rule
+ Integer[] b = (Integer [])c.toArray(new Integer[0]);

+

Full documentation

]]>
+ pmd + errorprone +
+ + ClassNamingConventions + Class naming conventions + category/java/codestyle.xml/ClassNamingConventions + BLOCKER + Title of issues: The {0} name '{1}' doesn't match '{2}' +

Configurable naming conventions for type declarations. This rule reports + type declarations which do not match the regex that applies to their + specific kind (e.g. enum or interface). Each regex can be configured through + properties.

+

By default, this rule uses the standard Java naming convention (Pascal case).

+

The rule can detect utility classes and enforce a different naming convention + on those. E.g. setting the property utilityClassPattern to + [A-Z][a-zA-Z0-9]+(Utils?|Helper|Constants) reports any utility class, whose name + does not end in "Util(s)", "Helper" or "Constants".

+

For this rule, a utility class is defined as: a concrete class that does not + inherit from a super class or implement any interface and only has static fields + or methods.

+

This rule detects test classes using the following convention: Test classes are top-level classes, that + either inherit from JUnit 3 TestCase or have at least one method annotated with the Test annotations from + JUnit4/5 or TestNG.

+

Example

+

 // This is Pascal case, the recommended naming convention in Java
+ // Note that the default values of this rule don't allow underscores
+ // or accented characters in type names
+ public class FooBar {}
+
+ // You may want abstract classes to be named 'AbstractXXX',
+ // in which case you can customize the regex for abstract
+ // classes to 'Abstract[A-Z]\w+'
+ public abstract class Thing {}
+
+ // This class doesn't respect the convention, and will be flagged
+ public class Éléphant {}

+

Alternative rules: java:S101, java:S114

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + ClassWithOnlyPrivateConstructorsShouldBeFinal + Class with only private constructors should be final + category/java/design.xml/ClassWithOnlyPrivateConstructorsShouldBeFinal + BLOCKER + Title of issues: This class has only private constructors and may be final +

Reports classes that may be made final because they cannot be extended from outside +their compilation unit anyway. This is because all their constructors are private, +so a subclass could not call the super constructor.

+

Example

+

 public class Foo {  //Should be final
+     private Foo() { }
+ }

+

Alternative rule: java:S2974

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + CloneMethodMustBePublic + Clone method must be public + category/java/errorprone.xml/CloneMethodMustBePublic + MAJOR + Title of issues: clone() method must be public if the class implements Cloneable +

The java manual says "By convention, classes that implement this interface should override +Object.clone (which is protected) with a public method."

+

Example

+

 public class Foo implements Cloneable {
+     @Override
+     protected Object clone() throws CloneNotSupportedException { // Violation, must be public
+     }
+ }
+
+ public class Foo implements Cloneable {
+     @Override
+     protected Foo clone() { // Violation, must be public
+     }
+ }
+
+ public class Foo implements Cloneable {
+     @Override
+     public Object clone() // Ok
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + CloneMethodMustImplementCloneable + Clone method must implement cloneable + category/java/errorprone.xml/CloneMethodMustImplementCloneable + MAJOR + Title of issues: clone() method should be implemented only if implementing Cloneable interface +

The method clone() should only be implemented if the class implements the Cloneable interface with the exception of +a final method that only throws CloneNotSupportedException.

+

The rule can also detect, if the class implements or extends a Cloneable class.

+

Example

+

 public class MyClass {
+  public Object clone() throws CloneNotSupportedException {
+   return foo;
+  }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + CloneMethodReturnTypeMustMatchClassName + Clone method return type must match class name + category/java/errorprone.xml/CloneMethodReturnTypeMustMatchClassName + MAJOR + Title of issues: The return type of the clone() method must be the class name when implements Cloneable +

If a class implements Cloneable the return type of the method clone() must be the class name. That way, the caller +of the clone method doesn't need to cast the returned clone to the correct type.

+

Note: Such a covariant return type is only possible with Java 1.5 or higher.

+

Example

+

 public class Foo implements Cloneable {
+     @Override
+     protected Object clone() { // Violation, Object must be Foo
+     }
+ }
+
+ public class Foo implements Cloneable {
+     @Override
+     public Foo clone() { //Ok
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + CloseResource + Close resource + category/java/errorprone.xml/CloseResource + MAJOR + Title of issues: Ensure that resources like this {0} object are closed after use +

Ensure that resources (like java.sql.Connection, java.sql.Statement, and java.sql.ResultSet objects +and any subtype of java.lang.AutoCloseable) are always closed after use. +Failing to do so might result in resource leaks.

+

Note: It suffices to configure the super type, e.g. java.lang.AutoCloseable, so that this rule automatically triggers +on any subtype (e.g. java.io.FileInputStream). Additionally specifying java.sql.Connection helps in detecting +the types, if the type resolution / auxclasspath is not correctly setup.

+

Note: Since PMD 6.16.0 the default value for the property types contains java.lang.AutoCloseable and detects +now cases where the standard java.io.*Stream classes are involved. In order to restore the old behaviour, +just remove "AutoCloseable" from the types.

+

Example

+

 public class Bar {
+     public void withSQL() {
+         Connection c = pool.getConnection();
+         try {
+             // do stuff
+         } catch (SQLException ex) {
+            // handle exception
+         } finally {
+             // oops, should close the connection using 'close'!
+             // c.close();
+         }
+     }
+
+     public void withFile() {
+         InputStream file = new FileInputStream(new File("/tmp/foo"));
+         try {
+             int c = file.in();
+         } catch (IOException e) {
+             // handle exception
+         } finally {
+             // TODO: close file
+         }
+     }
+ }

+

Alternative rule: java:S2095

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + CognitiveComplexity + Cognitive complexity + category/java/design.xml/CognitiveComplexity + MAJOR + Title of issues: The {0} '{1}' has a cognitive complexity of {2}, current threshold is {3} +

Methods that are highly complex are difficult to read and more costly to maintain. If you include too much decisional + logic within a single method, you make its behavior hard to understand and more difficult to modify.

+

Cognitive complexity is a measure of how difficult it is for humans to read and understand a method. Code that contains + a break in the control flow is more complex, whereas the use of language shorthands doesn't increase the level of + complexity. Nested control flows can make a method more difficult to understand, with each additional nesting of the + control flow leading to an increase in cognitive complexity.

+

Information about Cognitive complexity can be found in the original paper here: + https://www.sonarsource.com/docs/CognitiveComplexity.pdf

+

By default, this rule reports methods with a complexity of 15 or more. Reported methods should be broken down into less + complex components.

+

Example

+

 public class Foo {
+   // Has a cognitive complexity of 0
+   public void createAccount() {
+     Account account = new Account("PMD");
+     // save account
+   }
+
+   // Has a cognitive complexity of 1
+   public Boolean setPhoneNumberIfNotExisting(Account a, String phone) {
+     if (a.phone == null) {                          // +1
+       a.phone = phone;
+       return true;
+     }
+
+     return false;
+   }
+
+   // Has a cognitive complexity of 4
+   public void updateContacts(List<Contact> contacts) {
+     List<Contact> contactsToUpdate = new ArrayList<Contact>();
+
+     for (Contact contact : contacts) {                           // +1
+       if (contact.department.equals("Finance")) {                // +2 (nesting = 1)
+         contact.title = "Finance Specialist";
+         contactsToUpdate.add(contact);
+       } else if (contact.department.equals("Sales")) {           // +1
+         contact.title = "Sales Specialist";
+         contactsToUpdate.add(contact);
+       }
+     }
+     // save contacts
+   }
+ }

+

Full documentation

]]>
+ pmd + design +
+ + CollapsibleIfStatements + Collapsible if statements + category/java/design.xml/CollapsibleIfStatements + MAJOR + Title of issues: This if statement could be combined with its parent +

Reports nested 'if' statements that can be merged together by joining their +conditions with a boolean && operator in between.

+

Example

+

 class Foo {
+
+     void bar() {
+         if (x) {            // original implementation
+             if (y) {
+                 // do stuff
+             }
+         }
+     }
+
+     void bar() {
+         if (x && y) {        // clearer implementation
+             // do stuff
+         }
+     }
+ }

+

Alternative rule: java:S1066

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + CommentContent + Comment content + category/java/documentation.xml/CommentContent + MAJOR + Title of issues: Invalid words or phrases found +

A rule for the politically correct... we don't want to offend anyone.

+

Example

+

 //OMG, this is horrible, Bob is an idiot !!!

+

Full documentation

]]>
+ pmd + documentation +
+ + CommentDefaultAccessModifier + Comment default access modifier + category/java/codestyle.xml/CommentDefaultAccessModifier + MAJOR + Title of issues: Missing commented default access modifier on {0} '{1}' +

To avoid mistakes if we want that an Annotation, Class, Enum, Method, Constructor or Field have a default access modifier +we must add a comment at the beginning of its declaration. +By default, the comment must be / default / or / package /, if you want another, you have to provide a regular expression.

+

This rule ignores by default all cases that have a @VisibleForTesting annotation or any JUnit5/TestNG annotation. Use the +property "ignoredAnnotations" to customize the recognized annotations.

+

Example

+

 public class Foo {
+     final String stringValue = "some string";
+     String getString() {
+        return stringValue;
+     }
+
+     class NestedFoo {
+     }
+ }
+
+ // should be
+ public class Foo {
+     /* default */ final String stringValue = "some string";
+     /* default */ String getString() {
+        return stringValue;
+     }
+
+     /* default */ class NestedFoo {
+     }
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + CommentRequired + Comment required + category/java/documentation.xml/CommentRequired + MAJOR + Title of issues: Comment is required +

Denotes whether javadoc (formal) comments are required (or unwanted) for specific language elements.

+

Example

+

 /**
+ *
+ *
+ * @author Jon Doe
+ */

+

Full documentation

]]>
+ pmd + documentation +
+ + CommentSize + Comment size + category/java/documentation.xml/CommentSize + MAJOR + Title of issues: Comment is too large +

Determines whether the dimensions of non-header comments found are within the specified limits.

+

Example

+

 /**
+ *
+ *   too many lines!
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */

+

Full documentation

]]>
+ pmd + documentation +
+ + CompareObjectsWithEquals + Compare objects with equals + category/java/errorprone.xml/CompareObjectsWithEquals + MAJOR + Title of issues: Use equals() to compare object references. +

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.

+

Example

+

 class Foo {
+   boolean bar(String a, String b) {
+     return a == b;
+   }
+ }

+

Alternative rule: java:S1698

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative + + typesThatCompareByReference + + STRING + +
+ + ComparisonWithNaN + Comparison with na n + category/java/errorprone.xml/ComparisonWithNaN + MAJOR + Title of issues: Comparisons with NaN always return false +

Reports comparisons with double and float NaN (Not-a-Number) values. + These are specified + to have unintuitive behavior: NaN is considered unequal to itself. + This means a check like someDouble == Double.NaN will always return + false, even if someDouble is really the NaN value. To test whether a + value is the NaN value, one should instead use Double.isNaN(someDouble) + (or Float.isNaN). The != operator should be treated similarly. + Finally, comparisons like someDouble <= Double.NaN are nonsensical + and will always evaluate to false.

+

This rule has been renamed from "BadComparison" in PMD 6.36.0.

+

Example

+

 boolean x = (y == Double.NaN);

+

Full documentation

]]>
+ pmd + errorprone +
+ + ConfusingArgumentToVarargsMethod + Confusing argument to varargs method + category/java/errorprone.xml/ConfusingArgumentToVarargsMethod + MAJOR + Title of issues: Unclear if a varargs or non-varargs call is intended. Cast to {0} or {0}[], or pass varargs parameters separately to clarify intent. +

Reports a confusing argument passed to a varargs method.

+

This can occur when an array is passed as a single varargs argument, when the array type is not exactly the + type of array that the varargs method expects. If, that array is a subtype of the component type of the expected + array type, then it might not be clear what value the called varargs method will receive. + For instance if you have: +

 void varargs(Object... parm);
+ and call it like so: +
 varargs(new String[]{"a"});
+ it is not clear whether you intended the method to receive the value new Object[]{ new String[] {"a"} } or + just new String[] {"a"} (the latter happens). This confusion occurs because String[] is both a subtype + of Object[] and of Object. To clarify your intent in this case, use a cast or pass individual elements like so: +
 // varargs call
+             // parm will be `new Object[] { "a" }`
+             varargs("a");
+
+             // non-varargs call
+             // parm will be `new String[] { "a" }`
+             varargs((Object[]) new String[]{"a"});
+
+             // varargs call
+             // parm will be `new Object[] { new String[] { "a" } }`
+             varargs((Object) new String[]{"a"});

+

Another confusing case is when you pass null as the varargs argument. Here it is not clear whether you intended + to pass an array with a single null element, or a null array (the latter happens). This can similarly be clarified + with a cast.

+

Example

+

 import java.util.Arrays;
+
+             abstract class C {
+                 abstract void varargs(Object... args);
+                 static {
+                     varargs(new String[] { "a" });
+                     varargs(null);
+                 }
+             }

+

Full documentation

]]>
+ pmd + errorprone +
+ + ConfusingTernary + Confusing ternary + category/java/codestyle.xml/ConfusingTernary + MAJOR + Title of issues: Avoid if (x != y) ..; else ..; +

Avoid negation within an "if" expression with an "else" clause. For example, rephrase: +if (x != y) diff(); else same(); as: if (x == y) same(); else diff();.

+

Most "if (x != y)" cases without an "else" are often return cases, so consistent use of this +rule makes the code easier to read. Also, this resolves trivial ordering problems, such +as "does the error case go first?" or "does the common case go first?".

+

Example

+

 boolean bar(int x, int y) {
+     return (x != y) ? diff : same;
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + ConsecutiveAppendsShouldReuse + Consecutive appends should reuse + category/java/performance.xml/ConsecutiveAppendsShouldReuse + MAJOR + Title of issues: StringBuffer (or StringBuilder).append is called consecutively without reusing the target variable. +

Consecutive calls to StringBuffer/StringBuilder .append should be chained, reusing the target object. This can improve the performance +by producing a smaller bytecode, reducing overhead and improving inlining. A complete analysis can be found here

+

Example

+

 String foo = " ";
+
+ StringBuffer buf = new StringBuffer();
+ buf.append("Hello"); // poor
+ buf.append(foo);
+ buf.append("World");
+
+ StringBuffer buf = new StringBuffer();
+ buf.append("Hello").append(foo).append("World"); // good

+

Full documentation

]]>
+ pmd + performance +
+ + ConsecutiveLiteralAppends + Consecutive literal appends + category/java/performance.xml/ConsecutiveLiteralAppends + MAJOR + Title of issues: StringBuffer (or StringBuilder).append is called {0} consecutive times with literals. Use a single append with a single combined String. +

Consecutively calling StringBuffer/StringBuilder.append(...) with literals should be avoided. +Since the literals are constants, they can already be combined into a single String literal and this String +can be appended in a single method call.

+

Example

+

 StringBuilder buf = new StringBuilder();
+ buf.append("Hello").append(" ").append("World");    // poor
+ buf.append("Hello World");                          // good
+
+ buf.append('h').append('e').append('l').append('l').append('o'); // poor
+ buf.append("hello");                                             // good
+
+ buf.append(1).append('m');  // poor
+ buf.append("1m");           // good

+

Full documentation

]]>
+ pmd + performance +
+ + ConstantsInInterface + Constants in interface + category/java/bestpractices.xml/ConstantsInInterface + MAJOR + Title of issues: Using constants in interfaces is a bad practice. +

Using constants in interfaces is a bad practice. Interfaces define types, constants are implementation details better placed in classes or enums. If the constants are best viewed as members of an enumerated type, you should export them with an enum type. +For other scenarios, consider using a utility class. See Effective Java's 'Use interfaces only to define types'.

+

Example

+

 public interface ConstantInterface {
+     public static final int CONST1 = 1; // violation, no fields allowed in interface!
+     static final int CONST2 = 1;        // violation, no fields allowed in interface!
+     final int CONST3 = 1;               // violation, no fields allowed in interface!
+     int CONST4 = 1;                     // violation, no fields allowed in interface!
+ }
+
+ // with ignoreIfHasMethods = false
+ public interface AnotherConstantInterface {
+     public static final int CONST1 = 1; // violation, no fields allowed in interface!
+
+     int anyMethod();
+ }
+
+ // with ignoreIfHasMethods = true
+ public interface YetAnotherConstantInterface {
+     public static final int CONST1 = 1; // no violation
+
+     int anyMethod();
+ }

+

Full documentation

]]>
+ pmd + bestpractices + + ignoreIfHasMethods + + true + BOOLEAN + +
+ + ConstructorCallsOverridableMethod + Constructor calls overridable method + category/java/errorprone.xml/ConstructorCallsOverridableMethod + BLOCKER + Title of issues: Overridable {0} called during object construction{1} +

Reports calls to overridable methods on this during object initialization. These +are invoked on an incompletely constructed object and can be difficult to debug if overridden. +This is because the subclass usually assumes that the superclass is completely initialized +in all methods. If that is not the case, bugs can appear in the constructor, for instance, +some fields that are still null may cause a NullPointerException or be stored somewhere +else to blow up later.

+

To avoid this problem, only use methods that are static, private, or final in constructors. +Note that those methods also must not call overridable methods transitively to be safe.

+

Example

+

 public class SeniorClass {
+   public SeniorClass(){
+       toString(); //may throw NullPointerException if overridden
+   }
+   public String toString(){
+     return "IAmSeniorClass";
+   }
+ }
+ public class JuniorClass extends SeniorClass {
+   private String name;
+   public JuniorClass(){
+     super(); //Automatic call leads to NullPointerException
+     name = "JuniorClass";
+   }
+   public String toString(){
+     return name.toUpperCase();
+   }
+ }

+

Alternative rule: java:S1699

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + ControlStatementBraces + Control statement braces + category/java/codestyle.xml/ControlStatementBraces + MAJOR + Title of issues: This statement should have braces +

Enforce a policy for braces on control statements. It is recommended to use braces on 'if ... else' + statements and loop statements, even if they are optional. This usually makes the code clearer, and + helps prepare the future when you need to add another statement. That said, this rule lets you control + which statements are required to have braces via properties.

+

From 6.2.0 on, this rule supersedes WhileLoopMustUseBraces, ForLoopMustUseBraces, IfStmtMustUseBraces, + and IfElseStmtMustUseBraces.

+

Example

+

 while (true)    // not recommended
+   x++;
+
+ while (true) {  // preferred approach
+   x++;
+ }

+

Full documentation

]]>
+ pmd + codestyle + + checkIfElseStmt + + true + BOOLEAN + + + checkSingleIfStmt + + true + BOOLEAN + + + checkWhileStmt + + true + BOOLEAN + + + checkForStmt + + true + BOOLEAN + + + checkDoWhileStmt + + true + BOOLEAN + + + checkCaseStmt + + false + BOOLEAN + + + allowEmptyLoop + + false + BOOLEAN + +
+ + CouplingBetweenObjects + Coupling between objects + category/java/design.xml/CouplingBetweenObjects + MAJOR + Title of issues: A value of {0} may denote a high amount of coupling within the class (threshold: {1}) +

This rule counts the number of unique attributes, local variables, and return types within an object. +A number higher than the specified threshold can indicate a high degree of coupling.

+

Example

+

 import com.Blah;
+ import org.Bar;
+ import org.Bardo;
+
+ public class Foo {
+     private Blah var1;
+     private Bar var2;
+
+     //followed by many imports of unique objects
+     ObjectC doWork() {
+         Bardo var55;
+         ObjectA var44;
+         ObjectZ var93;
+         return something();
+     }
+ }

+

Alternative rule: java:S1200

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + CyclomaticComplexity + Cyclomatic complexity + category/java/design.xml/CyclomaticComplexity + MAJOR + Title of issues: The {0} '{1}' has a{2} cyclomatic complexity of {3}. +

The complexity of methods directly affects maintenance costs and readability. Concentrating too much decisional logic +in a single method makes its behaviour hard to read and change.

+

Cyclomatic complexity assesses the complexity of a method by counting the number of decision points in a method, +plus one for the method entry. Decision points are places where the control flow jumps to another place in the +program. As such, they include all control flow statements, such as if, while, for, and case. For more +details on the calculation, see the documentation CYCLO.

+

Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote +high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10. +Additionally, classes with many methods of moderate complexity get reported as well once the total of their +methods' complexities reaches 80, even if none of the methods was directly reported.

+

Reported methods should be broken down into several smaller methods. Reported classes should probably be broken down +into subcomponents.

+

Example

+

 class Foo {
+   void baseCyclo() {                // Cyclo = 1
+     highCyclo();
+   }
+
+   void highCyclo() {                // Cyclo = 10: reported!
+     int x = 0, y = 2;
+     boolean a = false, b = true;
+
+     if (a && (y == 1 ? b : true)) { // +3
+       if (y == x) {                 // +1
+         while (true) {              // +1
+           if (x++ < 20) {           // +1
+             break;                  // +1
+           }
+         }
+       } else if (y == t && !d) {    // +2
+         x = a ? y : x;              // +1
+       } else {
+         x = 2;
+       }
+     }
+   }
+ }

+

Alternative rule: java:S1541

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + DataClass + Data class + category/java/design.xml/DataClass + MAJOR + Title of issues: The class '{0}' is suspected to be a Data Class (WOC={1}, NOPA={2}, NOAM={3}, WMC={4}) +

Data Classes are simple data holders, which reveal most of their state, and +without complex functionality. The lack of functionality may indicate that +their behaviour is defined elsewhere, which is a sign of poor data-behaviour +proximity. By directly exposing their internals, Data Classes break encapsulation, +and therefore reduce the system's maintainability and understandability. Moreover, +classes tend to strongly rely on their data representation, which makes for a brittle +design.

+

Refactoring a Data Class should focus on restoring a good data-behaviour proximity. In +most cases, that means moving the operations defined on the data back into the class. +In some other cases it may make sense to remove entirely the class and move the data +into the former client classes.

+

The rule uses metrics to implement its detection strategy. The violation message gives information about the values of these metrics:

+ +

The rule identifies a god class by looking for classes which have all of the following properties:

+
  • High NOPA + NOAM
  • Low WOC
  • Low WMC
+

Example

+

 public class DataClass {
+
+   // class exposes public attributes
+   public String name = "";
+   public int bar = 0;
+   public int na = 0;
+
+   private int bee = 0;
+
+   // and private ones through getters
+   public void setBee(int n) {
+     bee = n;
+   }
+ }

+

Full documentation

]]>
+ pmd + design +
+ + DefaultLabelNotLastInSwitch + Default label not last in switch + category/java/bestpractices.xml/DefaultLabelNotLastInSwitch + MAJOR + Title of issues: The default label should be the last label in a switch statement or expression +

By convention, the default label should be the last label in a switch statement or switch expression.

+

Note: This rule has been renamed from "DefaultLabelNotLastInSwitchStmt" with PMD 7.7.0.

+

Example

+

 public class Foo {
+   void bar(int a) {
+    switch (a) {
+     case 1:  // do something
+        break;
+     default:  // the default case should be last, by convention
+        break;
+     case 2:
+        break;
+    }
+   }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + DetachedTestCase + Detached test case + category/java/errorprone.xml/DetachedTestCase + MAJOR + Title of issues: Probable detached JUnit test case. +

The method appears to be a test case since it has public or default visibility, +non-static access, no arguments, no return value, has no annotations, but is a +member of a class that has one or more JUnit test cases. If it is a utility +method, it should likely have private visibility. If it is an ignored test, it +should be annotated with @Test and @Ignore.

+

Example

+

 public class MyTest {
+     @Test
+     public void someTest() {
+     }
+
+     // violation: Not annotated
+     public void someOtherTest () {
+     }
+
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + DoNotCallGarbageCollectionExplicitly + Do not call garbage collection explicitly + category/java/errorprone.xml/DoNotCallGarbageCollectionExplicitly + CRITICAL + Title of issues: Do not explicitly trigger a garbage collection. +

Calls to System.gc(), Runtime.getRuntime().gc(), and System.runFinalization() are not advised. +Code should have the same behavior whether the garbage collection is disabled using the option +-Xdisableexplicitgc or not.

+

Moreover, "modern" JVMs do a very good job handling garbage collections. If memory usage issues unrelated to memory +leaks develop within an application, it should be dealt with JVM options rather than within the code itself.

+

Example

+

 public class GCCall {
+     public GCCall() {
+         // Explicit gc call !
+         System.gc();
+     }
+
+     public void doSomething() {
+         // Explicit gc call !
+         Runtime.getRuntime().gc();
+     }
+
+     public explicitGCcall() {
+         // Explicit gc call !
+         System.gc();
+     }
+
+     public void doSomething() {
+         // Explicit gc call !
+         Runtime.getRuntime().gc();
+     }
+ }

+

Alternative rule: java:S1215

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + DoNotExtendJavaLangError + Do not extend java lang error + category/java/design.xml/DoNotExtendJavaLangError + MAJOR + Title of issues: Exceptions should not extend java.lang.Error +

Errors are system exceptions. Do not extend them.

+

Example

+

 public class Foo extends Error { }

+

Alternative rule: java:S1194

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + DoNotExtendJavaLangThrowable + Do not extend java lang throwable + category/java/errorprone.xml/DoNotExtendJavaLangThrowable + MAJOR + Title of issues: Exceptions should not extend java.lang.Throwable +

Extend Exception or RuntimeException instead of Throwable.

+

Example

+

 public class Foo extends Throwable { }

+

Full documentation

]]>
+ pmd + errorprone +
+ + DoNotHardCodeSDCard + Do not hard code SDCard + category/java/errorprone.xml/DoNotHardCodeSDCard + MAJOR + Title of issues: Do not hardcode /sdcard. +

Use Environment.getExternalStorageDirectory() instead of "/sdcard"

+

Example

+

 public class MyActivity extends Activity {
+     protected void foo() {
+         String storageLocation = "/sdcard/mypackage";   // hard-coded, poor approach
+
+        storageLocation = Environment.getExternalStorageDirectory() + "/mypackage"; // preferred approach
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + DoNotTerminateVM + Do not terminate VM + category/java/errorprone.xml/DoNotTerminateVM + MAJOR + Title of issues: System.exit() should not be used in J2EE/JEE apps +

Web applications should not call System.exit(), since only the web container or the +application server should stop the JVM. Otherwise a web application would terminate all other applications +running on the same application server.

+

This rule also checks for the equivalent calls Runtime.getRuntime().exit() and Runtime.getRuntime().halt().

+

This rule has been renamed from "DoNotCallSystemExit" in PMD 6.29.0.

+

Example

+

 public void bar() {
+     System.exit(0);                 // never call this when running in an application server!
+ }
+ public void foo() {
+     Runtime.getRuntime().exit(0);   // never stop the JVM manually, the container will do this.
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + DoNotThrowExceptionInFinally + Do not throw exception in finally + category/java/errorprone.xml/DoNotThrowExceptionInFinally + MINOR + Title of issues: A throw statement in a finally block makes the control flow hard to understand. +

Throwing exceptions within a 'finally' block is confusing since they may mask other exceptions +or code defects. +

Note: This is a PMD implementation of the Lint4j rule "A throw in a finally block"

+

Example

+

 public class Foo {
+     public void bar() {
+         try {
+             // Here do some stuff
+         } catch( Exception e) {
+             // Handling the issue
+         } finally {
+             // is this really a good idea ?
+             throw new Exception();
+         }
+     }
+ }

+

Alternative rule: java:S1163

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + DoNotUseThreads + Do not use threads + category/java/multithreading.xml/DoNotUseThreads + MAJOR + Title of issues: To be compliant to J2EE, a webapp should not use any thread. +

The J2EE specification explicitly forbids the use of threads. Threads are resources, that should be managed and monitored by the J2EE server. +If the application creates threads on its own or uses own custom thread pools, then these threads are not managed, which could lead to resource exhaustion. +Also, EJBs might be moved between machines in a cluster and only managed resources can be moved along.

+

Example

+

 // This is not allowed
+ public class UsingThread extends Thread {
+
+ }
+
+ // Neither this,
+ public class UsingExecutorService {
+
+     public void methodX() {
+         ExecutorService executorService = Executors.newFixedThreadPool(5);
+     }
+ }
+
+ // Nor this,
+ public class Example implements ExecutorService {
+
+ }
+
+ // Nor this,
+ public class Example extends AbstractExecutorService {
+
+ }
+
+ // Nor this
+ public class UsingExecutors {
+
+     public void methodX() {
+         Executors.newSingleThreadExecutor().submit(() -> System.out.println("Hello!"));
+     }
+ }

+

Full documentation

]]>
+ pmd + multithreading +
+ + DontCallThreadRun + Dont call thread run + category/java/multithreading.xml/DontCallThreadRun + MINOR + Title of issues: Don't call Thread.run() explicitly, use Thread.start() +

Explicitly calling Thread.run() method will execute in the caller's thread of control. Instead, call Thread.start() for the intended behavior.

+

Example

+

 Thread t = new Thread();
+ t.run();            // use t.start() instead
+ new Thread().run(); // same violation

+

Alternative rule: java:S1217

+

Full documentation

]]>
+ pmd + multithreading + has-sonar-alternative +
+ + DontImportSun + Dont import sun + category/java/errorprone.xml/DontImportSun + MINOR + Title of issues: Avoid importing anything from the 'sun.*' packages +

Avoid importing anything from the 'sun.*' packages. These packages are not portable +and are likely to change.

+

If you find yourself having to depend on Sun APIs, confine this dependency to as +small a scope as possible, for instance by writing a stable wrapper class around +the unstable API. You can then suppress this rule in the implementation of the wrapper.

+

Example

+

 import sun.misc.foo;
+ public class Foo {}

+

Alternative rule: java:S1191

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + DontUseFloatTypeForLoopIndices + Dont use float type for loop indices + category/java/errorprone.xml/DontUseFloatTypeForLoopIndices + MAJOR + Title of issues: Don't use floating point for loop indices. If you must use floating point, use double. +

Don't use floating point for loop indices. If you must use floating point, use double +unless you're certain that float provides enough precision and you have a compelling +performance need (space or time).

+

Example

+

 public class Count {
+   public static void main(String[] args) {
+     final int START = 2000000000;
+     int count = 0;
+     for (float f = START; f < START + 50; f++)
+       count++;
+       //Prints 0 because (float) START == (float) (START + 50).
+       System.out.println(count);
+       //The termination test misbehaves due to floating point granularity.
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + DoubleBraceInitialization + Double brace initialization + category/java/bestpractices.xml/DoubleBraceInitialization + MAJOR + Title of issues: Double-brace initialization should be avoided +

Double brace initialisation is a pattern to initialise eg collections concisely. But it implicitly + generates a new .class file, and the object holds a strong reference to the enclosing object. For those + reasons, it is preferable to initialize the object normally, even though it's verbose.

+

This rule counts any anonymous class which only has a single initializer as an instance of double-brace + initialization. There is currently no way to find out whether a method called in the initializer is not + accessible from outside the anonymous class, and those legit cases should be suppressed for the time being.

+

Example

+

 // this is double-brace initialization
+ return new ArrayList<String>(){{
+     add("a");
+     add("b");
+     add("c");
+ }};
+
+ // the better way is to not create an anonymous class:
+ List<String> a = new ArrayList<>();
+ a.add("a");
+ a.add("b");
+ a.add("c");
+ return a;

+

Full documentation

]]>
+ pmd + bestpractices +
+ + DoubleCheckedLocking + Double checked locking + category/java/multithreading.xml/DoubleCheckedLocking + BLOCKER + Title of issues: Double checked locking is not thread safe in Java. +

Partially created objects can be returned by the Double Checked Locking pattern when used in Java. +An optimizing JRE may assign a reference to the baz variable before it calls the constructor of the object the +reference points to.

+

Note: With Java 5, you can make Double checked locking work, if you declare the variable to be volatile.

+

For more details refer to: http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html +or http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

+

Example

+

 public class Foo {
+     /*volatile */ Object baz = null; // fix for Java5 and later: volatile
+     Object bar() {
+         if (baz == null) { // baz may be non-null yet not fully created
+             synchronized(this) {
+                 if (baz == null) {
+                     baz = new Object();
+                 }
+               }
+         }
+         return baz;
+     }
+ }

+

Full documentation

]]>
+ pmd + multithreading +
+ + EmptyCatchBlock + Empty catch block + category/java/errorprone.xml/EmptyCatchBlock + MAJOR + Title of issues: Avoid empty catch blocks +

Empty Catch Block finds instances where an exception is caught, but nothing is done. +In most circumstances, this swallows an exception which should either be acted on +or reported.

+

Example

+

 public void doSomething() {
+     try {
+         FileInputStream fis = new FileInputStream("/tmp/bugger");
+     } catch (IOException ioe) {
+         // not good
+     }
+ }

+

Alternative rule: java:S108

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative + + allowCommentedBlocks + + false + BOOLEAN + + + allowExceptionNameRegex + + ^(ignored|expected)$ + STRING + +
+ + EmptyControlStatement + Empty control statement + category/java/codestyle.xml/EmptyControlStatement + MAJOR + Title of issues: This control statement has an empty branch +

Reports control statements whose body is empty, as well as empty initializers.

+

The checked code constructs are the following:

+
  • bodies of try statements
  • finally clauses of try statements
  • switch statements
  • synchronized statements
  • if statements
  • loop statements: while, for, do .. while
  • initializers
  • blocks used as statements (for scoping)
+

This rule replaces the rules EmptyFinallyBlock, + EmptyIfStmt, EmptyInitializer, EmptyStatementBlock, + EmptySwitchStatements, EmptySynchronizedBlock, EmptyTryBlock, and EmptyWhileStmt.

+

Notice that {% rule java/errorprone/EmptyCatchBlock %} is still an independent rule.

+

EmptyStatementNotInLoop is replaced by {% rule java/codestyle/UnnecessarySemicolon %}.

+

Example

+

 class Foo {
+     {
+         if (true); // empty if statement
+         if (true) { // empty as well
+         }
+     }
+
+     {} // empty initializer
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + EmptyFinalizer + Empty finalizer + category/java/errorprone.xml/EmptyFinalizer + MAJOR + Title of issues: Avoid empty finalize methods +

Empty finalize methods serve no purpose and should be removed. Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

+

Example

+

 public class Foo {
+    protected void finalize() {}
+ }

+

Alternative rule: java:S1186

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + EmptyMethodInAbstractClassShouldBeAbstract + Empty method in abstract class should be abstract + category/java/codestyle.xml/EmptyMethodInAbstractClassShouldBeAbstract + BLOCKER + Title of issues: An empty method in an abstract class should be abstract instead +

Empty or auto-generated methods in an abstract class should be tagged as abstract. This helps to remove their inapproprate +usage by developers who should be implementing their own versions in the concrete subclasses.

+

Example

+

 public abstract class ShouldBeAbstract {
+     public Object couldBeAbstract() {
+         // Should be abstract method ?
+         return null;
+     }
+
+     public void couldBeAbstract() {
+     }
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + EqualsNull + Equals null + category/java/errorprone.xml/EqualsNull + BLOCKER + Title of issues: Avoid using equals() to compare against null +

Tests for null should not use the equals() method. The '==' operator should be used instead.

+

Example

+

 String x = "foo";
+
+ if (x.equals(null)) {   // bad form
+     doSomething();
+ }
+
+ if (x == null) {        // preferred
+     doSomething();
+ }

+

Alternative rule: java:S2159

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + ExceptionAsFlowControl + Exception as flow control + category/java/design.xml/ExceptionAsFlowControl + MAJOR + Title of issues: Exception thrown at line {0} is caught in this block. +

This rule reports exceptions thrown and caught in an enclosing try statement. +This use of exceptions as a form of goto statement is discouraged, as that may +hide actual exceptions, and obscures control flow, especially when debugging. +To fix a violation, add the necessary validation or use an alternate control structure.

+

Example

+

 public void bar() {
+     try {
+         try {
+         } catch (Exception e) {
+             throw new WrapperException(e);
+             // this is essentially a GOTO to the WrapperException catch block
+         }
+     } catch (WrapperException e) {
+         // do some more stuff
+     }
+ }

+

Alternative rule: java:S1141

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + ExcessiveImports + Excessive imports + category/java/design.xml/ExcessiveImports + MAJOR + Title of issues: A high number of imports can indicate a high degree of coupling within an object. +

A high number of imports can indicate a high degree of coupling within an object. This rule +counts the number of unique imports and reports a violation if the count is above the +user-specified threshold.

+

Example

+

 import blah.blah.Baz;
+ import blah.blah.Bif;
+ // 28 others from the same package elided
+ public class Foo {
+     public void doWork() {}
+ }

+

Alternative rule: java:S1200

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + ExcessiveParameterList + Excessive parameter list + category/java/design.xml/ExcessiveParameterList + MAJOR + Title of issues: Avoid long parameter lists. +

Methods with numerous parameters are a challenge to maintain, especially if most of them share the +same datatype. These situations usually denote the need for new objects to wrap the numerous parameters.

+

Example

+

 public void addPerson(      // too many arguments liable to be mixed up
+     int birthYear, int birthMonth, int birthDate, int height, int weight, int ssn) {
+
+     . . . .
+ }
+
+ public void addPerson(      // preferred approach
+     Date birthdate, BodyMeasurements measurements, int ssn) {
+
+     . . . .
+ }

+

Alternative rule: java:S107

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + ExcessivePublicCount + Excessive public count + category/java/design.xml/ExcessivePublicCount + MAJOR + Title of issues: This class has a bunch of public methods and attributes +

Classes with large numbers of public methods and attributes require disproportionate testing efforts +since combinational side effects grow rapidly and increase risk. Refactoring these classes into +smaller ones not only increases testability and reliability but also allows new variations to be +developed easily.

+

Example

+

 public class Foo {
+     public String value;
+     public Bar something;
+     public Variable var;
+     // [... more more public attributes ...]
+
+     public void doWork() {}
+     public void doMoreWork() {}
+     public void doWorkAgain() {}
+     // [... more more public methods ...]
+ }

+

Alternative rule: java:S1448

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + ExhaustiveSwitchHasDefault + Exhaustive switch has default + category/java/bestpractices.xml/ExhaustiveSwitchHasDefault + MAJOR + Title of issues: The switch block is exhaustive even without the default case +

When switching over an enum or sealed class, the compiler will ensure that all possible cases are covered. +If a case is missing, this will result in a compilation error. But if a default case is added, this compiler +check is not performed anymore, leading to difficulties in noticing bugs at runtime.

+

Not using a default case makes sure, a compiler error is introduced whenever a new enum constant or a +new subclass to the sealed class hierarchy is added. We will discover this problem at compile time +rather than at runtime (if at all).

+

Note: The fix it not necessarily just removing the default case. Maybe a case is missing which needs to be implemented.

+

Example

+

 class Foo {
+     enum MyEnum { A, B };
+
+     void doSomething(MyEnum e) {
+         switch(e) {
+             case A -> System.out.println("a");
+             case B -> System.out.println("b");
+             default -> System.out.println("unnecessary default");
+         };
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + ExtendsObject + Extends object + category/java/codestyle.xml/ExtendsObject + MINOR + Title of issues: No need to explicitly extend Object. +

No need to explicitly extend Object.

+

Example

+

 public class Foo extends Object {     // not required
+ }

+

Alternative rule: java:S1939

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + FieldDeclarationsShouldBeAtStartOfClass + Field declarations should be at start of class + category/java/codestyle.xml/FieldDeclarationsShouldBeAtStartOfClass + MAJOR + Title of issues: Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes. +

Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes.

+

Example

+

 public class HelloWorldBean {
+
+   // Field declared before methods / inner classes - OK
+   private String _thing;
+
+   public String getMessage() {
+     return "Hello World!";
+   }
+
+   // Field declared after methods / inner classes - avoid this
+   private String _fieldInWrongLocation;
+ }

+

Alternative rule: java:S1213

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + FieldNamingConventions + Field naming conventions + category/java/codestyle.xml/FieldNamingConventions + BLOCKER + Title of issues: The {0} name '{1}' doesn't match '{2}' +

Configurable naming conventions for field declarations. This rule reports variable declarations + which do not match the regex that applies to their specific kind ---e.g. constants (static final), + enum constant, final field. Each regex can be configured through properties.

+

By default this rule uses the standard Java naming convention (Camel case), and uses the ALL_UPPER + convention for constants and enum constants.

+

Example

+

 class Foo {
+                 int myField = 1; // This is in camel case, so it's ok
+                 int my_Field = 1; // This contains an underscore, it's not ok by default
+                                   // but you may allow it, or even require the "my_" prefix
+
+                 final int FinalField = 1; // you may configure a different convention for final fields,
+                                           // e.g. here PascalCase: [A-Z][a-zA-Z0-9]*
+
+                 interface Interface {
+                     double PI = 3.14; // interface "fields" use the constantPattern property
+                 }
+
+                 enum AnEnum {
+                     ORG, NET, COM; // These use a separate property but are set to ALL_UPPER by default
+                 }
+             }

+

Full documentation

]]>
+ pmd + codestyle +
+ + FinalFieldCouldBeStatic + Final field could be static + category/java/design.xml/FinalFieldCouldBeStatic + MAJOR + Title of issues: This final field could be made static +

If a final field is assigned to a compile-time constant, it could be made static, thus saving overhead +in each object at runtime.

+

Example

+

 public class Foo {
+   public final int BAR = 42; // this could be static and save some space
+ }

+

Alternative rule: java:S1170

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + FinalParameterInAbstractMethod + Final parameter in abstract method + category/java/codestyle.xml/FinalParameterInAbstractMethod + BLOCKER + Title of issues: Final parameter in abstract method +

Declaring a method parameter as final for an interface method is useless because the implementation may choose to not respect it.

+

Example

+

 public interface MyInterface {
+   void process(final Object arg); // Avoid using final here
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + FinalizeDoesNotCallSuperFinalize + Finalize does not call super finalize + category/java/errorprone.xml/FinalizeDoesNotCallSuperFinalize + MAJOR + Title of issues: Last statement in finalize method should be a call to super.finalize() +

If the finalize() is implemented, its last action should be to call super.finalize. Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

+

Example

+

 protected void finalize() {
+     something();
+     // neglected to call super.finalize()
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + FinalizeOnlyCallsSuperFinalize + Finalize only calls super finalize + category/java/errorprone.xml/FinalizeOnlyCallsSuperFinalize + MAJOR + Title of issues: Finalize should do something besides just calling super.finalize() +

If the finalize() is implemented, it should do something besides just calling super.finalize(). Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

+

Example

+

 protected void finalize() {
+     super.finalize();
+ }

+

Alternative rule: java:S1185

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + FinalizeOverloaded + Finalize overloaded + category/java/errorprone.xml/FinalizeOverloaded + MAJOR + Title of issues: Finalize methods should not be overloaded +

Methods named finalize() should not have parameters. It is confusing and most likely an attempt to +overload Object.finalize(). It will not be called by the VM.

+

Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

+

Example

+

 public class Foo {
+     // this is confusing and probably a bug
+     protected void finalize(int a) {
+     }
+ }

+

Alternative rule: java:S1175

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + FinalizeShouldBeProtected + Finalize should be protected + category/java/errorprone.xml/FinalizeShouldBeProtected + MAJOR + Title of issues: If you override finalize(), make it protected +

When overriding the finalize(), the new method should be set as protected. If made public, +other classes may invoke it at inappropriate times.

+

Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

+

Example

+

 public void finalize() {
+     // do something
+ }

+

Alternative rule: java:S1174

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + ForLoopCanBeForeach + For loop can be foreach + category/java/bestpractices.xml/ForLoopCanBeForeach + MAJOR + Title of issues: This 'for' loop can be replaced by a 'foreach' loop +

Reports loops that can be safely replaced with the foreach syntax. The rule considers loops over +lists, arrays and iterators. A loop is safe to replace if it only uses the index variable to +access an element of the list or array, only has one update statement, and loops through every +element of the list or array left to right.

+

Example

+

 public class MyClass {
+   void loop(List<String> l) {
+     for (int i = 0; i < l.size(); i++) { // pre Java 1.5
+       System.out.println(l.get(i));
+     }
+
+     for (String s : l) {        // post Java 1.5
+       System.out.println(s);
+     }
+   }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + ForLoopShouldBeWhileLoop + For loop should be while loop + category/java/codestyle.xml/ForLoopShouldBeWhileLoop + MAJOR + Title of issues: This for loop could be simplified to a while loop +

Some for loops can be simplified to while loops, this makes them more concise.

+

Example

+

 public class Foo {
+     void bar() {
+         for (;true;) true; // No Init or Update part, may as well be: while (true)
+     }
+ }

+

Alternative rule: java:S1264

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + ForLoopVariableCount + For loop variable count + category/java/bestpractices.xml/ForLoopVariableCount + MAJOR + Title of issues: Too many control variables in the 'for' statement +

Having a lot of control variables in a 'for' loop makes it harder to see what range of values +the loop iterates over. By default this rule allows a regular 'for' loop with only one variable.

+

Example

+

 // this will be reported with the default setting of at most one control variable in a for loop
+ for (int i = 0, j = 0; i < 10; i++, j += 2) {
+    foo();

+

Full documentation

]]>
+ pmd + bestpractices + + maximumVariables + + 1 + INTEGER + +
+ + FormalParameterNamingConventions + Formal parameter naming conventions + category/java/codestyle.xml/FormalParameterNamingConventions + BLOCKER + Title of issues: The {0} name '{1}' doesn't match '{2}' +

Configurable naming conventions for formal parameters of methods and lambdas. + This rule reports formal parameters which do not match the regex that applies to their + specific kind (e.g. lambda parameter, or final formal parameter). Each regex can be + configured through properties.

+

By default this rule uses the standard Java naming convention (Camel case).

+

Example

+

 class Foo {
+
+                 abstract void bar(int myInt); // This is Camel case, so it's ok
+
+                 void bar(int my_i) { // this will be reported
+
+                 }
+
+                 void lambdas() {
+
+                     // lambdas parameters can be configured separately
+                     Consumer<String> lambda1 = s_str -> { };
+
+                     // lambda parameters with an explicit type can be configured separately
+                     Consumer<String> lambda1 = (String str) -> { };
+
+                 }
+
+             }

+

Full documentation

]]>
+ pmd + codestyle +
+ + GenericsNaming + Generics naming + category/java/codestyle.xml/GenericsNaming + MINOR + Title of issues: Generics names should be a one letter long and upper case. +

Names for references to generic values should be limited to a single uppercase letter.

+

Example

+

 public interface GenericDao<E extends BaseModel, K extends Serializable> extends BaseDao {
+     // This is ok...
+ }
+
+ public interface GenericDao<E extends BaseModel, K extends Serializable> {
+     // Also this
+ }
+
+ public interface GenericDao<e extends BaseModel, K extends Serializable> {
+     // 'e' should be an 'E'
+ }
+
+ public interface GenericDao<EF extends BaseModel, K extends Serializable> {
+    // 'EF' is not ok.
+ }

+

Alternative rule: java:S119

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + GodClass + God class + category/java/design.xml/GodClass + MAJOR + Title of issues: Possible God Class (WMC={0}, ATFD={2}, TCC={1}) +

The God Class rule detects the God Class design flaw using metrics. God classes do too many things, +are very big and overly complex. They should be split apart to be more object-oriented. +The rule uses the detection strategy described in "Object-Oriented Metrics in Practice". +The violations are reported against the entire class.

+

The rule uses metrics to implement its detection strategy. The violation message gives information about the values of these metrics:

+ +

The rule identifies a god class by looking for classes which have all of the following properties:

+
  • High WMC
  • High ATFD
  • Low TCC
+

See also the reference:

+

Michele Lanza and Radu Marinescu. Object-Oriented Metrics in Practice: +Using Software Metrics to Characterize, Evaluate, and Improve the Design +of Object-Oriented Systems. Springer, Berlin, 1 edition, October 2006. Page 80.

+

Full documentation

]]>
+ pmd + design +
+ + GuardLogStatement + Guard log statement + category/java/bestpractices.xml/GuardLogStatement + CRITICAL + Title of issues: Logger calls should be surrounded by log level guards. +

Whenever using a log level, one should check if it is actually enabled, or +otherwise skip the associate String creation and manipulation, as well as any method calls.

+

An alternative to checking the log level are substituting parameters, formatters or lazy logging +with lambdas. The available alternatives depend on the actual logging framework.

+

Example

+

 // Add this for performance - avoid manipulating strings if the logger may drop it
+ if (log.isDebugEnabled()) {
+     log.debug("log something" + param1 + " and " + param2 + "concat strings");
+ }
+
+ // Avoid the guarding if statement with substituting parameters
+ log.debug("log something {} and {}", param1, param2);
+
+ // Avoid the guarding if statement with formatters
+ log.debug("log something %s and %s", param1, param2);
+
+ // This is still an issue, method invocations may be expensive / have side-effects
+ log.debug("log something expensive: {}", calculateExpensiveLoggingText());
+
+ // Avoid the guarding if statement with lazy logging and lambdas
+ log.debug("log something expensive: {}", () -> calculateExpensiveLoggingText());
+
+ // … alternatively use method references
+ log.debug("log something expensive: {}", this::calculateExpensiveLoggingText);

+

Full documentation

]]>
+ pmd + bestpractices +
+ + HardCodedCryptoKey + Hard coded crypto key + category/java/security.xml/HardCodedCryptoKey + MAJOR + Title of issues: Do not use hard coded encryption keys +

Do not use hard coded values for cryptographic operations. Please store keys outside of source code.

+

Example

+

 public class Foo {
+     void good() {
+         SecretKeySpec secretKeySpec = new SecretKeySpec(Properties.getKey(), "AES");
+     }
+
+     void bad() {
+         SecretKeySpec secretKeySpec = new SecretKeySpec("my secret here".getBytes(), "AES");
+     }
+ }

+

Full documentation

]]>
+ pmd + security +
+ + IdempotentOperations + Idempotent operations + category/java/errorprone.xml/IdempotentOperations + MAJOR + Title of issues: Avoid idempotent operations (like assigning a variable to itself). +

Avoid idempotent operations - they have no effect.

+

Example

+

 public class Foo {
+  public void bar() {
+   int x = 2;
+   x = x;
+  }
+ }

+

Alternative rule: java:S1656

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + IdenticalCatchBranches + Identical catch branches + category/java/codestyle.xml/IdenticalCatchBranches + MAJOR + Title of issues: 'catch' branch identical to '{0}' branch +

Identical catch branches use up vertical space and increase the complexity of code without + adding functionality. It's better style to collapse identical branches into a single multi-catch + branch.

+

Example

+

 try {
+     // do something
+ } catch (IllegalArgumentException e) {
+     throw e;
+ } catch (IllegalStateException e) { // Can be collapsed into the previous block
+     throw e;
+ }
+
+ try {
+     // do something
+ } catch (IllegalArgumentException | IllegalStateException e) { // This is better
+     throw e;
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + ImmutableField + Immutable field + category/java/design.xml/ImmutableField + MAJOR + Title of issues: Field '{0}' may be declared final +

Reports non-final fields whose value never changes once object initialization ends, +and hence may be marked final.

+

Note that this rule does not enforce that the field value be deeply immutable itself. +An object can still have mutable state, even if all its member fields are declared final. +This is referred to as shallow immutability. For more information on mutability, +see Effective Java, 3rd Edition, Item 17: Minimize mutability.

+

Limitations: We can only check private fields for now.

+

Example

+

 public class Foo {
+   private int x; // could be final
+   public Foo() {
+       x = 7;
+   }
+   public void foo() {
+      int a = x + 2;
+   }
+ }

+

Full documentation

]]>
+ pmd + design +
+ + ImplicitFunctionalInterface + Implicit functional interface + category/java/bestpractices.xml/ImplicitFunctionalInterface + CRITICAL + Title of issues: Annotate this interface with @FunctionalInterface or with @SuppressWarnings("PMD.ImplicitFunctionalInterface") to clarify your intent. +

Reports functional interfaces that were not explicitly declared as such with + the annotation @FunctionalInterface. If an interface is accidentally a functional + interface, then it should bear a @SuppressWarnings("PMD.ImplicitFunctionalInterface") + annotation to make this clear.

+

Example

+

 // The intent on this declaration is unclear, and the rule will report it.
+             public interface MyInterface {
+                 void doSomething();
+             }
+
+             // This is clearly intended as a functional interface.
+             @FunctionalInterface
+             public interface MyInterface {
+                 void doSomething();
+             }
+
+             // This is clearly NOT intended as a functional interface.
+             @SuppressWarnings("PMD.ImplicitFunctionalInterface")
+             public interface MyInterface {
+                 void doSomething();
+             }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + ImplicitSwitchFallThrough + Implicit switch fall through + category/java/errorprone.xml/ImplicitSwitchFallThrough + MAJOR + Title of issues: This switch case may be reached by fallthrough from the previous case +

Switch statements without break or return statements for each case option +may indicate problematic behaviour. Empty cases are ignored as these indicate +an intentional fall-through.

+

You can ignore a violation by commenting // fallthrough before the case label +which is reached by fallthrough, or with @SuppressWarnings("fallthrough").

+

This rule has been renamed from "MissingBreakInSwitch" in PMD 6.37.0.

+

Example

+

 public void bar(int status) {
+     switch(status) {
+       case CANCELLED:
+         doCancelled();
+         // break; hm, should this be commented out?
+       case NEW:
+         doNew();
+         // is this really a fall-through?
+         // what happens if you add another case after this one?
+       case REMOVED:
+         doRemoved();
+         // fallthrough - this comment just clarifies that you want a fallthrough
+       case OTHER: // empty case - this is interpreted as an intentional fall-through
+       case ERROR:
+         doErrorHandling();
+         break;
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + InefficientEmptyStringCheck + Inefficient empty string check + category/java/performance.xml/InefficientEmptyStringCheck + MAJOR + Title of issues: String.trim().length() == 0 / String.trim().isEmpty() is an inefficient way to validate a blank String. +

String.trim().length() == 0 (or String.trim().isEmpty() for the same reason) is an inefficient +way to check if a String is really blank, as it creates a new String object just to check its size. +Consider creating a static function that loops through a string, checking Character.isWhitespace() +on each character and returning false if a non-whitespace character is found. A Smarter code to +check for an empty string would be:

+

 private boolean checkTrimEmpty(String str) {
+     for(int i = 0; i < str.length(); i++) {
+         if(!Character.isWhitespace(str.charAt(i))) {
+             return false;
+         }
+     }
+     return true;
+ }

+

You can refer to Apache's StringUtils#isBlank (in commons-lang), +Spring's StringUtils#hasText (in the Spring framework) or Google's +CharMatcher#whitespace (in Guava) for existing implementations (some might +include the check for != null).

+

Example

+

 public void bar(String string) {
+     if (string != null && string.trim().length() > 0) {
+         doSomething();
+     }
+ }

+

Full documentation

]]>
+ pmd + performance +
+ + InefficientStringBuffering + Inefficient string buffering + category/java/performance.xml/InefficientStringBuffering + MAJOR + Title of issues: Avoid concatenating nonliterals in a StringBuffer/StringBuilder constructor or append(). +

Avoid concatenating non-literals in a StringBuffer constructor or append() since intermediate buffers will +need to be be created and destroyed by the JVM.

+

Example

+

 // Avoid this, two buffers are actually being created here
+ StringBuffer sb = new StringBuffer("tmp = "+System.getProperty("java.io.tmpdir"));
+
+ // do this instead
+ StringBuffer sb = new StringBuffer("tmp = ");
+ sb.append(System.getProperty("java.io.tmpdir"));

+

Full documentation

]]>
+ pmd + performance +
+ + InsecureCryptoIv + Insecure crypto iv + category/java/security.xml/InsecureCryptoIv + MAJOR + Title of issues: Do not use hard coded initialization vector in crypto operations +

Do not use hard coded initialization vector in cryptographic operations. Please use a randomly generated IV.

+

Example

+

 public class Foo {
+     void good() {
+         SecureRandom random = new SecureRandom();
+         byte iv[] = new byte[16];
+         random.nextBytes(bytes);
+     }
+
+     void bad() {
+         byte[] iv = new byte[] { 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, };
+     }
+
+     void alsoBad() {
+         byte[] iv = "secret iv in here".getBytes();
+     }
+ }

+

Full documentation

]]>
+ pmd + security +
+ + InstantiationToGetClass + Instantiation to get class + category/java/errorprone.xml/InstantiationToGetClass + MINOR + Title of issues: Avoid instantiating an object just to call getClass() on it; use the .class public member instead +

Avoid instantiating an object just to call getClass() on it; use the .class public member instead.

+

Example

+

 // replace this
+ Class c = new String().getClass();
+
+ // with this:
+ Class c = String.class;

+

Alternative rule: java:S2133

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + InsufficientStringBufferDeclaration + Insufficient string buffer declaration + category/java/performance.xml/InsufficientStringBufferDeclaration + MAJOR + Title of issues: {0} has been initialized with size {1}, but has at least {2} characters appended. +

Failing to pre-size a StringBuffer or StringBuilder properly could cause it to re-size many times +during runtime. This rule attempts to determine the total number the characters that are actually +passed into StringBuffer.append(), but represents a best guess "worst case" scenario. An empty +StringBuffer/StringBuilder constructor initializes the object to 16 characters. This default +is assumed if the length of the constructor can not be determined.

+

Example

+

 StringBuilder bad = new StringBuilder();
+ bad.append("This is a long string that will exceed the default 16 characters");
+
+ StringBuilder good = new StringBuilder(41);
+ good.append("This is a long string, which is pre-sized");

+

Full documentation

]]>
+ pmd + performance +
+ + InvalidJavaBean + Invalid java bean + category/java/design.xml/InvalidJavaBean + MAJOR + Title of issues: The bean '{0}' is missing a getter for property '{1}'. +

Identifies beans, that don't follow the JavaBeans API specification.

+

Each non-static field should have both a getter and a setter method. If the field is just used internally and is not +a bean property, then the field should be marked as transient.

+

The rule verifies that the type of the field is the same as the result type of the getter. And that this type matches +the type used in the setter.

+

The rule also checks, that there is a no-arg or default constructor available.

+

Optionally the rule also verifies, that the bean implements java.io.Serializable. While this is a requirement for the +original JavaBeans specification, frameworks nowadays don't strictly require this anymore.

+

In order to avoid many false positives in classes that are not beans, the rule needs to be explicitly +enabled by configuring the property packages.

+

Example

+

 package org.example.beans;
+ public class MyBean {        // <-- bean is not serializable, missing "implements Serializable"
+     private String label;    // <-- missing setter for property "label"
+
+     public String getLabel() {
+         return label;
+     }
+ }

+

Full documentation

]]>
+ pmd + design +
+ + InvalidLogMessageFormat + Invalid log message format + category/java/errorprone.xml/InvalidLogMessageFormat + INFO + Title of issues: Invalid message format +

Check for messages in slf4j and log4j2 (since 6.19.0) loggers with non matching number of arguments and placeholders.

+

Since 6.32.0 in addition to parameterized message placeholders ({}) also format specifiers of string formatted +messages are supported (%s).

+

This rule has been renamed from "InvalidSlf4jMessageFormat" in PMD 6.19.0.

+

Example

+

 LOGGER.error("forget the arg {}");
+ LOGGER.error("forget the arg %s");
+ LOGGER.error("too many args {}", "arg1", "arg2");
+ LOGGER.error("param {}", "arg1", new IllegalStateException("arg")); //The exception is shown separately, so is correct.

+

Full documentation

]]>
+ pmd + errorprone +
+ + JUnit4SuitesShouldUseSuiteAnnotation + JUnit4 suites should use suite annotation + category/java/bestpractices.xml/JUnit4SuitesShouldUseSuiteAnnotation + MAJOR + Title of issues: JUnit 4 indicates test suites via annotations, not the suite method. +

In JUnit 3, test suites are indicated by the suite() method. In JUnit 4, suites are indicated +through the @RunWith(Suite.class) annotation.

+

Example

+

 public class BadExample extends TestCase{
+
+     public static Test suite(){
+         return new Suite();
+     }
+ }
+
+ @RunWith(Suite.class)
+ @SuiteClasses( { TestOne.class, TestTwo.class })
+ public class GoodTest {
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + JUnit5TestShouldBePackagePrivate + JUnit5 test should be package private + category/java/bestpractices.xml/JUnit5TestShouldBePackagePrivate + MAJOR + Title of issues: JUnit 5 tests should be package-private. +

Reports JUnit 5 test classes and methods that are not package-private. +Contrary to JUnit 4 tests, which required public visibility to be run by the engine, +JUnit 5 tests can also be run if they're package-private. Marking them as such +is a good practice to limit their visibility.

+

Test methods are identified as those which use @Test, @RepeatedTest, +@TestFactory, @TestTemplate or @ParameterizedTest.

+

Example

+

 class MyTest { // not public, that's fine
+     @Test
+     public void testBad() { } // should not have a public modifier
+
+     @Test
+     protected void testAlsoBad() { } // should not have a protected modifier
+
+     @Test
+     private void testNoRun() { } // should not have a private modifier
+
+     @Test
+     void testGood() { } // package private as expected
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + JUnitSpelling + JUnit spelling + category/java/errorprone.xml/JUnitSpelling + MAJOR + Title of issues: You may have misspelled a JUnit framework method (setUp or tearDown) +

In JUnit 3, the setUp method is used to set up all data entities required in running tests. + The tearDown method is used to clean up all data entities required in running tests. + You should not misspell method name if you want your test to set up and clean up everything correctly.

+

Example

+

 import junit.framework.*;
+
+ public class Foo extends TestCase {
+     public void setup() {}    // oops, should be setUp
+     public void TearDown() {} // oops, should be tearDown
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + JUnitStaticSuite + JUnit static suite + category/java/errorprone.xml/JUnitStaticSuite + MAJOR + Title of issues: You have a suite() method that is not both public and static, so JUnit won't call it to get your TestSuite. Is that what you wanted to do? +

The suite() method in a JUnit test needs to be both public and static.

+

Examples

+

Example 1

+

 import junit.framework.*;
+
+ public class Foo extends TestCase {
+     public void suite() {}         // oops, should be static
+ }

+

Example 2

+

 import junit.framework.*;
+
+ public class Foo extends TestCase {
+     private static void suite() {} // oops, should be public
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + JUnitUseExpected + JUnit use expected + category/java/bestpractices.xml/JUnitUseExpected + MAJOR + Title of issues: In JUnit4, use the @Test(expected) annotation to denote tests that should throw exceptions +

In JUnit4, use the @Test(expected) annotation to denote tests that should throw exceptions.

+

Example

+

 public class MyTest {
+     @Test
+     public void testBad() {
+         try {
+             doSomething();
+             fail("should have thrown an exception");
+         } catch (Exception e) {
+         }
+     }
+
+     @Test(expected=Exception.class)
+     public void testGood() {
+         doSomething();
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + JumbledIncrementer + Jumbled incrementer + category/java/errorprone.xml/JumbledIncrementer + MAJOR + Title of issues: Avoid modifying an outer loop incrementer in an inner loop for update expression +

Avoid jumbled loop incrementers - it's usually a mistake, and is confusing even if intentional.

+

Example

+

 public class JumbledIncrementerRule1 {
+     public void foo() {
+         for (int i = 0; i < 10; i++) {          // only references 'i'
+             for (int k = 0; k < 20; i++) {      // references both 'i' and 'k'
+                 System.out.println("Hello");
+             }
+         }
+     }
+ }

+

Alternative rule: java:S1994

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + LambdaCanBeMethodReference + Lambda can be method reference + category/java/codestyle.xml/LambdaCanBeMethodReference + MAJOR + Title of issues: Lambda expression could be written as a method reference: <code>{0}</code> +

This rule reports lambda expressions that can be written more succinctly as a method reference. This is the case if the lambda is an expression lambda that only calls one method, passing the entire lambda parameter list in order to the method. For instance: +

 x -> Foo.call(x) // can be Foo::call
+                 x -> call(x)     // can be this::call, if call is an instance method
+                 (x, y, z) -> call(x, y, z) // can be this::call
+                 () -> foo.get() // can be foo::get
+                 x -> x.foo()    // can be XType::foo (where XType is the type of x)

+

In some cases rewriting a lambda to a method reference can change the semantics of the code. For instance in (x) -> someVar.call(x), the invocation of the lambda may produce a NullPointerException (NPE) if someVar is null. The method reference someVar::call will also NPE if someVar is null, but it will do so at the point the method reference is created, while the lambda is created without error and its NPE is only thrown if the lambda is invoked (which may be never). Code should probably not rely on this subtle semantic difference, therefore these potentially problematic lambdas are also reported by default. This behavior can be disabled by setting the property ignoreIfMayNPE to true.

+

The property ignoreIfMayNPE is true by default. By default, calls whose receiver is itself a method call are ignored, because they could cause side effects. This may be changed by setting the property ignoreIfReceiverIsMethod to false.

+

Scope limitations:

+
  • This rule will not report lambdas of the form x -> new CtorCall().something(x), because the semantics of the method reference would be to create a single new object, while the lambda creates one object per invocation.
  • The rule cannot know if the qualifier of a method call performs side effects. This means (x) -> sideEffectingMethod().foo(x) will be reported. Suppress the warning in this case.
+

Example

+

 import java.util.stream.Stream;
+
+             public class LambdaCanBeMethodReference {
+                 static {
+                     Stream.of("abc", "d")
+                             .mapToInt(s -> s.length()) // could be String::length
+                             .reduce((x, y) -> Integer.sum(x, y)) // could be Integer::sum
+                             .getAsInt();
+                 }
+             }

+

Full documentation

]]>
+ pmd + codestyle +
+ + LawOfDemeter + Law of demeter + category/java/design.xml/LawOfDemeter + MAJOR + Title of issues: Potential violation of the law of Demeter ({0}) +

The law of Demeter is a simple rule that says "only talk to friends". It forbids +fetching data from "too far away", for some definition of distance, in order to +reduce coupling between classes or objects of different levels of abstraction.

+

The rule uses a notion of "degree", that quantifies how "far" an object is. Expressions with too high degree can only be used in certain ways. The degree of an expression is defined inductively:

+
  • The degree of this is 0
  • The degree of a method parameter is 1
  • The degree of a new object created in a method is 1
  • The degree of a static variable is 1
  • The degree of a field access expression like expr.field is the degree of expr plus 1
  • The degree of a "getter expression" like expr.getFoo() is the degree of expr plus 1
  • The degree of a "transformation expression" like expr.withFoo("") is the degree of expr
  • The degree of a variable is the maximum degree of all the assignments that reach it
+

Intuitively, the more you call getters, the more the degree increases. Eventually +the degree reaches the report threshold (property trustRadius) and the expression +is reported. The details of the calculation are more involved and make room for common +patterns, like usage of collections (objects that are in a list or array have the +same degree as their container), the builder pattern, and getters that do not appear +to break a boundary of abstraction.

+

Be aware that this rule is prone to many false-positives and low-priority warnings. You can increase the trustRadius property to reduce them drastically. The default trustRadius of 1 corresponds to the original law of Demeter (you're only allowed one getter call on untrusted values). Given some trustRadius value:

+
  • expressions of degree lower or equal to trustRadius are not reported
  • expressions of degree exactly trustRadius + 1 are reported, unless they are only returned from the current method, or passed as argument to another method. Without this exception it
  • values of degree strictly greater than trustRadius + 1 are not reported. The intuition is that to obtain a value of degree n > 1 then you must use an expression
+

See also the references:

+ +

Example

+

 public class Foo {
+     /**
+      * This example will result in one violation.
+      */
+     public void example(Bar b) { // b has degree 1
+         // `b.getC()` has degree 2, it's breaking a boundary of abstraction and so is reported.
+         b.getC().doIt();
+         // To respect the law of Demeter, Bar should encapsulate its
+         // C member more properly, eg by exposing a method like this:
+         b.callDoItOnC();
+
+         // a constructor call, not a method call.
+         D d = new D();
+         // this method call is ok, because we have create the new
+         // instance of D locally.
+         d.doSomethingElse();
+     }
+ }

+

Full documentation

]]>
+ pmd + design +
+ + LinguisticNaming + Linguistic naming + category/java/codestyle.xml/LinguisticNaming + MAJOR + Title of issues: Linguistics Antipattern - Method name and return type is inconsistent linguistically +

This rule finds Linguistic Naming Antipatterns. It checks for fields, that are named, as if they should + be boolean but have a different type. It also checks for methods, that according to their name, should + return a boolean, but don't. Further, it checks, that getters return something and setters won't. + Finally, it checks that methods, that start with "to" - so called transform methods - actually return + something, since according to their name, they should convert or transform one object into another. + There is additionally an option, to check for methods that contain "To" in their name - which are + also transform methods. However, this is disabled by default, since this detection is prone to + false positives.

+

For more information, see Linguistic Antipatterns - What They Are and How +Developers Perceive Them.

+

Example

+

 public class LinguisticNaming {
+     int isValid;    // the field name indicates a boolean, but it is an int.
+     boolean isTrue; // correct type of the field
+
+     void myMethod() {
+         int hasMoneyLocal;      // the local variable name indicates a boolean, but it is an int.
+         boolean hasSalaryLocal; // correct naming and type
+     }
+
+     // the name of the method indicates, it is a boolean, but the method returns an int.
+     int isValid() {
+         return 1;
+     }
+     // correct naming and return type
+     boolean isSmall() {
+         return true;
+     }
+
+     // the name indicates, this is a setter, but it returns something
+     int setName() {
+         return 1;
+     }
+
+     // the name indicates, this is a getter, but it doesn't return anything
+     void getName() {
+         // nothing to return?
+     }
+
+     // the name indicates, it transforms an object and should return the result
+     void toDataType() {
+         // nothing to return?
+     }
+     // the name indicates, it transforms an object and should return the result
+     void grapeToWine() {
+         // nothing to return?
+     }
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + LiteralsFirstInComparisons + Literals first in comparisons + category/java/bestpractices.xml/LiteralsFirstInComparisons + MAJOR + Title of issues: Position literals first in String comparisons +

Position literals first in all String comparisons, if the second argument is null then NullPointerExceptions + can be avoided, they will just return false. Note that switching literal positions for compareTo and + compareToIgnoreCase may change the result, see examples.

+

Note that compile-time constant strings are treated like literals. This is because they are inlined into + the class file, are necessarily non-null, and therefore cannot cause an NPE at runtime.

+

Example

+

 class Foo {
+     boolean bar(String x) {
+         return x.equals("2"); // should be "2".equals(x)
+     }
+     boolean bar(String x) {
+         return x.equalsIgnoreCase("2"); // should be "2".equalsIgnoreCase(x)
+     }
+     boolean bar(String x) {
+         return (x.compareTo("bar") > 0); // should be: "bar".compareTo(x) < 0
+     }
+     boolean bar(String x) {
+         return (x.compareToIgnoreCase("bar") > 0); // should be: "bar".compareToIgnoreCase(x) < 0
+     }
+     boolean bar(String x) {
+         return x.contentEquals("bar"); // should be "bar".contentEquals(x)
+     }
+
+     static final String CONSTANT = "const";
+     {
+         CONSTANT.equals("literal"); // not reported, this is effectively the same as writing "const".equals("foo")
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + LocalHomeNamingConvention + Local home naming convention + category/java/codestyle.xml/LocalHomeNamingConvention + MINOR + Title of issues: The Local Home interface of a Session EJB should be suffixed by 'LocalHome' +

The Local Home interface of a Session EJB should be suffixed by 'LocalHome'.

+

Example

+

 public interface MyBeautifulLocalHome extends javax.ejb.EJBLocalHome {} // proper name
+
+ public interface MissingProperSuffix extends javax.ejb.EJBLocalHome {}  // non-standard name

+

Full documentation

]]>
+ pmd + codestyle +
+ + LocalInterfaceSessionNamingConvention + Local interface session naming convention + category/java/codestyle.xml/LocalInterfaceSessionNamingConvention + MINOR + Title of issues: The Local Interface of a Session EJB should be suffixed by 'Local' +

The Local Interface of a Session EJB should be suffixed by 'Local'.

+

Example

+

 public interface MyLocal extends javax.ejb.EJBLocalObject {}                // proper name
+
+ public interface MissingProperSuffix extends javax.ejb.EJBLocalObject {}    // non-standard name

+

Full documentation

]]>
+ pmd + codestyle +
+ + LocalVariableCouldBeFinal + Local variable could be final + category/java/codestyle.xml/LocalVariableCouldBeFinal + MAJOR + Title of issues: Local variable '{0}' could be declared final +

A local variable assigned only once can be declared final.

+

Example

+

 public class Bar {
+     public void foo () {
+     String txtA = "a";          // if txtA will not be assigned again it is better to do this:
+     final String txtB = "b";
+     }
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + LocalVariableNamingConventions + Local variable naming conventions + category/java/codestyle.xml/LocalVariableNamingConventions + BLOCKER + Title of issues: The {0} name '{1}' doesn't match '{2}' +

Configurable naming conventions for local variable declarations and other locally-scoped + variables. This rule reports variable declarations which do not match the regex that applies to their + specific kind (e.g. final variable, or catch-clause parameter). Each regex can be configured through + properties.

+

By default this rule uses the standard Java naming convention (Camel case).

+

Example

+

 class Foo {
+                 void bar() {
+                     int localVariable = 1; // This is in camel case, so it's ok
+                     int local_variable = 1; // This will be reported unless you change the regex
+
+                     final int i_var = 1; // final local variables can be configured separately
+
+                     try {
+                         foo();
+                     } catch (IllegalArgumentException e_illegal) {
+                         // exception block parameters can be configured separately
+                     }
+
+                 }
+             }

+

Full documentation

]]>
+ pmd + codestyle +
+ + LogicInversion + Logic inversion + category/java/design.xml/LogicInversion + MAJOR + Title of issues: Use opposite operator instead of the logic complement operator. +

Use opposite operator instead of negating the whole expression with a logic complement operator.

+

Example

+

 public boolean bar(int a, int b) {
+
+     if (!(a == b)) { // use !=
+          return false;
+      }
+
+     if (!(a < b)) { // use >=
+          return false;
+     }
+
+     return true;
+ }

+

Alternative rule: java:S1940

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + LongVariable + Long variable + category/java/codestyle.xml/LongVariable + MAJOR + Title of issues: Avoid excessively long variable names like {0} +

Fields, formal arguments, or local variable names that are too long can make the code difficult to follow.

+

Example

+

 public class Something {
+     int reallyLongIntName = -3;             // VIOLATION - Field
+     public static void main( String argumentsList[] ) { // VIOLATION - Formal
+         int otherReallyLongName = -5;       // VIOLATION - Local
+         for (int interestingIntIndex = 0;   // VIOLATION - For
+              interestingIntIndex < 10;
+              interestingIntIndex ++ ) {
+     }
+ }

+

Alternative rule: java:S117

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative + + minimum + + 17 + INTEGER + +
+ + LooseCoupling + Loose coupling + category/java/bestpractices.xml/LooseCoupling + MAJOR + Title of issues: Avoid using implementation types like '{0}'; use the interface instead +

Excessive coupling to implementation types (e.g., HashSet) limits your ability to use alternate +implementations in the future as requirements change. Whenever available, declare variables +and parameters using a more general type (e.g, Set).

+

This rule reports uses of concrete collection types. User-defined types that should be treated +the same as interfaces can be configured with the property allowedTypes.

+

Example

+

 import java.util.ArrayList;
+ import java.util.HashSet;
+
+ public class Bar {
+     // sub-optimal approach
+     private ArrayList<SomeType> list = new ArrayList<>();
+
+     public HashSet<SomeType> getFoo() {
+         return new HashSet<SomeType>();
+     }
+
+     // preferred approach
+     private List<SomeType> list = new ArrayList<>();
+
+     public Set<SomeType> getFoo() {
+         return new HashSet<SomeType>();
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + LoosePackageCoupling + Loose package coupling + category/java/design.xml/LoosePackageCoupling + MAJOR + Title of issues: Use of '{0}' outside of package hierarchy '{1}' is not recommended; use recommended classes instead +

Avoid using classes from the configured package hierarchy outside of the package hierarchy, +except when using one of the configured allowed classes.

+

Example

+

 package some.package;
+
+ import some.other.package.subpackage.subsubpackage.DontUseThisClass;
+
+ public class Bar {
+     DontUseThisClass boo = new DontUseThisClass();
+ }

+

Full documentation

]]>
+ pmd + design +
+ + MDBAndSessionBeanNamingConvention + MDBAnd session bean naming convention + category/java/codestyle.xml/MDBAndSessionBeanNamingConvention + MINOR + Title of issues: SessionBean or MessageBean should be suffixed by Bean +

The EJB Specification states that any MessageDrivenBean or SessionBean should be suffixed by 'Bean'.

+

Example

+

 public class SomeBean implements SessionBean{}                  // proper name
+
+ public class MissingTheProperSuffix implements SessionBean {}   // non-standard name

+

Full documentation

]]>
+ pmd + codestyle +
+ + MethodArgumentCouldBeFinal + Method argument could be final + category/java/codestyle.xml/MethodArgumentCouldBeFinal + MAJOR + Title of issues: Parameter '{0}' is not assigned and could be declared final +

Reports method and constructor parameters that can be made final because they are never reassigned within the body of the method.

+

This rule ignores unused parameters so as not to overlap with the rule {% rule java/bestpractices/UnusedFormalParameter %}. + It will also ignore the parameters of abstract methods.

+

Example

+

 class Foo {
+     // reported, parameter can be declared final
+     public String foo1(String param) {
+         return param;
+     }
+     // not reported, parameter is declared final
+     public String foo2(final String param) {
+         return param.trim();
+     }
+     // not reported because param is unused
+     public String unusedParam(String param) {
+         return "abc";
+     }
+ }

+

Alternative rule: java:S1226

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + MethodNamingConventions + Method naming conventions + category/java/codestyle.xml/MethodNamingConventions + BLOCKER + Title of issues: The {0} name '{1}' doesn't match '{2}' +

Configurable naming conventions for method declarations. This rule reports + method declarations which do not match the regex that applies to their + specific kind (e.g. JUnit test or native method). Each regex can be + configured through properties.

+

By default, this rule uses the standard Java naming convention (Camel case).

+

Example

+

 public class Foo {
+     public void fooStuff() {
+     }
+ }

+

Alternative rule: java:S100

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + MethodReturnsInternalArray + Method returns internal array + category/java/bestpractices.xml/MethodReturnsInternalArray + MAJOR + Title of issues: Returning '{0}' may expose an internal array. +

Exposing internal arrays to the caller violates object encapsulation since elements can be +removed or replaced outside of the object that owns it. It is safer to return a copy of the array.

+

Example

+

 public class SecureSystem {
+     UserData [] ud;
+     public UserData [] getUserData() {
+         // Don't return directly the internal array, return a copy
+         return ud;
+     }
+ }

+

Alternative rule: java:S2384

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + MethodWithSameNameAsEnclosingClass + Method with same name as enclosing class + category/java/errorprone.xml/MethodWithSameNameAsEnclosingClass + MAJOR + Title of issues: A method should not have the same name as its containing class +

A method should not have the same name as its containing class. +This would be confusing as it would look like a constructor.

+

Example

+

 public class MyClass {
+
+     public MyClass() {}         // this is OK because it is a constructor
+
+     public void MyClass() {}    // this is bad because it is a method
+ }

+

Alternative rule: java:S1223

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + MisplacedNullCheck + Misplaced null check + category/java/errorprone.xml/MisplacedNullCheck + MAJOR + Title of issues: The null check here is misplaced; if the variable '{0}' is null there will be a NullPointerException +

The null check here is misplaced. If the variable is null a NullPointerException will be thrown. +Either the check is useless (the variable will never be null) or it is incorrect.

+

Examples

+

Example 1

+

 public class Foo {
+     void bar() {
+         if (a.equals(baz) && a != null) {} // a could be null, misplaced null check
+
+         if (a != null && a.equals(baz)) {} // correct null check
+     }
+ }

+

Example 2

+

 public class Foo {
+     void bar() {
+         if (a.equals(baz) || a == null) {} // a could be null, misplaced null check
+
+         if (a == null || a.equals(baz)) {} // correct null check
+     }
+ }

+

Alternative rules: java:S1697, java:S2259

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + MissingOverride + Missing override + category/java/bestpractices.xml/MissingOverride + MAJOR + Title of issues: The method '{0}' is missing an @Override annotation. +

Annotating overridden methods with @Override ensures at compile time that + the method really overrides one, which helps refactoring and clarifies intent.

+

Example

+

 public class Foo implements Runnable {
+                 // This method is overridden, and should have an @Override annotation
+                 public void run() {
+
+                 }
+             }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + MissingSerialVersionUID + Missing serial version UID + category/java/errorprone.xml/MissingSerialVersionUID + MAJOR + Title of issues: Classes implementing Serializable should set a serialVersionUID +

Serializable classes should provide a serialVersionUID field. +The serialVersionUID field is also needed for abstract base classes. Each individual class in the inheritance +chain needs an own serialVersionUID field. See also Should an abstract class have a serialVersionUID.

+

Example

+

 public class Foo implements java.io.Serializable {
+     String name;
+     // Define serialization id to avoid serialization related bugs
+     // i.e., public static final long serialVersionUID = 4328743;
+ }

+

Alternative rule: java:S2057

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + MissingStaticMethodInNonInstantiatableClass + Missing static method in non instantiatable class + category/java/errorprone.xml/MissingStaticMethodInNonInstantiatableClass + MAJOR + Title of issues: Class cannot be instantiated and does not provide any static methods or fields +

A class that has private constructors and does not have any static methods or fields cannot be used.

+

When one of the private constructors is annotated with one of the annotations, then the class is not considered +non-instantiatable anymore and no violation will be reported. +See the property annotations.

+

Example

+

 // This class is unusable, since it cannot be
+ // instantiated (private constructor),
+ // and no static method can be called.
+
+ public class Foo {
+   private Foo() {}
+   void foo() {}
+ }

+

Full documentation

]]>
+ pmd + errorprone + + annotations + + org.springframework.beans.factory.annotation.Autowired,javax.inject.Inject,com.google.inject.Inject,lombok.Builder + STRING + +
+ + MoreThanOneLogger + More than one logger + category/java/errorprone.xml/MoreThanOneLogger + CRITICAL + Title of issues: Class contains more than one logger. +

Normally only one logger is used in each class. This rule supports slf4j, log4j, Java Util Logging and +log4j2 (since 6.19.0).

+

Example

+

 public class Foo {
+     Logger log = Logger.getLogger(Foo.class.getName());
+     // It is very rare to see two loggers on a class, normally
+     // log information is multiplexed by levels
+     Logger log2= Logger.getLogger(Foo.class.getName());
+ }

+

Alternative rule: java:S1312

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + MutableStaticState + Mutable static state + category/java/design.xml/MutableStaticState + MAJOR + Title of issues: Do not use non-final non-private static fields +

Non-private static fields should be made constants (or immutable references) by +declaring them final.

+

Non-private non-final static fields break encapsulation and can lead to hard to find +bugs, since these fields can be modified from anywhere within the program. +Callers can trivially access and modify non-private non-final static fields. Neither +accesses nor modifications can be guarded against, and newly set values cannot +be validated.

+

If you are using this rule, then you don't need this +rule {% rule java/errorprone/AssignmentToNonFinalStatic %}.

+

Example

+

 public class Greeter { public static Foo foo = new Foo(); ... }       // avoid this
+ public class Greeter { public static final Foo FOO = new Foo(); ... } // use this instead

+

Full documentation

]]>
+ pmd + design +
+ + NPathComplexity + NPath complexity + category/java/design.xml/NPathComplexity + MAJOR + Title of issues: The {0} '{1}' has an NPath complexity of {2}, current threshold is {3} +

The NPath complexity of a method is the number of acyclic execution paths through that method. +While cyclomatic complexity counts the number of decision points in a method, NPath counts the number of +full paths from the beginning to the end of the block of the method. That metric grows exponentially, as +it multiplies the complexity of statements in the same block. For more details on the calculation, see the +documentation NPATH.

+

A threshold of 200 is generally considered the point where measures should be taken to reduce +complexity and increase readability.

+

Example

+

 public class Foo {
+   public static void bar() { // Ncss = 252: reported!
+     boolean a, b = true;
+     try { // 2 * 2 + 2 = 6
+       if (true) { // 2
+         List buz = new ArrayList();
+       }
+
+       for(int i = 0; i < 19; i++) { // * 2
+         List buz = new ArrayList();
+       }
+     } catch(Exception e) {
+       if (true) { // 2
+         e.printStackTrace();
+       }
+     }
+
+     while (j++ < 20) { //  * 2
+       List buz = new ArrayList();
+     }
+
+     switch(j) { // * 7
+       case 1:
+       case 2: break;
+       case 3: j = 5; break;
+       case 4: if (b && a) { bar(); } break;
+       default: break;
+     }
+
+     do { // * 3
+         List buz = new ArrayList();
+     } while (a && j++ < 30);
+   }
+ }

+

Full documentation

]]>
+ pmd + design +
+ + NcssCount + Ncss count + category/java/design.xml/NcssCount + MAJOR + Title of issues: The {0} '{1}' has a NCSS line count of {2}. +

This rule uses the NCSS (Non-Commenting Source Statements) metric to determine the number of lines +of code in a class, method or constructor. NCSS ignores comments, blank lines, and only counts actual +statements. For more details on the calculation, see the documentation +NCSS.

+

Example

+

 import java.util.Collections;       // +0
+ import java.io.IOException;         // +0
+
+ class Foo {                         // +1, total Ncss = 12
+
+   public void bigMethod()           // +1
+       throws IOException {
+     int x = 0, y = 2;               // +1
+     boolean a = false, b = true;    // +1
+
+     if (a || b) {                   // +1
+       try {                         // +1
+         do {                        // +1
+           x += 2;                   // +1
+         } while (x < 12);
+
+         System.exit(0);             // +1
+       } catch (IOException ioe) {   // +1
+         throw new PatheticFailException(ioe); // +1
+       }
+     } else {
+       assert false;                 // +1
+     }
+   }
+ }

+

Full documentation

]]>
+ pmd + design +
+ + NoPackage + No package + category/java/codestyle.xml/NoPackage + MAJOR + Title of issues: All classes, interfaces, enums and annotations must belong to a named package +

Detects when a class, interface, enum or annotation does not have a package definition.

+

Example

+

 // no package declaration
+ public class ClassInDefaultPackage {
+ }

+

Alternative rule: java:S1220

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + NonCaseLabelInSwitch + Non case label in switch + category/java/errorprone.xml/NonCaseLabelInSwitch + MAJOR + Title of issues: A non-case label was present in a switch statement or expression +

A non-case label (e.g. a named break/continue label) was present in a switch statement or switch expression. +This is legal, but confusing. It is easy to mix up the case labels and the non-case labels.

+

Note: This rule was renamed from NonCaseLabelInSwitchStatement with PMD 7.7.0.

+

Example

+

 public class Foo {
+   void bar(int a) {
+    switch (a) {
+      case 1:
+        // do something
+      mylabel: // this is legal, but confusing!
+        break;
+      default:
+        break;
+     }
+   }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + NonExhaustiveSwitch + Non exhaustive switch + category/java/bestpractices.xml/NonExhaustiveSwitch + MAJOR + Title of issues: Switch statements or expressions should be exhaustive, add a default case (or missing enum branches) +

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.

+

This rule doesn't consider Switch Statements, that use Pattern Matching, since for these the + compiler already ensures that all cases are covered. The same is true for Switch Expressions, + which are also not considered by this rule.

+

Example

+

 class Foo {{
+     int x = 2;
+     switch (x) {
+       case 1: int j = 6;
+       case 2: int j = 8;
+       // missing default: here
+     }
+ }}

+

Full documentation

]]>
+ pmd + bestpractices +
+ + NonSerializableClass + Non serializable class + category/java/errorprone.xml/NonSerializableClass + MAJOR + Title of issues: The field '{0}' of serializable class '{1}' is of non-serializable type '{2}'. +

If a class is marked as Serializable, then all fields need to be serializable as well. In order to exclude +a field, it can be marked as transient. Static fields are not considered.

+

This rule reports all fields, that are not serializable.

+

If a class implements the methods to perform manual serialization (writeObject, readObject) or uses +a replacement object (writeReplace, readResolve) then this class is ignored.

+

Note: This rule has been revamped with PMD 6.52.0. It was previously called "BeanMembersShouldSerialize". +The property prefix has been deprecated, since in a serializable class all fields have to be +serializable regardless of the name.

+

Example

+

 class Buzz implements java.io.Serializable {
+     private static final long serialVersionUID = 1L;
+
+     private transient int someFoo;          // good, it's transient
+     private static int otherFoo;            // also OK, it's static
+     private java.io.FileInputStream stream; // bad - FileInputStream is not serializable
+
+     public void setStream(FileInputStream stream) {
+         this.stream = stream;
+     }
+
+     public int getSomeFoo() {
+           return this.someFoo;
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + NonStaticInitializer + Non static initializer + category/java/errorprone.xml/NonStaticInitializer + MAJOR + Title of issues: Non-static initializers are confusing +

A non-static initializer block will be called any time a constructor is invoked (just prior to +invoking the constructor). While this is a valid language construct, it is rarely used and is +confusing.

+

Example

+

 public class MyClass {
+   // this block gets run before any call to a constructor
+   {
+     System.out.println("I am about to construct myself");
+   }
+ }

+

Alternative rule: java:S1171

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + NonThreadSafeSingleton + Non thread safe singleton + category/java/multithreading.xml/NonThreadSafeSingleton + MAJOR + Title of issues: Singleton is not thread safe +

Non-thread safe singletons can result in bad state changes. Eliminate +static singletons if possible by instantiating the object directly. Static +singletons are usually not needed as only a single instance exists anyway. +Other possible fixes are to synchronize the entire method or to use an +initialize-on-demand holder class.

+

Refrain from using the double-checked locking pattern. The Java Memory Model doesn't +guarantee it to work unless the variable is declared as volatile, adding an uneeded +performance penalty. Reference

+

See Effective Java, item 48.

+

Example

+

 private static Foo foo = null;
+
+ //multiple simultaneous callers may see partially initialized objects
+ public static Foo getFoo() {
+     if (foo==null) {
+         foo = new Foo();
+     }
+     return foo;
+ }

+

Alternative rule: java:S2444

+

Full documentation

]]>
+ pmd + multithreading + has-sonar-alternative +
+ + NullAssignment + Null assignment + category/java/errorprone.xml/NullAssignment + MAJOR + Title of issues: Assigning an Object to null is a code smell. Consider refactoring. +

Assigning a "null" to a variable (outside of its declaration) is usually bad form. Sometimes, this type +of assignment is an indication that the programmer doesn't completely understand what is going on in the code.

+

NOTE: This sort of assignment may used in some cases to dereference objects and encourage garbage collection.

+

Example

+

 public void bar() {
+   Object x = null; // this is OK
+   x = new Object();
+      // big, complex piece of code here
+   x = null; // this is not required
+      // big, complex piece of code here
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + OneDeclarationPerLine + One declaration per line + category/java/bestpractices.xml/OneDeclarationPerLine + MINOR + Title of issues: Use one line for each declaration, it enhances code readability. +

Java allows the use of several variables declaration of the same type on one line. +However, it can lead to quite messy code. This rule looks for several declarations on the same line.

+

Example

+

 String name;            // separate declarations
+ String lastname;
+
+ String name, lastname;  // combined declaration, a violation
+
+ String name,
+        lastname;        // combined declaration on multiple lines, no violation by default.
+                         // Set property strictMode to true to mark this as violation.

+

Alternative rule: java:S122

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative + + strictMode + + false + BOOLEAN + +
+ + OnlyOneReturn + Only one return + category/java/codestyle.xml/OnlyOneReturn + MAJOR + Title of issues: A method should have only one exit point, and that should be the last statement in the method +

A method should have only one exit point, and that should be the last statement in the method.

+

Example

+

 public class OneReturnOnly1 {
+   public String foo(int x) {
+     if (x > 0) {
+       return "hey";   // first exit
+     }
+     return "hi";    // second exit
+   }
+ }

+

Alternative rule: java:S1142

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + OptimizableToArrayCall + Optimizable to array call + category/java/performance.xml/OptimizableToArrayCall + MAJOR + Title of issues: This call to Collection.toArray() may be optimizable +

Calls to a collection's toArray(E[]) method should specify a target array of zero size. This allows the JVM +to optimize the memory allocation and copying as much as possible.

+

Previous versions of this rule (pre PMD 6.0.0) suggested the opposite, but current JVM implementations +perform always better, when they have full control over the target array. And allocation an array via +reflection is nowadays as fast as the direct allocation.

+

See also Arrays of Wisdom of the Ancients

+

Note: If you don't need an array of the correct type, then the simple toArray() method without an array +is faster, but returns only an array of type Object[].

+

Example

+

 List<Foo> foos = getFoos();
+
+ // much better; this one allows the jvm to allocate an array of the correct size and effectively skip
+ // the zeroing, since each array element will be overridden anyways
+ Foo[] fooArray = foos.toArray(new Foo[0]);
+
+ // inefficient, the array needs to be zeroed out by the jvm before it is handed over to the toArray method
+ Foo[] fooArray = foos.toArray(new Foo[foos.size()]);

+

Full documentation

]]>
+ pmd + performance +
+ + OverrideBothEqualsAndHashcode + Override both equals and hashcode + category/java/errorprone.xml/OverrideBothEqualsAndHashcode + MAJOR + Title of issues: Ensure you override both equals() and hashCode() +

Override both public boolean Object.equals(Object other), and public int Object.hashCode(), or override neither. Even if you are inheriting a hashCode() from a parent class, consider implementing hashCode and explicitly delegating to your superclass.

+

Example

+

 public class Bar {        // poor, missing a hashcode() method
+     public boolean equals(Object o) {
+       // do some comparison
+     }
+ }
+
+ public class Baz {        // poor, missing an equals() method
+     public int hashCode() {
+       // return some hash value
+     }
+ }
+
+ public class Foo {        // perfect, both methods provided
+     public boolean equals(Object other) {
+       // do some comparison
+     }
+     public int hashCode() {
+       // return some hash value
+     }
+ }

+

Alternative rule: java:S1206

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + PackageCase + Package case + category/java/codestyle.xml/PackageCase + MAJOR + Title of issues: Package name contains upper case characters +

Detects when a package definition contains uppercase characters.

+

Example

+

 package com.MyCompany;  // should be lowercase name
+
+ public class SomeClass {
+ }

+

Alternative rule: java:S120

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + PrematureDeclaration + Premature declaration + category/java/codestyle.xml/PrematureDeclaration + MAJOR + Title of issues: Declaration of '{0}' can be moved closer to its usages +

Checks for variables that are defined before they might be used. A declaration is +deemed to be premature if there are some statements that may return or throw an +exception between the time the variable is declared and the time it is first read.

+

Some variables cannot be declared close to their first usage because of side-effects +occurring before they're first used. We try to avoid reporting those by considering +most method and constructor invocations to be impure. See the second example.

+

Note that this rule is meant to improve code readability but is not an optimization. +A smart JIT will not care whether the variable is declared prematurely or not, as it +can reorder code.

+

Examples

+

Example 1

+

 public int getLength(String[] strings) {
+
+     int length = 0; // could be moved closer to the loop
+
+     if (strings == null || strings.length == 0) return 0;
+
+     for (String str : strings) {
+         length += str.length();
+     }
+
+     return length;
+ }

+

Example 2

+

 public int getLength(String[] strings) {
+
+     int startTime = System.nanoTime(); // cannot be moved because initializer is impure
+
+     if (strings == null || strings.length == 0) {
+         // some error logic
+         throw new SomeException(...);
+     }
+
+     for (String str : strings) {
+         length += str.length();
+     }
+
+     return System.nanoTime() - startTime;
+ }

+

Alternative rule: java:S1941

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + PreserveStackTrace + Preserve stack trace + category/java/bestpractices.xml/PreserveStackTrace + MAJOR + Title of issues: Thrown exception does not preserve the stack trace of exception '{0}' on all code paths +

Reports exceptions that are thrown from within a catch block, yet don't refer to the +exception parameter declared by that catch block. The stack trace of the original +exception could be lost, which makes the thrown exception less informative.

+

To preserve the stack trace, the original exception may be used as the cause of +the new exception, using Throwable#initCause, or passed as a constructor argument +to the new exception. It may also be preserved using Throwable#addSuppressed. +The rule actually assumes that any method or constructor that takes the original +exception as argument preserves the original stack trace.

+

The rule allows InvocationTargetException and PrivilegedActionException to be +replaced by their cause exception. The discarded part of the stack trace is in those +cases only JDK-internal code, which is not very useful. The rule also ignores exceptions +whose name starts with ignored.

+

Example

+

 public class Foo {
+     void good() {
+         try{
+             Integer.parseInt("a");
+         } catch (Exception e) {
+             throw new Exception(e); // Ok, this initializes the cause of the new exception
+         }
+         try {
+             Integer.parseInt("a");
+         } catch (Exception e) {
+             throw (IllegalStateException)new IllegalStateException().initCause(e); // second possibility to create exception chain.
+         }
+     }
+     void wrong() {
+         try{
+             Integer.parseInt("a");
+         } catch (Exception e) {
+             // Violation: this only preserves the message and not the stack trace
+             throw new Exception(e.getMessage());
+         }
+     }
+ }

+

Alternative rule: java:S1166

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + PrimitiveWrapperInstantiation + Primitive wrapper instantiation + category/java/bestpractices.xml/PrimitiveWrapperInstantiation + MAJOR + Title of issues: Do not use new <code>{0}</code>(...), prefer <code>{0}</code>.valueOf(...) +

Reports usages of primitive wrapper constructors. They are deprecated + since Java 9 and should not be used. Even before Java 9, they can + be replaced with usage of the corresponding static valueOf factory method + (which may be automatically inserted by the compiler since Java 1.5). + This has the advantage that it may reuse common instances instead of creating + a new instance each time.

+

Note that for Boolean, the named constants Boolean.TRUE and Boolean.FALSE + are preferred instead of Boolean.valueOf.

+

Example

+

 public class Foo {
+                 private Integer ZERO = new Integer(0);      // violation
+                 private Integer ZERO1 = Integer.valueOf(0); // better
+                 private Integer ZERO1 = 0;                  // even better
+             }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + ProperCloneImplementation + Proper clone implementation + category/java/errorprone.xml/ProperCloneImplementation + CRITICAL + Title of issues: Object clone() should be implemented with super.clone() +

Object clone() should be implemented with super.clone().

+

Example

+

 class Foo{
+     public Object clone(){
+         return new Foo(); // This is bad
+     }
+ }

+

Alternative rule: java:S1182

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + ProperLogger + Proper logger + category/java/errorprone.xml/ProperLogger + MAJOR + Title of issues: Logger should be defined private static final and have the correct class +

A logger should normally be defined private static final and be associated with the correct class. +private final Log log; is also allowed for rare cases where loggers need to be passed around, +with the restriction that the logger needs to be passed into the constructor.

+

Example

+

 public class Foo {
+
+     private static final Log LOG = LogFactory.getLog(Foo.class);    // proper way
+
+     protected Log LOG = LogFactory.getLog(Testclass.class);         // wrong approach
+ }

+

Alternative rule: java:S1312

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative + + staticLoggerName + + LOG + STRING + + + loggerName + + log + STRING + + + loggerClass + + org.apache.commons.logging.Log + STRING + +
+ + RedundantFieldInitializer + Redundant field initializer + category/java/performance.xml/RedundantFieldInitializer + MAJOR + Title of issues: Avoid using redundant field initializer for '${variableName}' +

Java will initialize fields with known default values so any explicit initialization of those same defaults +is redundant and results in a larger class file (approximately three additional bytecode instructions per field).

+

Example

+

 public class C {
+     boolean b   = false;    // examples of redundant initializers
+     byte by     = 0;
+     short s     = 0;
+     char c      = 0;
+     int i       = 0;
+     long l      = 0;
+
+     float f     = .0f;    // all possible float literals
+     double d    = 0d;     // all possible double literals
+     Object o    = null;
+
+     MyClass mca[] = null;
+     int i1 = 0, ia1[] = null;
+
+     class Nested {
+         boolean b = false;
+     }
+ }

+

Full documentation

]]>
+ pmd + performance +
+ + RemoteInterfaceNamingConvention + Remote interface naming convention + category/java/codestyle.xml/RemoteInterfaceNamingConvention + MINOR + Title of issues: Remote Interface of a Session EJB should NOT be suffixed +

Remote Interface of a Session EJB should not have a suffix.

+

Example

+

 /* Poor Session suffix */
+ public interface BadSuffixSession extends javax.ejb.EJBObject {}
+
+ /* Poor EJB suffix */
+ public interface BadSuffixEJB extends javax.ejb.EJBObject {}
+
+ /* Poor Bean suffix */
+ public interface BadSuffixBean extends javax.ejb.EJBObject {}

+

Full documentation

]]>
+ pmd + codestyle +
+ + RemoteSessionInterfaceNamingConvention + Remote session interface naming convention + category/java/codestyle.xml/RemoteSessionInterfaceNamingConvention + MINOR + Title of issues: Remote Home interface of a Session EJB should be suffixed by 'Home' +

A Remote Home interface type of a Session EJB should be suffixed by 'Home'.

+

Example

+

 public interface MyBeautifulHome extends javax.ejb.EJBHome {}       // proper name
+
+ public interface MissingProperSuffix extends javax.ejb.EJBHome {}   // non-standard name

+

Full documentation

]]>
+ pmd + codestyle +
+ + ReplaceEnumerationWithIterator + Replace enumeration with iterator + category/java/bestpractices.xml/ReplaceEnumerationWithIterator + MAJOR + Title of issues: Consider replacing this Enumeration with the newer java.util.Iterator +

Consider replacing Enumeration usages with the newer java.util.Iterator

+

Example

+

 public class Foo implements Enumeration {
+     private int x = 42;
+     public boolean hasMoreElements() {
+         return true;
+     }
+     public Object nextElement() {
+         return String.valueOf(i++);
+     }
+ }

+

Alternative rule: java:S1150

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + ReplaceHashtableWithMap + Replace hashtable with map + category/java/bestpractices.xml/ReplaceHashtableWithMap + MAJOR + Title of issues: Consider replacing this Hashtable with the newer java.util.Map +

Consider replacing Hashtable usage with the newer java.util.Map if thread safety is not required.

+

Example

+

 public class Foo {
+     void bar() {
+         Hashtable h = new Hashtable();
+     }
+ }

+

Alternative rule: java:S1149

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + ReplaceVectorWithList + Replace vector with list + category/java/bestpractices.xml/ReplaceVectorWithList + MAJOR + Title of issues: Consider replacing this Vector with the newer java.util.List +

Consider replacing Vector usages with the newer java.util.ArrayList if expensive thread-safe operations are not required.

+

Example

+

 import java.util.Vector;
+ public class Foo {
+     void bar() {
+         Vector v = new Vector();
+     }
+ }

+

Alternative rule: java:S1149

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + ReturnEmptyCollectionRatherThanNull + Return empty collection rather than null + category/java/errorprone.xml/ReturnEmptyCollectionRatherThanNull + BLOCKER + Title of issues: Return an empty collection rather than 'null'. +

For any method that returns an collection (such as an array, Collection or Map), it is better to return +an empty one rather than a null reference. This removes the need for null checking all results and avoids +inadvertent NullPointerExceptions.

+

See Effective Java, 3rd Edition, Item 54: Return empty collections or arrays instead of null

+

Example

+

 public class Example {
+     // Not a good idea...
+     public int[] badBehavior() {
+         // ...
+         return null;
+     }
+
+     // Good behavior
+     public String[] bonnePratique() {
+         //...
+         return new String[0];
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + ReturnFromFinallyBlock + Return from finally block + category/java/errorprone.xml/ReturnFromFinallyBlock + MAJOR + Title of issues: Avoid returning from a finally block +

Avoid returning from a finally block, this can discard exceptions.

+

Example

+

 public class Bar {
+     public String foo() {
+         try {
+             throw new Exception( "My Exception" );
+         } catch (Exception e) {
+             throw e;
+         } finally {
+             return "A. O. K."; // return not recommended here
+         }
+     }
+ }

+

Alternative rule: java:S1143

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + ShortClassName + Short class name + category/java/codestyle.xml/ShortClassName + MINOR + Title of issues: Avoid short class names like {0} +

Short Classnames with fewer than e.g. five characters are not recommended.

+

Example

+

 public class Foo {
+ }

+

Alternative rule: java:S101

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative + + minimum + + 5 + INTEGER + +
+ + ShortMethodName + Short method name + category/java/codestyle.xml/ShortMethodName + MAJOR + Title of issues: Avoid using short method names +

Method names that are very short are not helpful to the reader.

+

Example

+

 public class ShortMethod {
+     public void a( int i ) { // Violation
+     }
+ }

+

Alternative rule: java:S100

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative + + minimum + + 3 + INTEGER + +
+ + ShortVariable + Short variable + category/java/codestyle.xml/ShortVariable + MAJOR + Title of issues: Avoid variables with short names like {0} +

Fields, local variables, enum constant names or parameter names that are very short are not helpful to the reader.

+

Example

+

 public class Something {
+     private int q = 15;                         // field - too short
+     public static void main( String as[] ) {    // formal arg - too short
+         int r = 20 + q;                         // local var - too short
+         for (int i = 0; i < 10; i++) {          // not a violation (inside 'for' loop)
+             r += q;
+         }
+         for (Integer i : numbers) {             // not a violation (inside 'for-each' loop)
+             r += q;
+         }
+     }
+ }

+

Alternative rule: java:S117

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative + + minimum + + 3 + INTEGER + +
+ + SignatureDeclareThrowsException + Signature declare throws exception + category/java/design.xml/SignatureDeclareThrowsException + MAJOR + Title of issues: A method/constructor should not explicitly throw java.lang.Exception +

A method/constructor shouldn't explicitly throw the generic java.lang.Exception, since it +is unclear which exceptions that can be thrown from the methods. It might be +difficult to document and understand such vague interfaces. Use either a class +derived from RuntimeException or a checked exception.

+

Example

+

 public void foo() throws Exception {
+ }

+

Alternative rule: java:S112

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + SimpleDateFormatNeedsLocale + Simple date format needs locale + category/java/errorprone.xml/SimpleDateFormatNeedsLocale + MAJOR + Title of issues: When instantiating a SimpleDateFormat object, specify a Locale +

Be sure to specify a Locale when creating SimpleDateFormat instances to ensure that locale-appropriate +formatting is used.

+

Example

+

 public class Foo {
+   // Should specify Locale.US (or whatever)
+   private SimpleDateFormat sdf = new SimpleDateFormat("pattern");
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + SimplifiableTestAssertion + Simplifiable test assertion + category/java/bestpractices.xml/SimplifiableTestAssertion + MAJOR + Title of issues: Assertion may be simplified using {0} +

Reports test assertions that may be simplified using a more specific + assertion method. This enables better error messages, and makes the + assertions more readable.

+

Example

+

 import org.junit.Test;
+ import static org.junit.Assert.*;
+
+ class SomeTestClass {
+     Object a,b;
+     @Test
+     void testMethod() {
+         assertTrue(a.equals(b)); // could be assertEquals(a, b);
+         assertTrue(!a.equals(b)); // could be assertNotEquals(a, b);
+
+         assertTrue(!something); // could be assertFalse(something);
+         assertFalse(!something); // could be assertTrue(something);
+
+         assertTrue(a == b); // could be assertSame(a, b);
+         assertTrue(a != b); // could be assertNotSame(a, b);
+
+         assertTrue(a == null); // could be assertNull(a);
+         assertTrue(a != null); // could be assertNotNull(a);
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + SimplifiedTernary + Simplified ternary + category/java/design.xml/SimplifiedTernary + MAJOR + Title of issues: This conditional expression can be simplified with || or && +

Reports ternary expression with the form condition ? literalBoolean : foo +or condition ? foo : literalBoolean.

+

These expressions can be simplified as follows:

+
  • condition ? true : expr simplifies to condition || expr
  • condition ? false : expr simplifies to !condition && expr
  • condition ? expr : true simplifies to !condition || expr
  • condition ? expr : false simplifies to condition && expr
+

Example

+

 public class Foo {
+     public boolean test() {
+         return condition ? true : something(); // can be as simple as return condition || something();
+     }
+
+     public void test2() {
+         final boolean value = condition ? false : something(); // can be as simple as value = !condition && something();
+     }
+
+     public boolean test3() {
+         return condition ? something() : true; // can be as simple as return !condition || something();
+     }
+
+     public void test4() {
+         final boolean otherValue = condition ? something() : false; // can be as simple as condition && something();
+     }
+
+     public boolean test5() {
+         return condition ? true : false; // can be as simple as return condition;
+     }
+ }

+

Full documentation

]]>
+ pmd + design +
+ + SimplifyBooleanExpressions + Simplify boolean expressions + category/java/design.xml/SimplifyBooleanExpressions + MAJOR + Title of issues: Avoid unnecessary comparisons in boolean expressions +

Avoid unnecessary comparisons in boolean expressions, they serve no purpose and impacts readability.

+

Example

+

 public class Bar {
+   // can be simplified to
+   // bar = isFoo();
+   private boolean bar = (isFoo() == true);
+
+   public isFoo() { return false;}
+ }

+

Alternative rule: java:S1125

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + SimplifyBooleanReturns + Simplify boolean returns + category/java/design.xml/SimplifyBooleanReturns + MAJOR + Title of issues: This if statement can be replaced by <code>{0}</code> +

Avoid unnecessary if-then-else statements when returning a boolean. The result of +the conditional test can be returned instead.

+

Example

+

 public boolean isBarEqualTo(int x) {
+     if (bar == x) {      // this bit of code...
+         return true;
+     } else {
+         return false;
+     }
+ }
+
+ public boolean isBarEqualTo(int x) {
+     return bar == x;    // can be replaced with this
+ }

+

Alternative rule: java:S1126

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + SimplifyConditional + Simplify conditional + category/java/design.xml/SimplifyConditional + MAJOR + Title of issues: No need to check for null before an instanceof +

No need to check for null before an instanceof; the instanceof keyword returns false when given a null argument.

+

Example

+

 class Foo {
+   void bar(Object x) {
+     if (x != null && x instanceof Bar) {
+       // just drop the "x != null" check
+     }
+   }
+ }

+

Full documentation

]]>
+ pmd + design +
+ + SingleMethodSingleton + Single method singleton + category/java/errorprone.xml/SingleMethodSingleton + CRITICAL + Title of issues: Class contains multiple getInstance methods. Please review. +

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.

+

Example

+

 public class Singleton {
+
+     private static Singleton singleton = new Singleton( );
+
+     private Singleton(){ }
+
+     public static Singleton getInstance( ) {
+         return singleton;
+     }
+
+     public static Singleton getInstance(Object obj){
+         Singleton singleton = (Singleton) obj;
+         return singleton;           //violation
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + SingletonClassReturningNewInstance + Singleton class returning new instance + category/java/errorprone.xml/SingletonClassReturningNewInstance + CRITICAL + Title of issues: getInstance method always creates a new object and hence does not comply to Singleton Design Pattern behaviour. Please review +

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.

+

Example

+

 class Singleton {
+     private static Singleton instance = null;
+     public static Singleton getInstance() {
+         synchronized(Singleton.class) {
+             return new Singleton(); // this should be assigned to the field
+         }
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + SingularField + Singular field + category/java/design.xml/SingularField + MAJOR + Title of issues: Perhaps '{0}' could be replaced by a local variable. +

Reports fields which may be converted to a local variable. This is so because +in every method where the field is used, it is assigned before it is first read. +Hence, the value that the field had before the method call may not be observed, +so it might as well not be stored in the enclosing object.

+

Limitations:

+
  • We can only check private fields for now.
  • The rule is not aware of threading, so it may cause false positives in concurrent code. Such FPs are best handled by suppression (see also the ignoredAnnotations property).
+

Example

+

 public class Foo {
+     private int x; // this will be reported
+
+     public int foo(int y) {
+        x = y + 5; // assigned before any read
+        return x;
+     }
+
+     public int fooOk(int y) {
+        int z = y + 5; // might as well be a local like here
+        return z;
+     }
+ }

+

Full documentation

]]>
+ pmd + design +
+ + StaticEJBFieldShouldBeFinal + Static EJBField should be final + category/java/errorprone.xml/StaticEJBFieldShouldBeFinal + MAJOR + Title of issues: EJB's shouldn't have non-final static fields +

According to the J2EE specification, an EJB should not have any static fields +with write access. However, static read-only fields are allowed. This ensures proper +behavior especially when instances are distributed by the container on several JREs.

+

Example

+

 public class SomeEJB extends EJBObject implements EJBLocalHome {
+
+     private static int CountA;          // poor, field can be edited
+
+     private static final int CountB;    // preferred, read-only access
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + StringBufferInstantiationWithChar + String buffer instantiation with char + category/java/errorprone.xml/StringBufferInstantiationWithChar + MINOR + Title of issues: Argument to new StringBuilder() or new StringBuffer() is implicitly converted from char to int +

Individual character values provided as initialization arguments will be converted into integers. +This can lead to internal buffer sizes that are larger than expected. Some examples:

+

 new StringBuffer()      //  16
+ new StringBuffer(6)     //  6
+ new StringBuffer("hello world")  // 11 + 16 = 27
+ new StringBuffer('A')   //  chr(A) = 65
+ new StringBuffer("A")   //  1 + 16 = 17
+
+ new StringBuilder()     //  16
+ new StringBuilder(6)    //  6
+ new StringBuilder("hello world")  // 11 + 16 = 27
+ new StringBuilder('C')   //  chr(C) = 67
+ new StringBuilder("A")   //  1 + 16 = 17

+

Example

+

 // misleading instantiation, these buffers
+ // are actually sized to 99 characters long
+ StringBuffer  sb1 = new StringBuffer('c');
+ StringBuilder sb2 = new StringBuilder('c');
+
+ // in these forms, just single characters are allocated
+ StringBuffer  sb3 = new StringBuffer("c");
+ StringBuilder sb4 = new StringBuilder("c");

+

Alternative rule: java:S1317

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + StringInstantiation + String instantiation + category/java/performance.xml/StringInstantiation + CRITICAL + Title of issues: Avoid instantiating String objects; this is usually unnecessary. +

Avoid instantiating String objects; this is usually unnecessary since they are immutable and can be safely shared.

+

Example

+

 private String bar = new String("bar"); // just do a String bar = "bar";

+

Full documentation

]]>
+ pmd + performance +
+ + StringToString + String to string + category/java/performance.xml/StringToString + MAJOR + Title of issues: Avoid calling toString() on String objects; this is unnecessary. +

Avoid calling toString() on objects already known to be string instances; this is unnecessary.

+

Example

+

 private String baz() {
+     String bar = "howdy";
+     return bar.toString();
+ }

+

Alternative rule: java:S1858

+

Full documentation

]]>
+ pmd + performance + has-sonar-alternative +
+ + SuspiciousEqualsMethodName + Suspicious equals method name + category/java/errorprone.xml/SuspiciousEqualsMethodName + CRITICAL + Title of issues: The method name and parameter number are suspiciously close to equals(Object) +

The method name and parameter number are suspiciously close to Object.equals, which can denote an +intention to override it. However, the method does not override Object.equals, but overloads it instead. +Overloading Object.equals method is confusing for other programmers, error-prone and hard to maintain, +especially when using inheritance, because @Override annotations used in subclasses can provide a false +sense of security. For more information on Object.equals method, see Effective Java, 3rd Edition, +Item 10: Obey the general contract when overriding equals.

+

Example

+

 public class Foo {
+    public int equals(Object o) {
+      // oops, this probably was supposed to be boolean equals
+    }
+    public boolean equals(String s) {
+      // oops, this probably was supposed to be equals(Object)
+    }
+    public boolean equals(Object o1, Object o2) {
+      // oops, this probably was supposed to be equals(Object)
+    }
+ }

+

Alternative rule: java:S1201

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + SuspiciousHashcodeMethodName + Suspicious hashcode method name + category/java/errorprone.xml/SuspiciousHashcodeMethodName + MAJOR + Title of issues: The method name and return type are suspiciously close to hashCode() +

The method name and return type are suspiciously close to hashCode(), which may denote an intention +to override the hashCode() method.

+

Example

+

 public class Foo {
+     public int hashcode() { // oops, this probably was supposed to be 'hashCode'
+     }
+ }

+

Alternative rule: java:S1221

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + SuspiciousOctalEscape + Suspicious octal escape + category/java/errorprone.xml/SuspiciousOctalEscape + MAJOR + Title of issues: Suspicious decimal characters following octal escape in string literal: {0} +

A suspicious octal escape sequence was found inside a String literal. +The Java language specification (section 3.10.6) says an octal +escape sequence inside a literal String shall consist of a backslash +followed by:

+

OctalDigit | OctalDigit OctalDigit | ZeroToThree OctalDigit OctalDigit

+

Any octal escape sequence followed by non-octal digits can be confusing, +e.g. "\038" is interpreted as the octal escape sequence "\03" followed by +the literal character "8".

+

Example

+

 public void foo() {
+   // interpreted as octal 12, followed by character '8'
+   System.out.println("suspicious: \128");
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + SwitchDensity + Switch density + category/java/design.xml/SwitchDensity + MAJOR + Title of issues: A high ratio of statements to labels in a switch statement. Consider refactoring. +

A high ratio of statements to labels in a switch statement implies that the switch statement +is overloaded. Consider moving the statements into new methods or creating subclasses based +on the switch variable.

+

Example

+

 public class Foo {
+   public void bar(int x) {
+     switch (x) {
+       case 1: {
+         // lots of statements
+         break;
+       } case 2: {
+         // lots of statements
+         break;
+       }
+     }
+   }
+ }

+

Alternative rule: java:S1151

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + SystemPrintln + System println + category/java/bestpractices.xml/SystemPrintln + CRITICAL + Title of issues: Usage of System.out/err +

References to System.(out|err).print are usually intended for debugging purposes and can remain in +the codebase even in production code. By using a logger one can enable/disable this behaviour at +will (and by priority) and avoid clogging the Standard out log.

+

Example

+

 class Foo{
+     Logger log = Logger.getLogger(Foo.class.getName());
+     public void testA () {
+         System.out.println("Entering test");
+         // Better use this
+         log.fine("Entering test");
+     }
+ }

+

Alternative rule: java:S106

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + TestClassWithoutTestCases + Test class without test cases + category/java/errorprone.xml/TestClassWithoutTestCases + MAJOR + Title of issues: The class '{0}' might be a test class, but it contains no test cases. +

Test classes typically end with the suffix "Test", "Tests" or "TestCase". Having a non-test class with that name +is not a good practice, since most people will assume it is a test case. Test classes have test methods +named "testXXX" (JUnit3) or use annotations (e.g. @Test).

+

The suffix can be configured using the property testClassPattern. To disable the detection of possible test classes +by name, set this property to an empty string.

+

Example

+

 //Consider changing the name of the class if it is not a test
+ //Consider adding test methods if it is a test
+ public class CarTest {
+    public static void main(String[] args) {
+     // do something
+    }
+    // code
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + TooFewBranchesForSwitch + Too few branches for switch + category/java/performance.xml/TooFewBranchesForSwitch + MAJOR + Title of issues: A switch with less than three branches is inefficient, use a 'if statement' instead. +

Switch statements are intended to be used to support complex branching behaviour. Using a switch for only a few +cases is ill-advised, since switches are not as easy to understand as if-else statements. In these cases use the +if-else statement to increase code readability.

+

Note: This rule was named TooFewBranchesForASwitchStatement before PMD 7.7.0.

+

Example

+

 // With a minimumNumberCaseForASwitch of 3
+ public class Foo {
+     public void bar(int condition) {
+         switch (condition) {
+             case 1:
+                 instruction;
+                 break;
+             default:
+                 break; // not enough for a 'switch' stmt, a simple 'if' stmt would have been more appropriate
+         }
+     }
+ }

+

Full documentation

]]>
+ pmd + performance + + minimumNumberCaseForASwitch + + 3 + INTEGER + +
+ + TooManyFields + Too many fields + category/java/design.xml/TooManyFields + MAJOR + Title of issues: Too many fields +

Classes that have too many fields can become unwieldy and could be redesigned to have fewer fields, +possibly through grouping related fields in new objects. For example, a class with individual +city/state/zip fields could park them within a single Address field.

+

Example

+

 public class Person {   // too many separate fields
+    int birthYear;
+    int birthMonth;
+    int birthDate;
+    float height;
+    float weight;
+ }
+
+ public class Person {   // this is more manageable
+    Date birthDate;
+    BodyMeasurements measurements;
+ }

+

Full documentation

]]>
+ pmd + design + + maxfields + + 15 + INTEGER + +
+ + TooManyMethods + Too many methods + category/java/design.xml/TooManyMethods + MAJOR + Title of issues: This class has too many methods, consider refactoring it. +

A class with too many methods is probably a good suspect for refactoring, in order to reduce its +complexity and find a way to have more fine grained objects.

+

Alternative rule: java:S1448

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative + + maxmethods + + 10 + INTEGER + +
+ + TooManyStaticImports + Too many static imports + category/java/codestyle.xml/TooManyStaticImports + MAJOR + Title of issues: Too many static imports may lead to messy code +

If you overuse the static import feature, it can make your program unreadable and +unmaintainable, polluting its namespace with all the static members you import. +Readers of your code (including you, a few months after you wrote it) will not know +which class a static member comes from (Sun 1.5 Language Guide).

+

Example

+

 import static Lennon;
+ import static Ringo;
+ import static George;
+ import static Paul;
+ import static Yoko; // Too much !

+

Full documentation

]]>
+ pmd + codestyle + + maximumStaticImports + + 4 + INTEGER + +
+ + UncommentedEmptyConstructor + Uncommented empty constructor + category/java/documentation.xml/UncommentedEmptyConstructor + MAJOR + Title of issues: Document empty constructor +

Uncommented Empty Constructor finds instances where a constructor does not +contain statements, but there is no comment. By explicitly commenting empty +constructors it is easier to distinguish between intentional (commented) +and unintentional empty constructors.

+

Example

+

 public Foo() {
+   // This constructor is intentionally empty. Nothing special is needed here.
+ }

+

Alternative rule: java:S2094

+

Full documentation

]]>
+ pmd + documentation + has-sonar-alternative + + ignoreExplicitConstructorInvocation + + false + BOOLEAN + +
+ + UncommentedEmptyMethodBody + Uncommented empty method body + category/java/documentation.xml/UncommentedEmptyMethodBody + MAJOR + Title of issues: Document empty method body +

Uncommented Empty Method Body finds instances where a method body does not contain +statements, but there is no comment. By explicitly commenting empty method bodies +it is easier to distinguish between intentional (commented) and unintentional +empty methods.

+

Example

+

 public void doSomething() {
+ }

+

Alternative rule: java:S1186

+

Full documentation

]]>
+ pmd + documentation + has-sonar-alternative +
+ + UnconditionalIfStatement + Unconditional if statement + category/java/errorprone.xml/UnconditionalIfStatement + MAJOR + Title of issues: Do not use 'if' statements that are always true or always false +

Do not use "if" statements whose conditionals are always true or always false.

+

Example

+

 public class Foo {
+     public void close() {
+         if (true) {        // fixed conditional, not recommended
+             // ...
+         }
+     }
+ }

+

Alternative rule: java:S2583

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + UnitTestAssertionsShouldIncludeMessage + Unit test assertions should include message + category/java/bestpractices.xml/UnitTestAssertionsShouldIncludeMessage + MAJOR + Title of issues: Unit test assertions should include a message +

Unit assertions should include an informative message - i.e., use the three-argument version of +assertEquals(), not the two-argument version.

+

This rule supports tests using JUnit (3, 4 and 5) and TestNG.

+

Note: This rule was named JUnitAssertionsShouldIncludeMessage before PMD 7.7.0.

+

Example

+

 public class Foo {
+     @Test
+     public void testSomething() {
+         assertEquals("foo", "bar");
+         // Use the form:
+         // assertEquals("Foo does not equals bar", "foo", "bar");
+         // instead
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UnitTestContainsTooManyAsserts + Unit test contains too many asserts + category/java/bestpractices.xml/UnitTestContainsTooManyAsserts + MAJOR + Title of issues: Unit tests should not contain more than ${maximumAsserts} assert(s). +

Unit tests should not contain too many asserts. Many asserts are indicative of a complex test, for which + it is harder to verify correctness. Consider breaking the test scenario into multiple, shorter test scenarios. + Customize the maximum number of assertions used by this Rule to suit your needs.

+

This rule checks for JUnit (3, 4 and 5) and TestNG Tests.

+

Note: This rule was named JUnitTestContainsTooManyAsserts before PMD 7.7.0.

+

Example

+

 public class MyTestCase {
+     // Ok
+     @Test
+     public void testMyCaseWithOneAssert() {
+         boolean myVar = false;
+         assertFalse("should be false", myVar);
+     }
+
+     // Bad, too many asserts (assuming max=1)
+     @Test
+     public void testMyCaseWithMoreAsserts() {
+         boolean myVar = false;
+         assertFalse("myVar should be false", myVar);
+         assertEquals("should equals false", false, myVar);
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UnitTestShouldIncludeAssert + Unit test should include assert + category/java/bestpractices.xml/UnitTestShouldIncludeAssert + MAJOR + Title of issues: This unit test should include assert() or fail() +

Unit tests should include at least one assertion. This makes the tests more robust, and using assert + with messages provide the developer a clearer idea of what the test does.

+

This rule checks for JUnit (3, 4 and 5) and TestNG Tests.

+

Note: This rule was named JUnitTestsShouldIncludeAssert before PMD 7.7.0.

+

Example

+

 public class Foo {
+    @Test
+    public void testSomething() {
+       Bar b = findBar();
+       // This is better than having a NullPointerException
+       // assertNotNull("bar not found", b);
+       b.work();
+    }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UnitTestShouldUseAfterAnnotation + Unit test should use after annotation + category/java/bestpractices.xml/UnitTestShouldUseAfterAnnotation + MAJOR + Title of issues: Apply the correct annotation if this method is used to clean up the tests +

This rule detects methods called tearDown() that are not properly annotated as a cleanup method. +This is primarily intended to assist in upgrading from JUnit 3, where tear down methods were required to be called tearDown(). +To a lesser extent, this may help detect omissions even under newer JUnit versions or under TestNG, +as long as you are following this convention to name the methods.

+
  • JUnit 4 will only execute methods annotated with @After after running each test.
  • JUnit 5 introduced @AfterEach and @AfterAll annotations to execute methods after each test or after all tests in the class, respectively.
  • TestNG provides the annotations @AfterMethod and @AfterClass to execute methods after each test or after tests in the class, respectively.
+

Note: This rule was named JUnit4TestShouldUseAfterAnnotation before PMD 7.7.0.

+

Example

+

 public class MyTest {
+     public void tearDown() {
+         bad();
+     }
+ }
+ public class MyTest2 {
+     @After public void tearDown() {
+         good();
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UnitTestShouldUseBeforeAnnotation + Unit test should use before annotation + category/java/bestpractices.xml/UnitTestShouldUseBeforeAnnotation + MAJOR + Title of issues: Apply the correct annotation if this method is used to set up the tests +

This rule detects methods called setUp() that are not properly annotated as a setup method. +This is primarily intended to assist in upgrading from JUnit 3, where setup methods were required to be called setUp(). +To a lesser extent, this may help detect omissions even under newer JUnit versions or under TestNG, +as long as you are following this convention to name the methods.

+
  • JUnit 4 will only execute methods annotated with @Before before all tests.
  • JUnit 5 introduced @BeforeEach and @BeforeAll annotations to execute methods before each test or before all tests in the class, respectively.
  • TestNG provides the annotations @BeforeMethod and @BeforeClass to execute methods before each test or before tests in the class, respectively.
+

Note: This rule was named JUnit4TestShouldUseBeforeAnnotation before PMD 7.7.0.

+

Example

+

 public class MyTest {
+     public void setUp() {
+         bad();
+     }
+ }
+ public class MyTest2 {
+     @Before public void setUp() {
+         good();
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UnitTestShouldUseTestAnnotation + Unit test should use test annotation + category/java/bestpractices.xml/UnitTestShouldUseTestAnnotation + MAJOR + Title of issues: Unit tests should use the @Test annotation or won't be run. In case of JUnit 5, test methods might use @RepeatedTest, @TestFactory, @TestTemplate or @ParameterizedTest annotations instead. +

The rule will detect any test method starting with "test" that is not properly annotated, and will therefore not be run.

+

In JUnit 4, only methods annotated with the @Test annotation are executed. + In JUnit 5, one of the following annotations should be used for tests: @Test, @RepeatedTest, @TestFactory, @TestTemplate or @ParameterizedTest. + In TestNG, only methods annotated with the @Test annotation are executed.

+

Note: This rule was named JUnit4TestShouldUseTestAnnotation before PMD 7.7.0.

+

Example

+

 public class MyTest {
+     public void testBad() {
+         doSomething();
+     }
+
+     @Test
+     public void testGood() {
+         doSomething();
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices + + testClassPattern + + Test + STRING + +
+ + UnnecessaryAnnotationValueElement + Unnecessary annotation value element + category/java/codestyle.xml/UnnecessaryAnnotationValueElement + MAJOR + Title of issues: Avoid the use of value in annotations when it's the only element +

Avoid the use of value in annotations when it's the only element.

+

Example

+

 @TestClassAnnotation(value = "TEST")
+ public class Foo {
+
+     @TestMemberAnnotation(value = "TEST")
+     private String y;
+
+     @TestMethodAnnotation(value = "TEST")
+     public void bar() {
+         int x = 42;
+         return;
+     }
+ }
+
+ // should be
+
+ @TestClassAnnotation("TEST")
+ public class Foo {
+
+     @TestMemberAnnotation("TEST")
+     private String y;
+
+     @TestMethodAnnotation("TEST")
+     public void bar() {
+         int x = 42;
+         return;
+     }
+ }

+

Full documentation

]]>
+ pmd + codestyle + + java7Compatibility + + false + BOOLEAN + +
+ + UnnecessaryBooleanAssertion + Unnecessary boolean assertion + category/java/errorprone.xml/UnnecessaryBooleanAssertion + MAJOR + Title of issues: assertTrue(true) or similar statements are unnecessary +

A JUnit test assertion with a boolean literal is unnecessary since it always will evaluate to the same thing. +Consider using flow control (in case of assertTrue(false) or similar) or simply removing +statements like assertTrue(true) and assertFalse(false). If you just want a test to halt after finding +an error, use the fail() method and provide an indication message of why it did.

+

Example

+

 public class SimpleTest extends TestCase {
+     public void testX() {
+         assertTrue(true);            // serves no real purpose - remove it
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + UnnecessaryBoxing + Unnecessary boxing + category/java/codestyle.xml/UnnecessaryBoxing + MAJOR + Title of issues: Unnecessary {0} +

Reports explicit boxing and unboxing conversions that may safely be removed, + either because they would be inserted by the compiler automatically, + or because they're semantically a noop (eg unboxing a value to rebox it immediately).

+

Note that this only handles boxing and unboxing conversions occurring through + calls to valueOf or one of the intValue, byteValue, etc. methods. Casts + that command a conversion are reported by {% rule UnnecessaryCast %} instead.

+

Example

+

 {
+         // Instead of
+         Integer integer = Integer.valueOf(2);
+         // you may just write
+         Integer integer = 2;
+
+         int i = integer.intValue(); // similarly for unboxing
+
+         // Instead of
+         int x = Integer.valueOf("42");
+         // you may just write
+         int x = Integer.parseInt("42");
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + UnnecessaryCaseChange + Unnecessary case change + category/java/errorprone.xml/UnnecessaryCaseChange + MAJOR + Title of issues: Using equalsIgnoreCase() is cleaner than using toUpperCase/toLowerCase().equals(). +

Using equalsIgnoreCase() is faster than using toUpperCase/toLowerCase().equals()

+

Example

+

 boolean answer1 = buz.toUpperCase().equals("BAZ");              // should be buz.equalsIgnoreCase("BAZ")
+
+ boolean answer2 = buz.toUpperCase().equalsIgnoreCase("BAZ");    // another unnecessary toUpperCase()

+

Alternative rule: java:S1157

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + UnnecessaryCast + Unnecessary cast + category/java/codestyle.xml/UnnecessaryCast + MAJOR + Title of issues: Unnecessary cast ({0}) +

Detects casts which could be removed as the operand of the cast is already suitable +for the context type. For instance, in the following: +

 Object context = (Comparable) "o";
+The cast is unnecessary. This is because String already is a subtype of both +Comparable and Object.

+

This will also flag casts that can be avoided because of the autoboxing feature of Java 5. +

 Integer integer = (Integer) 1;
+The literal would be autoboxed to Integer anyway.

+

Examples

+

Example 1

+

 import java.util.function.Function;
+ class SomeClass {
+    static {
+       Object o; long l; int i; Integer boxedInt;
+
+       // reference conversions
+
+       o = (Object) new SomeClass();      // unnecessary
+       o = (SomeClass) o;                 // necessary (narrowing cast)
+       o = (Comparable<String>) "string"; // unnecessary
+
+       // primitive conversions
+
+       l = (long) 2;   // unnecessary
+       l = (long) 2.0; // necessary (narrowing cast)
+       l = (byte) i;   // necessary (narrowing cast)
+
+       // boxing/unboxing casts (since java 5)
+
+       o = (Integer) 3;    // unnecessary (autoboxing would apply)
+       o = (long) 3;       // necessary (would be boxed to Long)
+       l = (int) boxedInt; // necessary (cannot cast Integer to long)
+
+       // casts that give a target type to a lambda/ method ref are necessary
+
+       o = (Function<Integer, String>) Integer::toString; // necessary (no target type)
+    }
+ }

+

Example 2

+

 import java.util.*;
+ class SomeClass {
+    static {
+        /* Casts involving access to collections were common before Java 5, because collections
+         * were not generic. This rule may hence be useful when converting from using a raw
+         * type like `List` to a parameterized type like `List<String>`.
+         */
+        List<String> stringList = Arrays.asList("a", "b");
+        String element = (String) stringList.get(0); // this cast is unnecessary
+    }
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + UnnecessaryConstructor + Unnecessary constructor + category/java/codestyle.xml/UnnecessaryConstructor + MAJOR + Title of issues: Avoid unnecessary constructors - the compiler will generate these for you +

This rule detects when a constructor is not necessary; i.e., when there is only one constructor and the +constructor is identical to the default constructor. The default constructor should has same access +modifier as the declaring class. In an enum type, the default constructor is implicitly private.

+

Example

+

 public class Foo {
+   public Foo() {}
+ }

+

Alternative rule: java:S1186

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + UnnecessaryConversionTemporary + Unnecessary conversion temporary + category/java/errorprone.xml/UnnecessaryConversionTemporary + MAJOR + Title of issues: Avoid unnecessary temporaries when converting primitives to Strings +

Avoid the use temporary objects when converting primitives to Strings. Use the static conversion methods +on the wrapper classes instead.

+

Example

+

 public String convert(int x) {
+     String foo = new Integer(x).toString(); // this wastes an object
+
+     return Integer.toString(x);             // preferred approach
+ }

+

Alternative rule: java:S1158

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + UnnecessaryFullyQualifiedName + Unnecessary fully qualified name + category/java/codestyle.xml/UnnecessaryFullyQualifiedName + MINOR + Title of issues: Unnecessary qualifier '{0}': '{1}' is already in scope{2} +

Import statements allow the use of non-fully qualified names. The use of a fully qualified name +which is covered by an import statement is redundant. Consider using the non-fully qualified name.

+

Example

+

 import java.util.List;
+
+ public class Foo {
+     private java.util.List list1;   // Unnecessary FQN
+     private List list2;             // More appropriate given import of 'java.util.List'
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + UnnecessaryImport + Unnecessary import + category/java/codestyle.xml/UnnecessaryImport + MINOR + Title of issues: Unnecessary import '{0}' +

Reports import statements that can be removed. They are either unused, + duplicated, or the members they import are already implicitly in scope, + because they're in java.lang, or the current package.

+

If some imports cannot be resolved, for instance because you run PMD with + an incomplete auxiliary classpath, some imports may be conservatively marked + as used even if they're not to avoid false positives.

+

Example

+

 import java.io.File;            // not used, can be removed
+             import java.util.Collections;   // used below
+             import java.util.*;             // so this one is not used
+
+             import java.lang.Object;        // imports from java.lang, unnecessary
+             import java.lang.Object;        // duplicate, unnecessary
+
+             public class Foo {
+                 static Object emptyList() {
+                     return Collections.emptyList();
+                 }
+             }

+

Full documentation

]]>
+ pmd + codestyle +
+ + UnnecessaryLocalBeforeReturn + Unnecessary local before return + category/java/codestyle.xml/UnnecessaryLocalBeforeReturn + MAJOR + Title of issues: Consider simply returning the value vs storing it in local variable '{0}' +

Avoid the creation of unnecessary local variables

+

Example

+

 public class Foo {
+    public int foo() {
+      int x = doSomething();
+      return x;  // instead, just 'return doSomething();'
+    }
+ }

+

Alternative rule: java:S1488

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + UnnecessaryModifier + Unnecessary modifier + category/java/codestyle.xml/UnnecessaryModifier + MAJOR + Title of issues: Unnecessary modifier{0} on {1} '{2}'{3} +

Fields in interfaces and annotations are automatically public static final, and methods are public abstract. +Classes, interfaces or annotations nested in an interface or annotation are automatically public static +(all nested interfaces and annotations are automatically static). +Nested enums are automatically static. +For historical reasons, modifiers which are implied by the context are accepted by the compiler, but are superfluous.

+

Example

+

 public @interface Annotation {
+     public abstract void bar();     // both abstract and public are ignored by the compiler
+     public static final int X = 0;  // public, static, and final all ignored
+     public static class Bar {}      // public, static ignored
+     public static interface Baz {}  // ditto
+ }
+ public interface Foo {
+     public abstract void bar();     // both abstract and public are ignored by the compiler
+     public static final int X = 0;  // public, static, and final all ignored
+     public static class Bar {}      // public, static ignored
+     public static interface Baz {}  // ditto
+ }
+ public class Bar {
+     public static interface Baz {}  // static ignored
+     public static enum FoorBar {    // static ignored
+         FOO;
+     }
+ }
+ public class FooClass {
+     static record BarRecord() {}     // static ignored
+ }
+ public interface FooInterface {
+     static record BarRecord() {}     // static ignored
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + UnnecessaryReturn + Unnecessary return + category/java/codestyle.xml/UnnecessaryReturn + MAJOR + Title of issues: Unnecessary return statement +

Avoid the use of unnecessary return statements. A return is unnecessary when no +instructions follow anyway.

+

Example

+

 public class Foo {
+     public void bar() {
+         int x = 42;
+         return;
+     }
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + UnnecessarySemicolon + Unnecessary semicolon + category/java/codestyle.xml/UnnecessarySemicolon + MAJOR + Title of issues: Unnecessary semicolon +

Reports unnecessary semicolons (so called "empty statements" and "empty declarations"). + These can be removed without changing the program. The Java grammar + allows them for historical reasons, but they should be avoided.

+

This rule will not report empty statements that are syntactically + required, for instance, because they are the body of a control statement.

+

This rule replaces EmptyStatementNotInLoop.

+

Example

+

 class Foo {
+     {
+         toString();; // one of these semicolons is unnecessary
+         if (true); // this semicolon is not unnecessary, but it could be an empty block instead (not reported)
+     }
+ }; // this semicolon is unnecessary

+

Full documentation

]]>
+ pmd + codestyle +
+ + UnnecessaryVarargsArrayCreation + Unnecessary varargs array creation + category/java/bestpractices.xml/UnnecessaryVarargsArrayCreation + MAJOR + Title of issues: Unnecessary explicit array creation for varargs method call +

Reports explicit array creation when a varargs is expected. + For instance: +

 Arrays.asList(new String[] { "foo", "bar", });
+ can be replaced by: +
 Arrays.asList("foo", "bar");

+

Example

+

 import java.util.Arrays;
+
+ class C {
+     static {
+         Arrays.asList(new String[]{"foo", "bar",});
+         // should be
+         Arrays.asList("foo", "bar");
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UnnecessaryWarningSuppression + Unnecessary warning suppression + category/java/bestpractices.xml/UnnecessaryWarningSuppression + MAJOR + Title of issues: Unused suppression {0}. +

This rule reports suppression comments and annotations that did not suppress any PMD violation. + Note that violations of this rule cannot be suppressed.

+

Please note:

+
  • The rule will report those suppressions comments/annotations that did not suppress a violation _during the current run_. That means you cannot run this rule separately from other rules, it must
  • The rule for now only reports annotations specific to PMD, like @SuppressWarnings("PMD"). For instance @SuppressWarnings("all") is never reported as we cannot know if another tool is producing a
+

Example

+

 public class Something {
+                 // Unless some rule triggered on the following line, this rule will report the comment:
+                 private void foo() {} // NOPMD
+             }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UnsynchronizedStaticFormatter + Unsynchronized static formatter + category/java/multithreading.xml/UnsynchronizedStaticFormatter + MAJOR + Title of issues: Static Formatter objects should be accessed in a synchronized manner +

Instances of java.text.Format are generally not synchronized. +Sun recommends using separate format instances for each thread. +If multiple threads must access a static formatter, the formatter must be +synchronized on block level.

+

Example

+

 public class Foo {
+     private static final SimpleDateFormat sdf = new SimpleDateFormat();
+     void bar() {
+         sdf.format(); // poor, no thread-safety
+     }
+     void foo() {
+         synchronized (sdf) { // preferred
+             sdf.format();
+         }
+     }
+ }

+

Full documentation

]]>
+ pmd + multithreading +
+ + UnusedAssignment + Unused assignment + category/java/bestpractices.xml/UnusedAssignment + MAJOR + Title of issues: The value assigned to this variable is never used or always overwritten +

Reports assignments to variables that are never used before the variable is overwritten, + or goes out of scope. Unused assignments are those for which + 1. The variable is never read after the assignment, or + 2. The assigned value is always overwritten by other assignments before the next read of + the variable.

+

The rule tracks assignements to fields of this, and static fields of the current class. + This may cause some false positives in timing-sensitive concurrent code, which the rule cannot detect.

+

The rule may be suppressed with the standard @SuppressWarnings("unused") tag.

+

The rule subsumes UnusedLocalVariable, and UnusedFormalParameter. + Those violations are filtered + out by default, in case you already have enabled those rules, but may be enabled with the property + reportUnusedVariables. Variables whose name starts with ignored or unused are filtered out, as + is standard practice for exceptions.

+

Limitations:

+
  • The rule currently cannot know which method calls throw exceptions, or which exceptions they throw. In the body of a try block, every method or constructor call is assumed to throw. This may cause false-negatives.
  • The rule cannot resolve assignments across constructors, when they're called with the special this(...) syntax. This may cause false-negatives.
+

Both of those limitations may be partly relaxed in PMD 7.

+

Examples

+

Example 1

+

 class A {
+                 // this field initializer is redundant,
+                 // it is always overwritten in the constructor
+                 int f = 1;
+
+                 A(int f) {
+                     this.f = f;
+                 }
+             }

+

Example 2

+

 class B {
+
+     int method(int i, int j) {
+         // this initializer is redundant,
+         // it is overwritten in all branches of the `if`
+         int k = 0;
+
+         // Both the assignments to k are unused, because k is
+         // not read after the if/else
+         // This may hide a bug: the programmer probably wanted to return k
+         if (i < j)
+             k = i;
+         else
+             k = j;
+
+         return j;
+     }
+
+ }

+

Example 3

+

 class C {
+
+     int method() {
+         int i = 0;
+
+         checkSomething(++i);
+         checkSomething(++i);
+         checkSomething(++i);
+         checkSomething(++i);
+
+         // That last increment is not reported unless
+         // the property `checkUnusedPrefixIncrement` is
+         // set to `true`
+         // Technically it could be written (i+1), but it
+         // is not very important
+     }
+
+ }

+

Example 4

+

 class C {
+
+     // variables that are truly unused (at most assigned to, but never accessed)
+     // are only reported if property `reportUnusedVariables` is true
+
+     void method(int param) { } // for example this method parameter
+
+     // even then, you can suppress the violation with an annotation:
+
+     void method(@SuppressWarning("unused") int param) { } // no violation, even if `reportUnusedVariables` is true
+
+     // For catch parameters, or for resources which don't need to be used explicitly,
+     // you can give a name that starts with "ignored" to ignore such warnings
+
+     {
+         try (Something ignored = Something.create()) {
+             // even if ignored is unused, it won't be flagged
+             // its purpose might be to side-effect in the create/close routines
+
+         } catch (Exception e) { // this is unused and will cause a warning if `reportUnusedVariables` is true
+             // you should choose a name that starts with "ignored"
+             return;
+         }
+     }
+
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UnusedFormalParameter + Unused formal parameter + category/java/bestpractices.xml/UnusedFormalParameter + MAJOR + Title of issues: Avoid unused {0} parameters such as '{1}'. +

Reports parameters of methods and constructors that are not referenced them in the method body. +Parameters whose name starts with ignored or unused are filtered out.

+

Removing unused formal parameters from public methods could cause a ripple effect through the code base. +Hence, by default, this rule only considers private methods. To include non-private methods, set the +checkAll property to true.

+

Example

+

 public class Foo {
+     private void bar(String howdy) {
+         // howdy is not used
+     }
+ }

+

Alternative rule: java:S1172

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + UnusedLocalVariable + Unused local variable + category/java/bestpractices.xml/UnusedLocalVariable + MAJOR + Title of issues: Avoid unused local variables such as '{0}'. +

Detects when a local variable is declared and/or assigned, but not used. +Variables whose name starts with ignored or unused are filtered out.

+

Example

+

 public class Foo {
+     public void doSomething() {
+         int i = 5; // Unused
+     }
+ }

+

Alternative rule: java:S1481

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + UnusedNullCheckInEquals + Unused null check in equals + category/java/errorprone.xml/UnusedNullCheckInEquals + MAJOR + Title of issues: Invoke equals() on the object you've already ensured is not null +

After checking an object reference for null, you should invoke equals() on that object rather than passing +it to another object's equals() method.

+

Example

+

 public class Test {
+
+     public String method1() { return "ok";}
+     public String method2() { return null;}
+
+     public void method(String a) {
+         String b;
+         // I don't know it method1() can be "null"
+         // but I know "a" is not null..
+         // I'd better write a.equals(method1())
+
+         if (a!=null && method1().equals(a)) { // will trigger the rule
+             //whatever
+         }
+
+         if (method1().equals(a) && a != null) { // won't trigger the rule
+             //whatever
+         }
+
+         if (a!=null && method1().equals(b)) { // won't trigger the rule
+             //whatever
+         }
+
+         if (a!=null && "LITERAL".equals(a)) { // won't trigger the rule
+             //whatever
+         }
+
+         if (a!=null && !a.equals("go")) { // won't trigger the rule
+             a=method2();
+             if (method1().equals(a)) {
+                 //whatever
+             }
+         }
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + UnusedPrivateField + Unused private field + category/java/bestpractices.xml/UnusedPrivateField + MAJOR + Title of issues: Avoid unused private fields such as '{0}'. +

Detects when a private field is declared and/or assigned a value, but not used.

+

Since PMD 6.50.0 private fields are ignored, if the fields are annotated with any annotation or the +enclosing class has any annotation. Annotations often enable a framework (such as dependency injection, mocking +or e.g. Lombok) which use the fields by reflection or other means. This usage can't be detected by static code analysis. +Previously these frameworks where explicitly allowed by listing their annotations in the property +"ignoredAnnotations", but that turned out to be prone of false positive for any not explicitly considered framework.

+

Example

+

 public class Something {
+     private static int FOO = 2; // Unused
+     private int i = 5; // Unused
+     private int j = 6;
+     public int addOne() {
+         return j++;
+     }
+ }

+

Alternative rule: java:S1068

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + UnusedPrivateMethod + Unused private method + category/java/bestpractices.xml/UnusedPrivateMethod + MAJOR + Title of issues: Avoid unused private methods such as '{0}'. +

Unused Private Method detects when a private method is declared but is unused.

+

Example

+

 public class Something {
+     private void foo() {} // unused
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UseArrayListInsteadOfVector + Use array list instead of vector + category/java/performance.xml/UseArrayListInsteadOfVector + MAJOR + Title of issues: Use ArrayList instead of Vector +

ArrayList is a much better Collection implementation than Vector if thread-safe operation is not required.

+

Example

+

 import java.util.*;
+ public class SimpleTest extends TestCase {
+     public void testX() {
+     Collection c1 = new Vector();
+     Collection c2 = new ArrayList();    // achieves the same with much better performance
+     }
+ }

+

Alternative rule: java:S1149

+

Full documentation

]]>
+ pmd + performance + has-sonar-alternative +
+ + UseArraysAsList + Use arrays as list + category/java/performance.xml/UseArraysAsList + MAJOR + Title of issues: Use asList instead of tight loops +

The java.util.Arrays class has a asList() method that should be used when you want to create a new List from +an array of objects. It is faster than executing a loop to copy all the elements of the array one by one.

+

Note that the result of Arrays.asList() is backed by the specified array, +changes in the returned list will result in the array to be modified. +For that reason, it is not possible to add new elements to the returned list of Arrays.asList() +(UnsupportedOperationException). +You must use new ArrayList<>(Arrays.asList(...)) if that is inconvenient for you (e.g. because of concurrent access).

+

Example

+

 public class Test {
+     public void foo(Integer[] ints) {
+         // could just use Arrays.asList(ints)
+         List<Integer> l = new ArrayList<>(100);
+         for (int i = 0; i < ints.length; i++) {
+             l.add(ints[i]);
+         }
+
+         List<Integer> anotherList = new ArrayList<>();
+         for (int i = 0; i < ints.length; i++) {
+             anotherList.add(ints[i].toString()); // won't trigger the rule
+         }
+     }
+ }

+

Full documentation

]]>
+ pmd + performance +
+ + UseCollectionIsEmpty + Use collection is empty + category/java/bestpractices.xml/UseCollectionIsEmpty + MAJOR + Title of issues: Substitute calls to size() == 0 (or size() != 0, size() > 0, size() < 1) with calls to isEmpty() +

The isEmpty() method on java.util.Collection is provided to determine if a collection has any elements. +Comparing the value of size() to 0 does not convey intent as well as the isEmpty() method.

+

Example

+

 public class Foo {
+     void good() {
+         List foo = getList();
+         if (foo.isEmpty()) {
+             // blah
+         }
+     }
+
+     void bad() {
+         List foo = getList();
+         if (foo.size() == 0) {
+             // blah
+         }
+     }
+ }

+

Alternative rule: java:S1155

+

Full documentation

]]>
+ pmd + bestpractices + has-sonar-alternative +
+ + UseConcurrentHashMap + Use concurrent hash map + category/java/multithreading.xml/UseConcurrentHashMap + MAJOR + Title of issues: If you run in Java5 or newer and have concurrent access, you should use the ConcurrentHashMap implementation +

Since Java5 brought a new implementation of the Map designed for multi-threaded access, you can +perform efficient map reads without blocking other threads.

+

Example

+

 public class ConcurrentApp {
+   public void getMyInstance() {
+     Map map1 = new HashMap();           // fine for single-threaded access
+     Map map2 = new ConcurrentHashMap(); // preferred for use with multiple threads
+
+     // the following case will be ignored by this rule
+     Map map3 = someModule.methodThatReturnMap(); // might be OK, if the returned map is already thread-safe
+   }
+ }

+

Full documentation

]]>
+ pmd + multithreading +
+ + UseCorrectExceptionLogging + Use correct exception logging + category/java/errorprone.xml/UseCorrectExceptionLogging + MAJOR + Title of issues: Use the correct logging statement for logging exceptions +

To make sure the full stacktrace is printed out, use the logging statement with two arguments: a String and a Throwable.

+

This rule only applies to Apache Commons Logging.

+

Example

+

 public class Main {
+     private static final Log _LOG = LogFactory.getLog( Main.class );
+     void bar() {
+         try {
+         } catch( Exception e ) {
+             _LOG.error( e ); //Wrong!
+         } catch( OtherException oe ) {
+             _LOG.error( oe.getMessage(), oe ); //Correct
+         }
+     }
+ }

+

Alternative rule: java:S1166

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + UseDiamondOperator + Use diamond operator + category/java/codestyle.xml/UseDiamondOperator + MAJOR + Title of issues: Explicit type arguments can be replaced by a diamond: <code>{0}</code> +

In some cases, explicit type arguments in a constructor call for a generic type +may be replaced by diamond type arguments (<>), and be inferred by the compiler. +This rule recommends that you use diamond type arguments anywhere possible, since +it avoids duplication of the type arguments, and makes the code more concise and readable.

+

This rule is useful when upgrading a codebase to Java 1.7, Java 1.8, or Java 9. +The diamond syntax was first introduced in Java 1.7. In Java 8, improvements in Java's +type inference made more type arguments redundant. In Java 9, type arguments inference +was made possible for anonymous class constructors.

+

Example

+

 import java.util.*;
+             class Foo {
+                 static {
+                     List<String> strings;
+                     strings = new ArrayList<String>(); // unnecessary duplication of type parameters
+                     strings = new ArrayList<>();       // using diamond type arguments is more concise
+
+                     strings = new ArrayList(); // accidental use of a raw type, you can use ArrayList<> instead
+
+                     strings = new ArrayList<>() {
+                         // for anonymous classes, this is possible since Java 9 only
+                     };
+                 }
+             }

+

Full documentation

]]>
+ pmd + codestyle +
+ + UseEnumCollections + Use enum collections + category/java/bestpractices.xml/UseEnumCollections + MAJOR + Title of issues: This collection could be an {0} +

Wherever possible, use EnumSet or EnumMap instead of HashSet and HashMap when the keys + are of an enum type. The specialized enum collections are more space- and time-efficient. + This rule reports constructor expressions for hash sets or maps whose key + type is an enum type.

+

Example

+

 import java.util.EnumMap;
+             import java.util.HashSet;
+
+             enum Example {
+                 A, B, C;
+
+                 public static Set<Example> newSet() {
+                     return new HashSet<>(); // Could be EnumSet.noneOf(Example.class)
+                 }
+
+                 public static <V> Map<Example, V> newMap() {
+                     return new HashMap<>(); // Could be new EnumMap<>(Example.class)
+                 }
+             }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UseEqualsToCompareStrings + Use equals to compare strings + category/java/errorprone.xml/UseEqualsToCompareStrings + MAJOR + Title of issues: Use equals() to compare strings instead of '==' or '!=' +

Using '==' or '!=' to compare strings is only reliable if the interned string (String#intern()) +is used on both sides.

+

Use the equals() method instead.

+

Example

+

 public boolean test(String s) {
+     if (s == "one") return true;        // unreliable
+     if ("two".equals(s)) return true;   // better
+     return false;
+ }

+

Alternative rule: java:S1698

+

Full documentation

]]>
+ pmd + errorprone + has-sonar-alternative +
+ + UseExplicitTypes + Use explicit types + category/java/codestyle.xml/UseExplicitTypes + MAJOR + Title of issues: Use Explicit Types +

Java 10 introduced the var keyword. This reduces the amount of code written because java can infer the type +from the initializer of the variable declaration.

+

This is essentially a trade-off: On the one hand, it can make code more readable by eliminating redundant +information. On the other hand, it can make code less readable by eliding useful information. There is no +blanket rule for when var should be used or shouldn't.

+

It may make sense to use var when the type is inherently clear upon reading the statement +(ie: assignment to either a literal value or a constructor call). Those use cases +can be enabled through properties.

+

Notice that lambda parameters are allowed, as they are already inferred by default (the var keyword +is completely optional).

+

See also Local Variable Type Inference Style Guidelines.

+

Full documentation

]]>
+ pmd + codestyle + + allowLiterals + + false + BOOLEAN + + + allowCtors + + false + BOOLEAN + +
+ + UseIOStreamsWithApacheCommonsFileItem + Use IOStreams with apache commons file item + category/java/performance.xml/UseIOStreamsWithApacheCommonsFileItem + MAJOR + Title of issues: Avoid memory intensive FileItem.get() or FileItem.getString() +

Problem: Use of FileItem.get() +and FileItem.getString() +could exhaust memory since they load the entire file into memory.

+

Solution: Use FileItem.getInputStream() +and buffering.

+

Example

+

 import org.apache.commons.fileupload.FileItem;
+
+ public class FileStuff {
+    private String bad(FileItem fileItem) {
+         return fileItem.getString();
+    }
+
+    private InputStream good(FileItem fileItem) {
+         return fileItem.getInputStream();
+    }
+ }

+

Full documentation

]]>
+ pmd + performance +
+ + UseIndexOfChar + Use index of char + category/java/performance.xml/UseIndexOfChar + MAJOR + Title of issues: String.indexOf(char) is faster than String.indexOf(String). +

Use String.indexOf(char) when checking for the index of a single character; it executes faster.

+

Example

+

 String s = "hello world";
+ // avoid this
+ if (s.indexOf("d") {}
+ // instead do this
+ if (s.indexOf('d') {}

+

Full documentation

]]>
+ pmd + performance +
+ + UseLocaleWithCaseConversions + Use locale with case conversions + category/java/errorprone.xml/UseLocaleWithCaseConversions + MAJOR + Title of issues: When doing a String.toLowerCase()/toUpperCase() call, use a Locale +

When doing String::toLowerCase()/toUpperCase() conversions, use an explicit locale argument to specify the case +transformation rules.

+

Using String::toLowerCase() without arguments implicitly uses Locale::getDefault(). +The problem is that the default locale depends on the current JVM setup (and usually on the system in which +it is running). Using the system default may be exactly what you want (e.g. if you are manipulating strings +you got through standard input), but it may as well not be the case (e.g. if you are getting the string over +the network or a file, and the encoding is well-defined and independent of the environment). In the latter case, +using the default locale makes the case transformation brittle, as it may yield unexpected results on a machine +whose locale has other case translation rules. For example, in Turkish, the uppercase form of i is İ (U+0130, +not ASCII) and not I (U+0049) as in English.

+

The rule is intended to force developers to think about locales when dealing with strings. By taking a +conscious decision about the choice of locale at the time of writing, you reduce the risk of surprising +behaviour down the line, and communicate your intent to future readers.

+

Example

+

 // violation - implicitly system-dependent conversion
+ if (x.toLowerCase().equals("list")) {}
+
+ // The above will not match "LIST" on a system with a Turkish locale.
+ // It could be replaced with
+ if (x.toLowerCase(Locale.US).equals("list")) { }
+ // or simply
+ if (x.equalsIgnoreCase("list")) { }
+
+ // ok - system independent conversion
+ String z = a.toLowerCase(Locale.ROOT);
+
+ // ok - explicit system-dependent conversion
+ String z2 = a.toLowerCase(Locale.getDefault());

+

Full documentation

]]>
+ pmd + errorprone +
+ + UseNotifyAllInsteadOfNotify + Use notify all instead of notify + category/java/multithreading.xml/UseNotifyAllInsteadOfNotify + MAJOR + Title of issues: Call Thread.notifyAll() rather than Thread.notify() +

Thread.notify() awakens a thread monitoring the object. If more than one thread is monitoring, then only +one is chosen. The thread chosen is arbitrary; thus it's usually safer to call notifyAll() instead.

+

Example

+

 void bar() {
+     x.notify();
+     // If many threads are monitoring x, only one (and you won't know which) will be notified.
+     // use instead:
+     x.notifyAll();
+   }

+

Alternative rule: java:S2446

+

Full documentation

]]>
+ pmd + multithreading + has-sonar-alternative +
+ + UseObjectForClearerAPI + Use object for clearer API + category/java/design.xml/UseObjectForClearerAPI + MAJOR + Title of issues: Rather than using a lot of String arguments, consider using a container object for those values. +

When you write a public method, you should be thinking in terms of an API. If your method is public, it means other class +will use it, therefore, you want (or need) to offer a comprehensive and evolutive API. If you pass a lot of information +as a simple series of Strings, you may think of using an Object to represent all those information. You'll get a simpler +API (such as doWork(Workload workload), rather than a tedious series of Strings) and more importantly, if you need at some +point to pass extra data, you'll be able to do so by simply modifying or extending Workload without any modification to +your API.

+

Example

+

 public class MyClass {
+     public void connect(String username,
+         String pssd,
+         String databaseName,
+         String databaseAdress)
+         // Instead of those parameters object
+         // would ensure a cleaner API and permit
+         // to add extra data transparently (no code change):
+         // void connect(UserData data);
+     {
+
+     }
+ }

+

Alternative rule: java:S107

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + UseProperClassLoader + Use proper class loader + category/java/errorprone.xml/UseProperClassLoader + MAJOR + Title of issues: In J2EE, getClassLoader() might not work as expected. Use Thread.currentThread().getContextClassLoader() instead. +

In J2EE, the getClassLoader() method might not work as expected. Use +Thread.currentThread().getContextClassLoader() instead.

+

Example

+

 public class Foo {
+     ClassLoader cl = Bar.class.getClassLoader();
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + UseShortArrayInitializer + Use short array initializer + category/java/codestyle.xml/UseShortArrayInitializer + MAJOR + Title of issues: Array initialization can be written shorter +

When declaring and initializing array fields or variables, it is not necessary to explicitly create a new array +using new. Instead one can simply define the initial content of the array as a expression in curly braces.

+

E.g. int[] x = new int[] { 1, 2, 3 }; can be written as int[] x = { 1, 2, 3 };.

+

Example

+

 Foo[] x = new Foo[] { ... }; // Overly verbose
+ Foo[] x = { ... }; //Equivalent to above line

+

Full documentation

]]>
+ pmd + codestyle +
+ + UseStandardCharsets + Use standard charsets + category/java/bestpractices.xml/UseStandardCharsets + MAJOR + Title of issues: Please use StandardCharsets constants +

Starting with Java 7, StandardCharsets provides constants for common Charset objects, such as UTF-8. +Using the constants is less error prone, and can provide a small performance advantage compared to Charset.forName(...) +since no scan across the internal Charset caches is needed.

+

Example

+

 public class UseStandardCharsets {
+     public void run() {
+
+         // looking up the charset dynamically
+         try (OutputStreamWriter osw = new OutputStreamWriter(out, Charset.forName("UTF-8"))) {
+             osw.write("test");
+         }
+
+         // best to use StandardCharsets
+         try (OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
+             osw.write("test");
+         }
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UseStringBufferForStringAppends + Use string buffer for string appends + category/java/performance.xml/UseStringBufferForStringAppends + MAJOR + Title of issues: Prefer StringBuilder (non-synchronized) or StringBuffer (synchronized) over += for concatenating strings +

The use of the '+=' operator for appending strings causes the JVM to create and use an internal StringBuffer. +If a non-trivial number of these concatenations are being used then the explicit use of a StringBuilder or +threadsafe StringBuffer is recommended to avoid this.

+

Example

+

 public class Foo {
+     String inefficientConcatenation() {
+         String result = "";
+         for (int i = 0; i < 10; i++) {
+             // warning: this concatenation will create one new StringBuilder per iteration
+             result += getStringFromSomeWhere(i);
+         }
+         return result;
+     }
+
+     String efficientConcatenation() {
+         // better would be to use one StringBuilder for the entire loop
+         StringBuilder result = new StringBuilder();
+         for (int i = 0; i < 10; i++) {
+             result.append(getStringFromSomeWhere(i));
+         }
+         return result.toString();
+     }
+ }

+

Full documentation

]]>
+ pmd + performance +
+ + UseStringBufferLength + Use string buffer length + category/java/performance.xml/UseStringBufferLength + MAJOR + Title of issues: This is an inefficient use of CharSequence.toString; call CharSequence.length instead. +

Use StringBuffer.length() to determine StringBuffer length rather than using StringBuffer.toString().equals("") +or StringBuffer.toString().length() == ...

+

Example

+

 StringBuffer sb = new StringBuffer();
+
+ if (sb.toString().equals("")) {}        // inefficient
+
+ if (sb.length() == 0) {}                // preferred

+

Full documentation

]]>
+ pmd + performance +
+ + UseTryWithResources + Use try with resources + category/java/bestpractices.xml/UseTryWithResources + MAJOR + Title of issues: Consider using a try-with-resources statement instead of explicitly closing the resource +

Java 7 introduced the try-with-resources statement. This statement ensures that each resource is closed at the end +of the statement. It avoids the need of explicitly closing the resources in a finally block. Additionally exceptions +are better handled: If an exception occurred both in the try block and finally block, then the exception from +the try block was suppressed. With the try-with-resources statement, the exception thrown from the try-block is +preserved.

+

Example

+

 public class TryWithResources {
+     public void run() {
+         InputStream in = null;
+         try {
+             in = openInputStream();
+             int i = in.read();
+         } catch (IOException e) {
+             e.printStackTrace();
+         } finally {
+             try {
+                 if (in != null) in.close();
+             } catch (IOException ignored) {
+                 // ignored
+             }
+         }
+
+         // better use try-with-resources
+         try (InputStream in2 = openInputStream()) {
+             int i = in2.read();
+         }
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UseUnderscoresInNumericLiterals + Use underscores in numeric literals + category/java/codestyle.xml/UseUnderscoresInNumericLiterals + MAJOR + Title of issues: Number {0} should separate every third digit with an underscore +

Since Java 1.7, numeric literals can use underscores to separate digits. This rule enforces that + numeric literals above a certain length use these underscores to increase readability.

+

The rule only supports decimal (base 10) literals for now. The acceptable length under which literals + are not required to have underscores is configurable via a property. Even under that length, underscores + that are misplaced (not making groups of 3 digits) are reported.

+

Example

+

 public class Foo {
+     private int num = 1000000; // should be 1_000_000
+ }

+

Full documentation

]]>
+ pmd + codestyle + + acceptableDecimalLength + + 4 + INTEGER + +
+ + UseUtilityClass + Use utility class + category/java/design.xml/UseUtilityClass + MAJOR + Title of issues: All methods are static. Consider using a utility class instead. Alternatively, you could add a private constructor or make the class abstract to silence this warning. +

For classes that only have static methods, consider making them utility classes. +Note that this doesn't apply to abstract classes, since their subclasses may +well include non-static methods. Also, if you want this class to be a utility class, +remember to add a private constructor to prevent instantiation. +(Note, that this use was known before PMD 5.1.0 as UseSingleton).

+

Example

+

 public class MaybeAUtility {
+   public static void foo() {}
+   public static void bar() {}
+ }

+

Alternative rule: java:S1118

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + UseVarargs + Use varargs + category/java/bestpractices.xml/UseVarargs + MINOR + Title of issues: Consider using varargs for methods or constructors which take an array the last parameter. +

Java 5 introduced the varargs parameter declaration for methods and constructors. This syntactic +sugar provides flexibility for users of these methods and constructors, allowing them to avoid +having to deal with the creation of an array.

+

Byte arrays in any method and String arrays in public static void main(String[]) methods are ignored.

+

Example

+

 public class Foo {
+     public void foo(String s, Object[] args) {
+         // Do something here...
+     }
+
+     public void bar(String s, Object... args) {
+         // Ahh, varargs tastes much better...
+     }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + UselessOperationOnImmutable + Useless operation on immutable + category/java/errorprone.xml/UselessOperationOnImmutable + MAJOR + Title of issues: The result of an operation on an immutable object is ignored +

An operation on an immutable object will not change the object itself since the result of the operation is a new object. +Therefore, ignoring the result of such an operation is likely a mistake. The operation can probably be removed.

+

This rule recognizes the types String, BigDecimal, BigInteger or any type from java.time.* as immutable.

+

Example

+

 import java.math.*;
+
+ class Test {
+     void method1() {
+         BigDecimal bd=new BigDecimal(10);
+         bd.add(new BigDecimal(5));      // this will trigger the rule
+     }
+     void method2() {
+         BigDecimal bd=new BigDecimal(10);
+         bd = bd.add(new BigDecimal(5)); // this won't trigger the rule
+     }
+ }

+

Full documentation

]]>
+ pmd + errorprone +
+ + UselessOverridingMethod + Useless overriding method + category/java/design.xml/UselessOverridingMethod + MAJOR + Title of issues: Overriding method merely calls super +

The overriding method merely calls the same method defined in a superclass.

+

Example

+

 public void foo(String bar) {
+     super.foo(bar);      // why bother overriding?
+ }
+
+ public String foo() {
+     return super.foo();  // why bother overriding?
+ }
+
+ @Id
+ public Long getId() {
+     return super.getId();  // OK if 'ignoreAnnotations' is false, which is the default behavior
+ }

+

Alternative rule: java:S1185

+

Full documentation

]]>
+ pmd + design + has-sonar-alternative +
+ + UselessParentheses + Useless parentheses + category/java/codestyle.xml/UselessParentheses + MINOR + Title of issues: Useless parentheses. +

Parenthesized expressions are used to override the default operator precedence + rules. Parentheses whose removal would not change the relative nesting of operators + are unnecessary, because they don't change the semantics of the enclosing expression.

+

Some parentheses that strictly speaking are unnecessary, may still be considered useful for readability. This rule allows to ignore violations on two kinds of unnecessary parentheses:

+
  • "Clarifying" parentheses, which separate operators of difference precedence. While unnecessary, they make precedence rules explicit, which may be useful for rarely used
+
  • "Balancing" parentheses, which are unnecessary but visually balance out another pair of parentheses around an equality operator. For example, those two expressions are equivalent:
     (a == null) != (b == null)
    +                 a == null != (b == null)
    The parentheses on the right are required, and the parentheses on the left are just more visually pleasing. Unset the property ignoreBalancing to report them.
+

Example

+

 public class Foo {
+     {
+         int n = 0;
+         n = (n);         // here
+         n = (n * 2) * 3; // and here
+         n = n * (2 * 3); // and here
+     }
+ }

+

Alternative rule: java:S1110

+

Full documentation

]]>
+ pmd + codestyle + has-sonar-alternative +
+ + UselessQualifiedThis + Useless qualified this + category/java/codestyle.xml/UselessQualifiedThis + MAJOR + Title of issues: Useless qualified this usage in the same class. +

Reports qualified this usages in the same class.

+

Example

+

 public class Foo {
+     final Foo otherFoo = Foo.this;  // use "this" directly
+
+     public void doSomething() {
+          final Foo anotherFoo = Foo.this;  // use "this" directly
+     }
+
+     private ActionListener returnListener() {
+         return new ActionListener() {
+             @Override
+             public void actionPerformed(ActionEvent e) {
+                 doSomethingWithQualifiedThis(Foo.this);  // This is fine
+             }
+         };
+     }
+
+     private class Foo3 {
+         final Foo myFoo = Foo.this;  // This is fine
+     }
+
+     private class Foo2 {
+         final Foo2 myFoo2 = Foo2.this;  // Use "this" direclty
+     }
+ }

+

Full documentation

]]>
+ pmd + codestyle +
+ + UselessStringValueOf + Useless string value of + category/java/performance.xml/UselessStringValueOf + MAJOR + Title of issues: No need to call String.valueOf to append to a string. +

No need to call String.valueOf to append to a string; just use the valueOf() argument directly.

+

Example

+

 public String convert(int i) {
+     String s;
+     s = "a" + String.valueOf(i);    // not required
+     s = "a" + i;                    // preferred approach
+     return s;
+ }

+

Alternative rule: java:S1153

+

Full documentation

]]>
+ pmd + performance + has-sonar-alternative +
+ + WhileLoopWithLiteralBoolean + While loop with literal boolean + category/java/bestpractices.xml/WhileLoopWithLiteralBoolean + MAJOR + Title of issues: The loop can be simplified. +

do {} while (true); requires reading the end of the statement before it is +apparent that it loops forever, whereas while (true) {} is easier to understand.

+

do {} while (false); is redundant, and if an inner variable scope is required, +a block {} is sufficient.

+

while (false) {} will never execute the block and can be removed in its entirety.

+

Example

+

 public class Example {
+   {
+     while (true) { } // allowed
+     while (false) { } // disallowed
+     do { } while (true); // disallowed
+     do { } while (false); // disallowed
+     do { } while (false | false); // disallowed
+     do { } while (false || false); // disallowed
+   }
+ }

+

Full documentation

]]>
+ pmd + bestpractices +
+ + XPathRule + PMD XPath Template Rule + MAJOR + net.sourceforge.pmd.lang.rule.xpath.XPathRule + MULTIPLE + + + The PMD 7 compatible XPath expression for Java. + + + + The message for issues created by this rule. + + PMD provides a very handy method for creating new rules by writing an XPath query. When the XPath query finds a match, a violation is created.

+

Let's take a simple example: assume we have a Factory class that must be always declared final. +We'd like to report a violation each time a declaration of Factory is not declared final. Consider the following class:

+

+import io.factories.Factory;
+
+public class a {
+  Factory f1;
+
+  void myMethod() {
+    Factory f2;
+    int a;
+  }
+}
+
+

The following expression does the magic we need:

+

+//(FieldDeclaration|LocalVariableDeclaration)[
+      not (pmd-java:modifiers() = 'final')
+   ]/ClassType[pmd-java:typeIs('io.factories.Factory')]
+
+

See the XPath rule tutorial for more information.

+

Tip: use the PMD Designer application to create the XPath expressions.

+]]>
+ pmd + xpath +
+
diff --git a/scripts/pmd7_rules_xml_generator.groovy b/scripts/pmd7_rules_xml_generator.groovy new file mode 100644 index 00000000..e68dfd0c --- /dev/null +++ b/scripts/pmd7_rules_xml_generator.groovy @@ -0,0 +1,722 @@ +import groovy.xml.XmlSlurper +import groovy.xml.MarkupBuilder +import groovy.json.JsonBuilder +import groovy.json.JsonSlurper + +import java.time.ZoneOffset +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter +import java.util.zip.ZipFile +import groovy.grape.Grape +import groovy.transform.Field + +// Resolve versions from pom.xml to have a single source of truth +@Field def pomFile = new File('pom.xml') +if (!pomFile.exists()) { + pomFile = new File('../pom.xml') // allow running from scripts/ directory +} +if (!pomFile.exists()) { + throw new RuntimeException('pom.xml not found to determine versions') +} + +@Field def pom = new XmlSlurper().parse(pomFile) +@Field def pmdVersion = (pom.properties.'pmd.version'.text() ?: '').trim() +if (!pmdVersion) { + throw new RuntimeException('pmd.version not found in pom.xml') +} + +// Dynamically grab required dependencies matching pom-defined versions +Grape.grab([group: 'net.sourceforge.pmd', module: 'pmd-java', version: pmdVersion]) +Grape.grab([group: 'net.sourceforge.pmd', module: 'pmd-kotlin', version: pmdVersion]) +// Note: sonar-pmd-lib is provided on the classpath by the groovy-maven-plugin configuration; no Grape needed. + +import org.sonar.plugins.pmd.rule.JavaRulePropertyExtractor +import org.sonar.plugins.pmd.rule.MarkdownToHtmlConverter +import org.sonar.plugins.pmd.rule.util.PmdSeverityMapper +import org.sonar.plugins.pmd.rule.util.RuleParamFormatter + +// Simple logging utilities +@Field boolean DEBUG_LOG = Boolean.parseBoolean(System.getProperty('pmd7.rules.gen.debug', 'false')) + +def logInfo(Object msg) { + println String.valueOf(msg) +} + +def logDebug(Object msg) { + if (DEBUG_LOG) { + println "DEBUG: " + String.valueOf(msg) + } +} + +def logWarn(Object msg) { + System.err.println "WARN: " + String.valueOf(msg) +} + +def logError(Object msg) { + System.err.println "ERROR: " + String.valueOf(msg) +} + +// Configure PMD version for MarkdownToHtmlConverter to avoid lib dependency on PMD +MarkdownToHtmlConverter.setPmdVersion(pmdVersion) + +// Configuration +@Field def pmdJavaJarPath = new File("${System.getProperty("user.home")}/.m2/repository/net/sourceforge/pmd/pmd-java/${pmdVersion}/pmd-java-${pmdVersion}.jar") +@Field def pmdKotlinJarPath = new File("${System.getProperty("user.home")}/.m2/repository/net/sourceforge/pmd/pmd-kotlin/${pmdVersion}/pmd-kotlin-${pmdVersion}.jar") +def javaCategoriesPropertiesPath = "category/java/categories.properties" +def kotlinCategoriesPropertiesPath = "category/kotlin/categories.properties" +// Define language-specific rule alternatives paths +@Field String javaRuleAlternativesPath = "scripts/rule-alternatives-java.json" +@Field String kotlinRuleAlternativesPath = "scripts/rule-alternatives-kotlin.json" + +// Extract Java rule properties from the jar file +logInfo("extracting Java rule properties from ${pmdJavaJarPath}") +@Field def javaRulePropertyExtractor = new JavaRulePropertyExtractor() +@Field def javaRuleProperties = javaRulePropertyExtractor.extractProperties(pmdJavaJarPath) +logInfo("found properties for ${javaRuleProperties.size()} Java rule classes") + +// Extract Kotlin rule properties from the jar file +logInfo("extracting Kotlin rule properties from ${pmdKotlinJarPath}") +@Field def kotlinRulePropertyExtractor = new JavaRulePropertyExtractor() +@Field def kotlinRuleProperties = kotlinRulePropertyExtractor.extractProperties(pmdKotlinJarPath) +logInfo("found properties for ${kotlinRuleProperties.size()} Kotlin rule classes") + +// Function to read rule alternatives from a JSON file +def readRuleAlternatives(String filePath) { + def alternatives = [:] + try { + def alternativesFile = new File(filePath) + if (alternativesFile.exists()) { + def jsonSlurper = new JsonSlurper() + def alternativesData = jsonSlurper.parse(alternativesFile) + alternatives = alternativesData.ruleAlternatives + logInfo("loaded ${alternatives.size()} rule alternatives from ${filePath}") + } else { + logWarn("rule alternatives file not found at ${filePath}") + } + } catch (Exception e) { + logError("reading rule alternatives: ${e.message}") + } + return alternatives +} + +// Read Java rule alternatives +@Field Map javaRuleAlternatives = readRuleAlternatives(javaRuleAlternativesPath) + +// Read Kotlin rule alternatives (for future use) +@Field Map kotlinRuleAlternatives = readRuleAlternatives(kotlinRuleAlternativesPath) + +// If we're in test mode, make the MarkdownToHtmlConverter available but don't run the main code +if (binding.hasVariable('TEST_MODE') && binding.getVariable('TEST_MODE')) { + // Make MarkdownToHtmlConverter available to the caller + binding.setVariable('MarkdownToHtmlConverter', MarkdownToHtmlConverter) + return // Skip the rest of the script +} + +// Get output directory from binding variable (set by Maven) or use a default directory +// The 'outputDir' variable is passed from Maven's groovy-maven-plugin configuration +@Field def defaultOutputDir = new File("sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd").exists() ? + "sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd" : "." +@Field def outputDirPath = binding.hasVariable('outputDir') ? outputDir : defaultOutputDir +@Field def javaOutputFileName = "rules-java.xml" +@Field def kotlinOutputFileName = "rules-kotlin.xml" +@Field def javaOutputFilePath = new File(outputDirPath, javaOutputFileName) +@Field def kotlinOutputFilePath = new File(outputDirPath, kotlinOutputFileName) + +logInfo("PMD ${pmdVersion} Rules XML Generator") +logInfo("=" * 50) +logInfo("Java output file: ${javaOutputFilePath}") +logInfo("Kotlin output file: ${kotlinOutputFilePath}") + +// Function to read rules from a PMD JAR +def readRulesFromJar = { jarFile, categoriesPath -> + if (!jarFile.exists()) { + logError("PMD JAR not found at: ${jarFile}") + return [] + } + + def rules = [] + def categoryFiles = [] + + try { + def zipFile = new ZipFile(jarFile) + + // Read categories.properties to get rule files + def categoriesEntry = zipFile.getEntry(categoriesPath) + if (categoriesEntry) { + def categoriesProps = new Properties() + categoriesProps.load(zipFile.getInputStream(categoriesEntry)) + categoryFiles = categoriesProps.getProperty("rulesets.filenames", "").split(",").collect { it.trim() } + logInfo("found ${categoryFiles.size()} category files in PMD JAR: ${jarFile}") + } else { + logWarn("${categoriesPath} not found in PMD JAR: ${jarFile}") + } + + // Process each category file + categoryFiles.each { categoryFile -> + def entry = zipFile.getEntry(categoryFile) + if (!entry) { + logWarn(" - category file not found: ${categoryFile}") + return + } + + try { + def categoryXml = new XmlSlurper().parse(zipFile.getInputStream(entry)) + def categoryName = categoryFile.tokenize('/').last() - '.xml' + + // Process each rule in the category + categoryXml.rule.each { rule -> + def ruleName = rule.@name.toString() + if (!ruleName) return + + rules << [ + name: ruleName, + category: categoryName, + categoryFile: categoryFile, + class: rule.@class.toString(), + deprecated: rule.@deprecated.toString() == "true", + ref: rule.@ref.toString(), + since: rule.@since.toString(), + externalInfoUrl: rule.@externalInfoUrl.toString(), + message: rule.@message.toString() ?: ruleName, + description: rule.description.text(), + priority: rule.priority.text() ?: "3", + examples: rule.example.collect { it.text() }, + properties: rule.properties.property.collect { prop -> [ + name: prop.@name.toString(), + description: prop.@description.toString(), + type: prop.@type.toString(), + value: prop.@value.toString(), + min: prop.@min.toString(), + max: prop.@max.toString() + ]} + ] + } + logInfo(" - processed ${categoryFile}: found ${categoryXml.rule.size()} rules") + } catch (Exception e) { + logError(" - processing ${categoryFile}: ${e.message}") + } + } + + zipFile.close() + return rules + } catch (Exception e) { + logError("reading PMD JAR: ${e.message}") + return [] + } +} + +// Read Java rules +logInfo("reading Java rules from ${pmdJavaJarPath}") +def javaRules = readRulesFromJar(pmdJavaJarPath, javaCategoriesPropertiesPath) +logInfo("found ${javaRules.size()} total Java rules\n") + +// Read Kotlin rules +logInfo("reading Kotlin rules from ${pmdKotlinJarPath}") +def kotlinRules = readRulesFromJar(pmdKotlinJarPath, kotlinCategoriesPropertiesPath) +logInfo("found ${kotlinRules.size()} total Kotlin rules\n") + +// Helper function to escape XML content for CDATA +String escapeForCdata(String text) { + if (!text) return "" + // Split any occurrence of the CDATA closing sequence so the CDATA remains valid + return text.replaceAll(/\]\]>/, "]]]]>") +} + +// Helper function to format description with examples using MdToHtmlConverter +def formatDescription(ruleData, String language) { + def description = ruleData.description ?: "" + def examples = ruleData.examples ?: [] + def externalInfoUrl = ruleData.externalInfoUrl ?: "" + def message = ruleData.message ?: "" + def ruleName = ruleData.name + + // Build markdown content + def markdownContent = new StringBuilder() + + // Title and base description + appendTitleSection(markdownContent, message) + markdownContent.append(description ?: "") + + // Examples + appendExamplesSection(markdownContent, examples, language) + + // Convert to HTML and enrich + def htmlContent = MarkdownToHtmlConverter.convertToHtml(markdownContent.toString()) + htmlContent = enrichWithAlternatives(htmlContent, ruleName, language) + htmlContent = appendExternalInfoLink(htmlContent, externalInfoUrl) + + return htmlContent +} + +// Function to generate XML file (refactored to use helper methods for readability) +def generateXmlFile = { outputFile, rules, language -> + def rulesWithoutDescription = 0 + def renamedRules = 0 + def rulesWithDeprecatedAndRef = [] + + try { + // Generate XML file + outputFile.withWriter('UTF-8') { writer -> + def xml = new MarkupBuilder(writer) + xml.setDoubleQuotes(true) + + // Write XML declaration manually + writer.println('') + // Add generation banner (ignored by parser) for traceability and to reflect regeneration + def ts = ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_LOCAL_DATE) + writer.println("") + + xml.rules { + rules.sort { it.name }.each { ruleData -> + // Skip rules with deprecated=true and ref attribute + if (ruleData.deprecated && ruleData.ref) { + renamedRules++ + rulesWithDeprecatedAndRef << ruleData + return // Skip this rule + } + + rule { + key(ruleData.name) + def readableName = MarkdownToHtmlConverter.camelCaseToReadable(ruleData.name) + name(readableName) + internalKey("${ruleData.categoryFile}/${ruleData.name}") + severity(PmdSeverityMapper.priorityToSeverity(ruleData.priority, ruleData.category)) + + // Determine whether the rule message contains variable placeholders like {0}, {1}, ... + def hasVariablePlaceholders = (ruleData.message ?: "").find(/\{\d+\}/) != null + + // Description + boolean usedFallback = writeDescription(xml, ruleData, language) + if (usedFallback) { + rulesWithoutDescription++ + } + + // Status if deprecated + if (ruleData.deprecated) { + status("DEPRECATED") + } + + // Tags + tag("pmd") + tag(ruleData.category) + addAlternativeTagIfAny(xml, language, ruleData.name) + + // Parameters + def existingParamKeys = new HashSet(ruleData.properties.findAll { it.name }.collect { it.name }) + addRuleParams(xml, ruleData, language, existingParamKeys) + addSuppressionParamIfNeeded(xml, hasVariablePlaceholders, existingParamKeys) + } + } + } + } + + // Print summary information + def activeRules = rules.count { !it.deprecated } + def deprecatedRules = rules.count { it.deprecated } + def categoryStats = rules.groupBy { it.category } + + logInfo(""" +successfully generated ${outputFile.name} +total ${language} rules: ${rules.size()} +active ${language} rules: ${activeRules} +deprecated ${language} rules: ${deprecatedRules} +${renamedRules > 0 ? "renamed ${language} rules (deprecated with ref): ${renamedRules}" : ""} +${rulesWithoutDescription > 0 ? "${language} rules with generated fallback descriptions: ${rulesWithoutDescription}" : ""} +using camelCase transformation for all rule names + +${language} rules by category:""") + + categoryStats.sort { it.key }.each { category, categoryRules -> + def activeCount = categoryRules.count { !it.deprecated } + def deprecatedCount = categoryRules.count { it.deprecated } + logInfo(" - ${category}: ${categoryRules.size()} total (${activeCount} active, ${deprecatedCount} deprecated)") + } + + logInfo("tags that will be applied for ${language} rules:") + logInfo(" - pmd: ${rules.size()} rules") + categoryStats.sort { it.key }.each { category, categoryRules -> + logInfo(" - ${category}: ${categoryRules.size()} rules") + } + + // Verify no empty descriptions + reportEmptyDescriptions(outputFile, language) + + // Print warnings for renamed rules with deprecated=true and ref attribute and write JSON + if (renamedRules > 0) { + handleRenamedRules(language, renamedRules, rulesWithDeprecatedAndRef) + } + + return true + } catch (Exception e) { + logError("generating ${language} XML file: ${e.message}") + e.printStackTrace() + return false + } +} + +// Generate Java rules XML file +logInfo("") +logInfo("Generating Java rules XML file...") +logInfo("=" * 30) +def javaSuccess = generateXmlFile(javaOutputFilePath, javaRules, "Java") + +// Generate Kotlin rules XML file +logInfo("") +logInfo("Generating Kotlin rules XML file...") +logInfo("=" * 30) +def kotlinSuccess = generateXmlFile(kotlinOutputFilePath, kotlinRules, "Kotlin") + +// Add XPathRule as a special case to the Java rules XML file +addXPathRuleToJavaFile() + +logInfo("") +if (javaSuccess && kotlinSuccess) { + logInfo("XML generation completed successfully for both Java and Kotlin rules!") +} else { + logInfo("XML generation completed with errors. Please check the logs above.") +} + + +// === Helper methods extracted for readability === + +def appendTitleSection(StringBuilder sb, String message) { + if (message && !message.trim().isEmpty()) { + def processedMessage = + wrapPlaceholdersOutsideBackticks(message) + .replaceAll(/''/, "'") + sb.append("## Title of issues: ").append(processedMessage).append("\n\n") + } +} + +def wrapPlaceholdersOutsideBackticks(String text) { + def parts = text.split('`', -1) // -1 to keep empty trailing parts + def result = new StringBuilder() + + for (int i = 0; i < parts.length; i++) { + if (i % 2 == 0) { + // Outside backticks - process placeholders + def processed = parts[i].replaceAll(/\{(\d+)\}/, '`{$1}`') + result.append(processed) + } else { + // Inside backticks - don't process + result.append(parts[i]) + } + + // Add back the backtick separator (except for the last part) + if (i < parts.length - 1) { + result.append('`') + } + } + + return result.toString() +} + + + +def appendExamplesSection(StringBuilder sb, List examples, String language) { + if (examples && !examples.isEmpty()) { + sb.append(examples.size() > 1 ? "\n\n## Examples\n\n" : "\n\n## Example\n\n") + examples.eachWithIndex { example, index -> + if (examples.size() > 1) { + sb.append("### Example ").append(index + 1).append("\n\n") + } + sb.append("```").append(language.toLowerCase()).append("\n") + sb.append(example) + sb.append("\n```\n\n") + } + } +} + +def enrichWithAlternatives(String htmlContent, String ruleName, String language) { + def ruleAlternativesForLanguage = language == "Java" ? javaRuleAlternatives : kotlinRuleAlternatives + if (ruleAlternativesForLanguage && ruleAlternativesForLanguage.containsKey(ruleName)) { + def alternatives = ruleAlternativesForLanguage[ruleName] + if (alternatives && !alternatives.isEmpty()) { + def alternativesHtml = new StringBuilder("

Alternative " + (alternatives.size() == 1 ? "rule" : "rules") + ": ") + alternatives.eachWithIndex { alt, index -> + if (index > 0) alternativesHtml.append(", ") + def internalLink = "./coding_rules?rule_key=${URLEncoder.encode(alt.key, 'UTF-8')}&open=${URLEncoder.encode(alt.key, 'UTF-8')}" + alternativesHtml.append("${alt.key}") + } + alternativesHtml.append("

") + htmlContent += "\n" + alternativesHtml.toString() + } + } + return htmlContent +} + +def appendExternalInfoLink(String htmlContent, String externalInfoUrl) { + if (externalInfoUrl) { + def linkText = "Full documentation" + htmlContent += "\n

${linkText}

" + } + return htmlContent +} + +def writeDescription(xml, Map ruleData, String language) { + def descContent = formatDescription(ruleData, language) + boolean usedFallback = false + if (!descContent || descContent.trim().isEmpty()) { + descContent = MarkdownToHtmlConverter.convertToHtml("THIS SHOULD NOT HAPPEN") + usedFallback = true + } + xml.description { + xml.mkp.yieldUnescaped("") + } + return usedFallback +} + +def addAlternativeTagIfAny(xml, String language, String ruleName) { + def ruleAlternativesForLanguage = language == "Java" ? javaRuleAlternatives : kotlinRuleAlternatives + if (ruleAlternativesForLanguage && ruleAlternativesForLanguage.containsKey(ruleName)) { + xml.tag("has-sonar-alternative") + } +} + +def addParam(xml, String keyName, String descText, String defaultVal, String typeToken) { + xml.param { + key(keyName) + description { + xml.mkp.yieldUnescaped("") + } + // Always emit an explicit empty default when the default is missing + def effectiveDefault = defaultVal + if (effectiveDefault == null) { + effectiveDefault = "" + } + if (effectiveDefault != null) defaultValue(effectiveDefault) + if (typeToken) type(typeToken) + } +} + +def addXmlDefinedRuleParams(xml, Map ruleData, Set existingParamKeys) { + ruleData.properties.findAll { prop -> + prop.name && prop.description + }.each { prop -> + String typeToken = null + if (prop.type) { + def t = prop.type.toUpperCase() + if (t.startsWith("LIST[") || t.contains("REGEX") || t == "REGULAR_EXPRESSION") { + typeToken = "STRING" + } else { + typeToken = t + } + } + addParam(xml, prop.name, prop.description, prop.value, typeToken) + existingParamKeys.add(prop.name) + } +} + +// --- Helpers for addClassDefinedRuleParams --- +def getRulePropertiesForClass(Map rulePropertiesMap, String ruleClass) { + rulePropertiesMap.get(ruleClass) +} + +def getUnwrappedType(propInfo) { + def propType = propInfo.type + try { + return propInfo.getWrappedType() + } catch (MissingMethodException ignore) { + return propType + } +} + +def shouldLogProperty(String propName) { + !(propName == "violationSuppressRegex" || propName == "violationSuppressXPath") +} + +def handleSuppressionSpecialCases(xml, propInfo) { + if (propInfo.name == "violationSuppressXPath") { + // Skip adding this parameter as it's too complex/error-prone for users + return true + } + if (propInfo.name == "violationSuppressRegex") { + // Do not emit this parameter here. It will be added later by addSuppressionParamIfNeeded + // only when the rule message contains variable placeholders. This keeps + // keep the suppression regex description centralized and ensure the param + // is only present when appropriate. + return true + } + return false +} + + +def getAcceptedValues(propInfo) { + try { + return (propInfo.getAcceptedValues() ?: []) as List + } catch (MissingMethodException ignore) { + return [] + } catch (MissingPropertyException ignore) { + return [] + } +} + +def isMultiple(propInfo) { + try { + return propInfo.isMultiple() + } catch (MissingMethodException ignore) { + return false + } +} + +def computeBaseDescription(propInfo, List accepted, boolean multiple) { + RuleParamFormatter.buildDescription( + null, + propInfo.description, + accepted, + multiple + ) +} + +def determineTypeToken(List accepted, boolean multiple, String unwrappedType) { + if (accepted && !accepted.isEmpty()) { + return RuleParamFormatter.buildSelectTypeToken(accepted, multiple) + } + if (unwrappedType in ["Integer", "Long", "Short", "Byte", "BigInteger"]) { + return "INTEGER" + } + if (unwrappedType in ["Double", "Float", "BigDecimal"]) { + return "FLOAT" + } + if (unwrappedType?.equalsIgnoreCase("Boolean")) { + return "BOOLEAN" + } + if (unwrappedType?.equalsIgnoreCase("Pattern")) { + return "STRING" + } + return "STRING" +} + +def computeDefaultValue(propInfo) { + def defVal = (propInfo.defaultValuesAsString) ?: "" + if (defVal == "[]") { + logWarn("wrong $defVal for $propInfo") + } + return defVal +} + +def addParamAndTrack(xml, String name, String desc, String defVal, String typeToken, Set existingParamKeys) { + addParam(xml, name, desc, defVal, typeToken) + existingParamKeys.add(name) +} + +def processStandardProperty(xml, propInfo, Set existingParamKeys) { + def accepted = getAcceptedValues(propInfo) + def multiple = isMultiple(propInfo) + def baseDesc = computeBaseDescription(propInfo, accepted, multiple) + def unwrappedType = getUnwrappedType(propInfo) + def typeToken = determineTypeToken(accepted, multiple, unwrappedType) + def defVal = computeDefaultValue(propInfo) + addParamAndTrack(xml, propInfo.name, baseDesc, defVal, typeToken, existingParamKeys) +} + +// Main orchestrator + +def addClassDefinedRuleParams(xml, Map ruleData, String language, Set existingParamKeys) { + def ruleClass = ruleData.class + if (!ruleClass) return + def rulePropertiesMap = language == "Java" ? javaRuleProperties : kotlinRuleProperties + def ruleProperties = getRulePropertiesForClass(rulePropertiesMap, ruleClass) + if (ruleProperties.size()) { + logDebug(" - found ${ruleProperties.size()} properties for rule ${ruleData.name} (${ruleClass})") + ruleProperties.each { propInfo -> + def propType = propInfo.type + def unwrappedType = getUnwrappedType(propInfo) + if (shouldLogProperty(propInfo.name)) { + logDebug("### PROP: ${propInfo.name} TYPE: ${propType} (wrapped: ${unwrappedType})") + } + if (handleSuppressionSpecialCases(xml, propInfo)) { + return + } + processStandardProperty(xml, propInfo, existingParamKeys) + } + } +} + +def addRuleParams(xml, Map ruleData, String language, Set existingParamKeys) { + if (ruleData.class.equals("net.sourceforge.pmd.lang.rule.xpath.XPathRule")) { + addXmlDefinedRuleParams(xml, ruleData, existingParamKeys) + } else { + addClassDefinedRuleParams(xml, ruleData, language, existingParamKeys) + } +} + +def addSuppressionParamIfNeeded(xml, boolean hasVariablePlaceholders, Set existingParamKeys) { + if (hasVariablePlaceholders && !existingParamKeys.contains("violationSuppressRegex")) { + addParam(xml, + "violationSuppressRegex", + "Suppress violations with messages matching a regular expression. WARNING: make sure the regular expression is correct, otherwise analysis will fail with unclear XML validation errors.", + "", + "STRING" + ) + } +} + +def reportEmptyDescriptions(File outputFile, String language) { + def outputXml = new XmlSlurper().parse(outputFile) + def emptyDescriptions = outputXml.rule.findAll { + !it.description.text() || it.description.text().trim().isEmpty() + } + if (emptyDescriptions.size() > 0) { + logWarn("found ${emptyDescriptions.size()} ${language} rules with empty descriptions:") + emptyDescriptions.each { rule -> + logInfo(" - ${rule.key.text()}") + } + } else { + logInfo("all ${language} rules have descriptions") + } +} + +def handleRenamedRules(String language, int renamedRules, List rulesWithDeprecatedAndRef) { + logWarn("renamed ${renamedRules} ${language} rules with deprecated=true and ref attribute:") + rulesWithDeprecatedAndRef.each { rule -> + logInfo(" - ${rule.name} (ref: ${rule.ref})") + } + def renamedRulesData = [ + language: language, + count: renamedRules, + rules: rulesWithDeprecatedAndRef.collect { rule -> [name: rule.name, ref: rule.ref, category: rule.category] } + ] + def jsonBuilder = new JsonBuilder(renamedRulesData) + def renamedRulesFile = new File("scripts/renamed-${language.toLowerCase()}-rules.json") + renamedRulesFile.write(jsonBuilder.toPrettyString()) + logInfo("generated renamed rules information in ${renamedRulesFile.absolutePath}") +} + +def addXPathRuleToJavaFile() { + addXPathRuleToJavaFile(javaOutputFilePath as File) +} + +def addXPathRuleToJavaFile(File outFile) { + logInfo("") + logInfo("adding XPathRule to Java rules XML file...") + logInfo("=" * 30) + try { + def xmlFile = outFile + def xmlContent = xmlFile.text + if (xmlContent.contains("XPathRule")) { + logInfo("XPathRule already exists in the Java rules XML file.") + } else { + def closingTagIndex = xmlContent.lastIndexOf("
") + if (closingTagIndex != -1) { + // Load XPathRule XML snippet from file; fail if missing + def snippetPath = (binding?.hasVariable('xpathRuleSnippetPath') && binding.getVariable('xpathRuleSnippetPath')) ? binding.getVariable('xpathRuleSnippetPath').toString() : "scripts/xpath-rule-snippet.xml" + def snippetFile = new File(snippetPath) + if (!snippetFile.exists()) { + throw new FileNotFoundException("XPathRule snippet file not found at ${snippetFile.absolutePath}. Provide the file via 'xpathRuleSnippetPath' binding or create scripts/xpath-rule-snippet.xml") + } + logInfo("loading XPathRule snippet from ${snippetFile.absolutePath}") + String xpathRuleXml = snippetFile.getText('UTF-8') + def newXmlContent = xmlContent.substring(0, closingTagIndex) + xpathRuleXml + xmlContent.substring(closingTagIndex) + xmlFile.text = newXmlContent + logInfo("successfully added XPathRule to Java rules XML file.") + } else { + logError("could not find closing tag in Java rules XML file.") + } + } + } catch (Exception e) { + logError("adding XPathRule to Java rules XML file: ${e.message}") + throw e + } +} + diff --git a/scripts/renamed-java-rules.json b/scripts/renamed-java-rules.json new file mode 100644 index 00000000..dc323692 --- /dev/null +++ b/scripts/renamed-java-rules.json @@ -0,0 +1,56 @@ +{ + "language": "Java", + "count": 10, + "rules": [ + { + "name": "DefaultLabelNotLastInSwitchStmt", + "ref": "DefaultLabelNotLastInSwitch", + "category": "bestpractices" + }, + { + "name": "JUnit4TestShouldUseAfterAnnotation", + "ref": "UnitTestShouldUseAfterAnnotation", + "category": "bestpractices" + }, + { + "name": "JUnit4TestShouldUseBeforeAnnotation", + "ref": "UnitTestShouldUseBeforeAnnotation", + "category": "bestpractices" + }, + { + "name": "JUnit4TestShouldUseTestAnnotation", + "ref": "UnitTestShouldUseTestAnnotation", + "category": "bestpractices" + }, + { + "name": "JUnitAssertionsShouldIncludeMessage", + "ref": "UnitTestAssertionsShouldIncludeMessage", + "category": "bestpractices" + }, + { + "name": "JUnitTestContainsTooManyAsserts", + "ref": "UnitTestContainsTooManyAsserts", + "category": "bestpractices" + }, + { + "name": "JUnitTestsShouldIncludeAssert", + "ref": "UnitTestShouldIncludeAssert", + "category": "bestpractices" + }, + { + "name": "NonCaseLabelInSwitchStatement", + "ref": "NonCaseLabelInSwitch", + "category": "errorprone" + }, + { + "name": "SwitchStmtsShouldHaveDefault", + "ref": "NonExhaustiveSwitch", + "category": "bestpractices" + }, + { + "name": "TooFewBranchesForASwitchStatement", + "ref": "TooFewBranchesForSwitch", + "category": "performance" + } + ] +} \ No newline at end of file diff --git a/scripts/rule-alternatives-java.json b/scripts/rule-alternatives-java.json new file mode 100644 index 00000000..4535d6b8 --- /dev/null +++ b/scripts/rule-alternatives-java.json @@ -0,0 +1,754 @@ +{ + "ruleAlternatives": { + "AbstractClassWithoutAbstractMethod": [ + { + "key": "java:S1694", + "link": "https://rules.sonarsource.com/java/RSPEC-1694" + } + ], + "AbstractClassWithoutAnyMethod": [ + { + "key": "java:S1694", + "link": "https://rules.sonarsource.com/java/RSPEC-1694" + } + ], + "ArrayIsStoredDirectly": [ + { + "key": "java:S2384", + "link": "https://rules.sonarsource.com/java/RSPEC-2384" + } + ], + "AssignmentInOperand": [ + { + "key": "java:S1121", + "link": "https://rules.sonarsource.com/java/RSPEC-1121" + } + ], + "AtLeastOneConstructor": [ + { + "key": "java:S1118", + "link": "https://rules.sonarsource.com/java/RSPEC-1118" + }, + { + "key": "java:S1258", + "link": "https://rules.sonarsource.com/java/RSPEC-1258" + } + ], + "AvoidAssertAsIdentifier": [ + { + "key": "java:S1190", + "link": "https://rules.sonarsource.com/java/RSPEC-1190" + } + ], + "AvoidCatchingGenericException": [ + { + "key": "java:S2221", + "link": "https://rules.sonarsource.com/java/RSPEC-2221" + } + ], + "AvoidCatchingNPE": [ + { + "key": "java:S1696", + "link": "https://rules.sonarsource.com/java/RSPEC-1696" + } + ], + "AvoidCatchingThrowable": [ + { + "key": "java:S1181", + "link": "https://rules.sonarsource.com/java/RSPEC-1181" + } + ], + "AvoidDecimalLiteralsInBigDecimalConstructor": [ + { + "key": "java:S2111", + "link": "https://rules.sonarsource.com/java/RSPEC-2111" + } + ], + "AvoidDeeplyNestedIfStmts": [ + { + "key": "java:S134", + "link": "https://rules.sonarsource.com/java/RSPEC-134" + } + ], + "AvoidDollarSigns": [ + { + "key": "java:S114", + "link": "https://rules.sonarsource.com/java/RSPEC-114" + }, + { + "key": "java:S115", + "link": "https://rules.sonarsource.com/java/RSPEC-115" + }, + { + "key": "java:S116", + "link": "https://rules.sonarsource.com/java/RSPEC-116" + }, + { + "key": "java:S117", + "link": "https://rules.sonarsource.com/java/RSPEC-117" + } + ], + "AvoidDuplicateLiterals": [ + { + "key": "java:S1192", + "link": "https://rules.sonarsource.com/java/RSPEC-1192" + } + ], + "AvoidEnumAsIdentifier": [ + { + "key": "java:S1190", + "link": "https://rules.sonarsource.com/java/RSPEC-1190" + } + ], + "AvoidFieldNameMatchingMethodName": [ + { + "key": "java:S1845", + "link": "https://rules.sonarsource.com/java/RSPEC-1845" + } + ], + "AvoidFieldNameMatchingTypeName": [ + { + "key": "java:S1700", + "link": "https://rules.sonarsource.com/java/RSPEC-1700" + } + ], + "AvoidInstanceofChecksInCatchClause": [ + { + "key": "java:S1193", + "link": "https://rules.sonarsource.com/java/RSPEC-1193" + } + ], + "AvoidLiteralsInIfCondition": [ + { + "key": "java:S109", + "link": "https://rules.sonarsource.com/java/RSPEC-109" + } + ], + "AvoidLosingExceptionInformation": [ + { + "key": "java:S1166", + "link": "https://rules.sonarsource.com/java/RSPEC-1166" + } + ], + "AvoidMultipleUnaryOperators": [ + { + "key": "java:S881", + "link": "https://rules.sonarsource.com/java/RSPEC-881" + } + ], + "AvoidPrintStackTrace": [ + { + "key": "java:S1148", + "link": "https://rules.sonarsource.com/java/RSPEC-1148" + } + ], + "AvoidProtectedFieldInFinalClass": [ + { + "key": "java:S2156", + "link": "https://rules.sonarsource.com/java/RSPEC-2156" + } + ], + "AvoidProtectedMethodInFinalClassNotExtending": [ + { + "key": "java:S2156", + "link": "https://rules.sonarsource.com/java/RSPEC-2156" + } + ], + "AvoidReassigningParameters": [ + { + "key": "java:S1226", + "link": "https://rules.sonarsource.com/java/RSPEC-1226" + } + ], + "AvoidRethrowingException": [ + { + "key": "java:S1166", + "link": "https://rules.sonarsource.com/java/RSPEC-1166" + } + ], + "AvoidStringBufferField": [ + { + "key": "java:S1149", + "link": "https://rules.sonarsource.com/java/RSPEC-1149" + } + ], + "AvoidThrowingNewInstanceOfSameException": [ + { + "key": "java:S1166", + "link": "https://rules.sonarsource.com/java/RSPEC-1166" + } + ], + "AvoidThrowingNullPointerException": [ + { + "key": "java:S1695", + "link": "https://rules.sonarsource.com/java/RSPEC-1695" + } + ], + "AvoidThrowingRawExceptionTypes": [ + { + "key": "java:S112", + "link": "https://rules.sonarsource.com/java/RSPEC-112" + } + ], + "AvoidUsingHardCodedIP": [ + { + "key": "java:S1313", + "link": "https://rules.sonarsource.com/java/RSPEC-1313" + } + ], + "AvoidUsingOctalValues": [ + { + "key": "java:S1314", + "link": "https://rules.sonarsource.com/java/RSPEC-1314" + } + ], + "BrokenNullCheck": [ + { + "key": "java:S1697", + "link": "https://rules.sonarsource.com/java/RSPEC-1697" + } + ], + "CheckSkipResult": [ + { + "key": "java:S2674", + "link": "https://rules.sonarsource.com/java/RSPEC-2674" + } + ], + "ClassNamingConventions": [ + { + "key": "java:S101", + "link": "https://rules.sonarsource.com/java/RSPEC-101" + }, + { + "key": "java:S114", + "link": "https://rules.sonarsource.com/java/RSPEC-114" + } + ], + "ClassWithOnlyPrivateConstructorsShouldBeFinal": [ + { + "key": "java:S2974", + "link": "https://rules.sonarsource.com/java/RSPEC-2974" + } + ], + "CloseResource": [ + { + "key": "java:S2095", + "link": "https://rules.sonarsource.com/java/RSPEC-2095" + } + ], + "CollapsibleIfStatements": [ + { + "key": "java:S1066", + "link": "https://rules.sonarsource.com/java/RSPEC-1066" + } + ], + "CompareObjectsWithEquals": [ + { + "key": "java:S1698", + "link": "https://rules.sonarsource.com/java/RSPEC-1698" + } + ], + "ConstructorCallsOverridableMethod": [ + { + "key": "java:S1699", + "link": "https://rules.sonarsource.com/java/RSPEC-1699" + } + ], + "CouplingBetweenObjects": [ + { + "key": "java:S1200", + "link": "https://rules.sonarsource.com/java/RSPEC-1200" + } + ], + "CyclomaticComplexity": [ + { + "key": "java:S1541", + "link": "https://rules.sonarsource.com/java/RSPEC-1541" + } + ], + "DoNotCallGarbageCollectionExplicitly": [ + { + "key": "java:S1215", + "link": "https://rules.sonarsource.com/java/RSPEC-1215" + } + ], + "DoNotExtendJavaLangError": [ + { + "key": "java:S1194", + "link": "https://rules.sonarsource.com/java/RSPEC-1194" + } + ], + "DoNotThrowExceptionInFinally": [ + { + "key": "java:S1163", + "link": "https://rules.sonarsource.com/java/RSPEC-1163" + } + ], + "DontCallThreadRun": [ + { + "key": "java:S1217", + "link": "https://rules.sonarsource.com/java/RSPEC-1217" + } + ], + "DontImportSun": [ + { + "key": "java:S1191", + "link": "https://rules.sonarsource.com/java/RSPEC-1191" + } + ], + "EmptyCatchBlock": [ + { + "key": "java:S108", + "link": "https://rules.sonarsource.com/java/RSPEC-108" + } + ], + "EmptyFinalizer": [ + { + "key": "java:S1186", + "link": "https://rules.sonarsource.com/java/RSPEC-1186" + } + ], + "EqualsNull": [ + { + "key": "java:S2159", + "link": "https://rules.sonarsource.com/java/RSPEC-2159" + } + ], + "ExceptionAsFlowControl": [ + { + "key": "java:S1141", + "link": "https://rules.sonarsource.com/java/RSPEC-1141" + } + ], + "ExcessiveImports": [ + { + "key": "java:S1200", + "link": "https://rules.sonarsource.com/java/RSPEC-1200" + } + ], + "ExcessiveParameterList": [ + { + "key": "java:S107", + "link": "https://rules.sonarsource.com/java/RSPEC-107" + } + ], + "ExcessivePublicCount": [ + { + "key": "java:S1448", + "link": "https://rules.sonarsource.com/java/RSPEC-1448" + } + ], + "ExtendsObject": [ + { + "key": "java:S1939", + "link": "https://rules.sonarsource.com/java/RSPEC-1939" + } + ], + "FieldDeclarationsShouldBeAtStartOfClass": [ + { + "key": "java:S1213", + "link": "https://rules.sonarsource.com/java/RSPEC-1213" + } + ], + "FinalFieldCouldBeStatic": [ + { + "key": "java:S1170", + "link": "https://rules.sonarsource.com/java/RSPEC-1170" + } + ], + "FinalizeOnlyCallsSuperFinalize": [ + { + "key": "java:S1185", + "link": "https://rules.sonarsource.com/java/RSPEC-1185" + } + ], + "FinalizeOverloaded": [ + { + "key": "java:S1175", + "link": "https://rules.sonarsource.com/java/RSPEC-1175" + } + ], + "FinalizeShouldBeProtected": [ + { + "key": "java:S1174", + "link": "https://rules.sonarsource.com/java/RSPEC-1174" + } + ], + "ForLoopShouldBeWhileLoop": [ + { + "key": "java:S1264", + "link": "https://rules.sonarsource.com/java/RSPEC-1264" + } + ], + "GenericsNaming": [ + { + "key": "java:S119", + "link": "https://rules.sonarsource.com/java/RSPEC-119" + } + ], + "IdempotentOperations": [ + { + "key": "java:S1656", + "link": "https://rules.sonarsource.com/java/RSPEC-1656" + } + ], + "InstantiationToGetClass": [ + { + "key": "java:S2133", + "link": "https://rules.sonarsource.com/java/RSPEC-2133" + } + ], + "JumbledIncrementer": [ + { + "key": "java:S1994", + "link": "https://rules.sonarsource.com/java/RSPEC-1994" + } + ], + "LogicInversion": [ + { + "key": "java:S1940", + "link": "https://rules.sonarsource.com/java/RSPEC-1940" + } + ], + "LongVariable": [ + { + "key": "java:S117", + "link": "https://rules.sonarsource.com/java/RSPEC-117" + } + ], + "MethodArgumentCouldBeFinal": [ + { + "key": "java:S1226", + "link": "https://rules.sonarsource.com/java/RSPEC-1226" + } + ], + "MethodNamingConventions": [ + { + "key": "java:S100", + "link": "https://rules.sonarsource.com/java/RSPEC-100" + } + ], + "MethodReturnsInternalArray": [ + { + "key": "java:S2384", + "link": "https://rules.sonarsource.com/java/RSPEC-2384" + } + ], + "MethodWithSameNameAsEnclosingClass": [ + { + "key": "java:S1223", + "link": "https://rules.sonarsource.com/java/RSPEC-1223" + } + ], + "MisplacedNullCheck": [ + { + "key": "java:S1697", + "link": "https://rules.sonarsource.com/java/RSPEC-1697" + }, + { + "key": "java:S2259", + "link": "https://rules.sonarsource.com/java/RSPEC-2259" + } + ], + "MissingSerialVersionUID": [ + { + "key": "java:S2057", + "link": "https://rules.sonarsource.com/java/RSPEC-2057" + } + ], + "MoreThanOneLogger": [ + { + "key": "java:S1312", + "link": "https://rules.sonarsource.com/java/RSPEC-1312" + } + ], + "NoPackage": [ + { + "key": "java:S1220", + "link": "https://rules.sonarsource.com/java/RSPEC-1220" + } + ], + "NonStaticInitializer": [ + { + "key": "java:S1171", + "link": "https://rules.sonarsource.com/java/RSPEC-1171" + } + ], + "NonThreadSafeSingleton": [ + { + "key": "java:S2444", + "link": "https://rules.sonarsource.com/java/RSPEC-2444" + } + ], + "OneDeclarationPerLine": [ + { + "key": "java:S122", + "link": "https://rules.sonarsource.com/java/RSPEC-122" + } + ], + "OnlyOneReturn": [ + { + "key": "java:S1142", + "link": "https://rules.sonarsource.com/java/RSPEC-1142" + } + ], + "OverrideBothEqualsAndHashcode": [ + { + "key": "java:S1206", + "link": "https://rules.sonarsource.com/java/RSPEC-1206" + } + ], + "PackageCase": [ + { + "key": "java:S120", + "link": "https://rules.sonarsource.com/java/RSPEC-120" + } + ], + "PrematureDeclaration": [ + { + "key": "java:S1941", + "link": "https://rules.sonarsource.com/java/RSPEC-1941" + } + ], + "PreserveStackTrace": [ + { + "key": "java:S1166", + "link": "https://rules.sonarsource.com/java/RSPEC-1166" + } + ], + "ProperCloneImplementation": [ + { + "key": "java:S1182", + "link": "https://rules.sonarsource.com/java/RSPEC-1182" + } + ], + "ProperLogger": [ + { + "key": "java:S1312", + "link": "https://rules.sonarsource.com/java/RSPEC-1312" + } + ], + "ReplaceEnumerationWithIterator": [ + { + "key": "java:S1150", + "link": "https://rules.sonarsource.com/java/RSPEC-1150" + } + ], + "ReplaceHashtableWithMap": [ + { + "key": "java:S1149", + "link": "https://rules.sonarsource.com/java/RSPEC-1149" + } + ], + "ReplaceVectorWithList": [ + { + "key": "java:S1149", + "link": "https://rules.sonarsource.com/java/RSPEC-1149" + } + ], + "ReturnFromFinallyBlock": [ + { + "key": "java:S1143", + "link": "https://rules.sonarsource.com/java/RSPEC-1143" + } + ], + "ShortClassName": [ + { + "key": "java:S101", + "link": "https://rules.sonarsource.com/java/RSPEC-101" + } + ], + "ShortMethodName": [ + { + "key": "java:S100", + "link": "https://rules.sonarsource.com/java/RSPEC-100" + } + ], + "ShortVariable": [ + { + "key": "java:S117", + "link": "https://rules.sonarsource.com/java/RSPEC-117" + } + ], + "SignatureDeclareThrowsException": [ + { + "key": "java:S112", + "link": "https://rules.sonarsource.com/java/RSPEC-112" + } + ], + "SimplifyBooleanExpressions": [ + { + "key": "java:S1125", + "link": "https://rules.sonarsource.com/java/RSPEC-1125" + } + ], + "SimplifyBooleanReturns": [ + { + "key": "java:S1126", + "link": "https://rules.sonarsource.com/java/RSPEC-1126" + } + ], + "StringBufferInstantiationWithChar": [ + { + "key": "java:S1317", + "link": "https://rules.sonarsource.com/java/RSPEC-1317" + } + ], + "StringToString": [ + { + "key": "java:S1858", + "link": "https://rules.sonarsource.com/java/RSPEC-1858" + } + ], + "SuspiciousEqualsMethodName": [ + { + "key": "java:S1201", + "link": "https://rules.sonarsource.com/java/RSPEC-1201" + } + ], + "SuspiciousHashcodeMethodName": [ + { + "key": "java:S1221", + "link": "https://rules.sonarsource.com/java/RSPEC-1221" + } + ], + "SwitchDensity": [ + { + "key": "java:S1151", + "link": "https://rules.sonarsource.com/java/RSPEC-1151" + } + ], + "SystemPrintln": [ + { + "key": "java:S106", + "link": "https://rules.sonarsource.com/java/RSPEC-106" + } + ], + "TooManyMethods": [ + { + "key": "java:S1448", + "link": "https://rules.sonarsource.com/java/RSPEC-1448" + } + ], + "UncommentedEmptyConstructor": [ + { + "key": "java:S2094", + "link": "https://rules.sonarsource.com/java/RSPEC-2094" + } + ], + "UncommentedEmptyMethodBody": [ + { + "key": "java:S1186", + "link": "https://rules.sonarsource.com/java/RSPEC-1186" + } + ], + "UnconditionalIfStatement": [ + { + "key": "java:S2583", + "link": "https://rules.sonarsource.com/java/RSPEC-2583" + } + ], + "UnnecessaryCaseChange": [ + { + "key": "java:S1157", + "link": "https://rules.sonarsource.com/java/RSPEC-1157" + } + ], + "UnnecessaryConstructor": [ + { + "key": "java:S1186", + "link": "https://rules.sonarsource.com/java/RSPEC-1186" + } + ], + "UnnecessaryConversionTemporary": [ + { + "key": "java:S1158", + "link": "https://rules.sonarsource.com/java/RSPEC-1158" + } + ], + "UnnecessaryLocalBeforeReturn": [ + { + "key": "java:S1488", + "link": "https://rules.sonarsource.com/java/RSPEC-1488" + } + ], + "UnusedFormalParameter": [ + { + "key": "java:S1172", + "link": "https://rules.sonarsource.com/java/RSPEC-1172" + } + ], + "UnusedLocalVariable": [ + { + "key": "java:S1481", + "link": "https://rules.sonarsource.com/java/RSPEC-1481" + } + ], + "UnusedPrivateField": [ + { + "key": "java:S1068", + "link": "https://rules.sonarsource.com/java/RSPEC-1068" + } + ], + "UseArrayListInsteadOfVector": [ + { + "key": "java:S1149", + "link": "https://rules.sonarsource.com/java/RSPEC-1149" + } + ], + "UseCollectionIsEmpty": [ + { + "key": "java:S1155", + "link": "https://rules.sonarsource.com/java/RSPEC-1155" + } + ], + "UseCorrectExceptionLogging": [ + { + "key": "java:S1166", + "link": "https://rules.sonarsource.com/java/RSPEC-1166" + } + ], + "UseEqualsToCompareStrings": [ + { + "key": "java:S1698", + "link": "https://rules.sonarsource.com/java/RSPEC-1698" + } + ], + "UseNotifyAllInsteadOfNotify": [ + { + "key": "java:S2446", + "link": "https://rules.sonarsource.com/java/RSPEC-2446" + } + ], + "UseObjectForClearerAPI": [ + { + "key": "java:S107", + "link": "https://rules.sonarsource.com/java/RSPEC-107" + } + ], + "UseUtilityClass": [ + { + "key": "java:S1118", + "link": "https://rules.sonarsource.com/java/RSPEC-1118" + } + ], + "UselessOverridingMethod": [ + { + "key": "java:S1185", + "link": "https://rules.sonarsource.com/java/RSPEC-1185" + } + ], + "UselessParentheses": [ + { + "key": "java:S1110", + "link": "https://rules.sonarsource.com/java/RSPEC-1110" + } + ], + "UselessStringValueOf": [ + { + "key": "java:S1153", + "link": "https://rules.sonarsource.com/java/RSPEC-1153" + } + ] + } +} diff --git a/scripts/xpath-rule-snippet.xml b/scripts/xpath-rule-snippet.xml new file mode 100644 index 00000000..bf7924bc --- /dev/null +++ b/scripts/xpath-rule-snippet.xml @@ -0,0 +1,41 @@ + + XPathRule + PMD XPath Template Rule + MAJOR + net.sourceforge.pmd.lang.rule.xpath.XPathRule + MULTIPLE + + + The PMD 7 compatible XPath expression for Java. + + + + The message for issues created by this rule. + + PMD provides a powerful method for creating custom rules by writing an XPath query. When the XPath query finds a match, a violation is created.

+

Let's take a simple example: assume we have a Factory class that must be always declared final. +We'd like to report a violation each time a declaration of Factory is not declared final. Consider the following class:

+

+import io.factories.Factory;
+
+public class Foo {
+  Factory f1;
+
+  void myMethod() {
+    Factory f2;
+    int a;
+  }
+}
+
+

The following expression does the magic we need:

+

+//(FieldDeclaration|LocalVariableDeclaration)[
+      not (pmd-java:modifiers() = 'final')
+   ]/ClassType[pmd-java:typeIs('io.factories.Factory')]
+
+

See the XPath rule tutorial for more information.

+

Tip: use the PMD Designer application to create the XPath expressions.

+]]>
+ pmd + xpath +
diff --git a/sonar-pmd-lib/pom.xml b/sonar-pmd-lib/pom.xml new file mode 100644 index 00000000..5f6b7a88 --- /dev/null +++ b/sonar-pmd-lib/pom.xml @@ -0,0 +1,83 @@ + + + + + + 4.0.0 + + org.sonarsource.pmd + sonar-pmd + ${revision} + + + sonar-pmd-lib + SonarQube PMD Library + + + 17 + 17 + UTF-8 + + + + + org.sonarsource.api.plugin + sonar-plugin-api + provided + + + commons-io + commons-io + ${commons-io.version} + + + org.apache.commons + commons-lang3 + compile + + + + org.jetbrains + annotations + 26.0.2-1 + compile + + + net.sourceforge.pmd + pmd-java + + + org.slf4j + slf4j-api + 2.0.17 + + + org.slf4j + slf4j-simple + 2.0.17 + test + + + + diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoader.java b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoader.java similarity index 83% rename from sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoader.java rename to sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoader.java index bbd052fc..88ea530b 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoader.java +++ b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoader.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,17 +17,17 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - package org.sonar.plugins.pmd.rule; +import org.sonar.api.server.rule.RulesDefinition; + import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; -import java.io.PrintWriter; import java.net.URL; import java.nio.charset.StandardCharsets; -import org.sonar.api.server.rule.RulesDefinition; +import static java.util.stream.Collectors.joining; /** * Reads the corresponding classpath resource to add HTML descriptions to a given rule. @@ -56,15 +56,9 @@ public void addHtmlDescription(RulesDefinition.NewRule rule) { } void addHtmlDescription(RulesDefinition.NewRule rule, URL resource) { - final StringBuilder builder = new StringBuilder(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.openStream(), StandardCharsets.UTF_8))) { - reader - .lines() - .forEach(l -> { - builder.append(l); - builder.append(System.lineSeparator()); - }); - rule.setHtmlDescription(builder.toString()); + String description = reader.lines().collect(joining(System.lineSeparator())); + rule.setHtmlDescription(description); } catch (IOException e) { throw new IllegalStateException("Failed to read: " + resource, e); } diff --git a/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/JavaRulePropertyExtractor.java b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/JavaRulePropertyExtractor.java new file mode 100644 index 00000000..fa5cb640 --- /dev/null +++ b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/JavaRulePropertyExtractor.java @@ -0,0 +1,537 @@ +package org.sonar.plugins.pmd.rule; + +import net.sourceforge.pmd.lang.rule.AbstractRule; +import net.sourceforge.pmd.properties.PropertyConstraint; +import net.sourceforge.pmd.properties.PropertyDescriptor; +import net.sourceforge.pmd.properties.PropertySource; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.plugins.pmd.rule.util.ZipBombProtection; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.*; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * Helper class to extract property information from Java rule classes in PMD jar files. + * This class loads rule classes from the jar files, identifies those that extend AbstractJavaRule, + * and extracts property information from them. + */ +public class JavaRulePropertyExtractor { + private static final Logger LOGGER = LoggerFactory.getLogger(JavaRulePropertyExtractor.class); + + static final String ABSTRACT_RULE_CLASS_NAME = AbstractRule.class.getName(); + + + /** + * Extracts property information from Java rule classes in the specified jar file. + * + * @param file Path to the PMD jar file + * @return Map of rule class names to their property information + */ + @SuppressWarnings("java:S5042") // security warning for ZIP bomb attack: implemented countermeasures + public Map> extractProperties(File file) throws IOException { + // Create a map that returns an empty list for any key that's not in the map + Map> result = new HashMap<>() { + @Override + public List get(Object key) { + List value = super.get(key); + return value != null ? value : Collections.emptyList(); + } + }; + + try (JarFile jarFile = new JarFile(file)) { + // Create a class loader for the jar file + URL[] urls = { new URL("file:" + file) }; + try (URLClassLoader classLoader = new URLClassLoader(urls, getClass().getClassLoader())) { + // First, scan the JAR for potential ZIP bomb characteristics + ZipBombProtection.scanJar(jarFile, file); + + // After validation, iterate through entries to find class files + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (entry.getName().endsWith(".class")) { + String className = entry.getName().replace('/', '.').replace(".class", ""); + try { + // Load the class + Class clazz = classLoader.loadClass(className); + + // Check if the class extends AbstractJavaRule + if (isRuleClass(clazz)) { + // Extract property information + List properties = extractPropertyInfo(clazz); + // Always add the rule to the map, even if it has no properties + result.put(className, properties); + } + } catch (ClassNotFoundException | NoClassDefFoundError e) { + // Skip classes that can't be loaded + LOGGER.debug("Could not load class: {}", className, e); + } + } + } + LOGGER.info("Extracted {} rule properties from jar file: {}", result.size(), file); + } + } + + return result; + } + + /** + * Checks if the given class is a rule class (extends AbstractJavaRule). + */ + private boolean isRuleClass(Class clazz) { + Class superClass = clazz.isAssignableFrom(AbstractRule.class) ? clazz : clazz.getSuperclass(); + while (superClass != null) { + if (ABSTRACT_RULE_CLASS_NAME.equals(superClass.getName())) { + return true; + } + superClass = superClass.getSuperclass(); + } + return false; + } + + private boolean canInstantiate(Class clazz) { + // Check if class is abstract + if (Modifier.isAbstract(clazz.getModifiers())) { + return false; + } + + // Check if class is interface + if (clazz.isInterface()) { + return false; + } + + // Non-static inner classes require an outer instance -> warn and skip + Class enclosing = clazz.getEnclosingClass(); + if (enclosing != null && !Modifier.isStatic(clazz.getModifiers())) { + LOGGER.error("Skip non-static inner rule class: {}", clazz.getName()); + return false; + } + + // Check if class has accessible default constructor + try { + Constructor constructor = clazz.getDeclaredConstructor(); + int mods = constructor.getModifiers(); + + // private -> not instantiable + if (Modifier.isPrivate(mods)) { + return false; + } + + // package-private (neither public, protected, nor private) -> warn and skip + if (!Modifier.isPublic(mods) && !Modifier.isProtected(mods)) { + LOGGER.error("Skip rule class with package-private default constructor: {}", clazz.getName()); + return false; + } + + // public or protected -> allowed for now + return true; + } catch (NoSuchMethodException e) { + return false; // No default constructor + } + + } + + /** + * Extracts property information from the given rule class. + */ + private List extractPropertyInfo(Class clazz) { + List properties = new ArrayList<>(); + + if (!canInstantiate(clazz)) { + LOGGER.info("Skip non instantiatable rule class: {}", clazz.getName()); + return properties; + } + + try { + // Try to instantiate the rule class + Object ruleInstance = clazz.getDeclaredConstructor().newInstance(); + + LOGGER.debug("Extracting properties for rule class: {}", clazz.getName()); + + // Use PMD's PropertySource API directly (PMD 7+) + if (!(ruleInstance instanceof PropertySource)) { + LOGGER.debug("Rule does not implement PropertySource: {}", clazz.getName()); + return properties; + } + + List> descriptors = + ((PropertySource) ruleInstance).getPropertyDescriptors(); + + if (descriptors != null) { + for (PropertyDescriptor descriptor : descriptors) { + PropertyInfo propertyInfo = createPropertyInfo(descriptor); + if (propertyInfo != null) { + properties.add(propertyInfo); + } + } + } + + return properties; + + } catch (Exception e) { + LOGGER.error("Error instantiating rule class: {}", clazz.getName()); + } + + return properties; + } + + /** + * Creates a PropertyInfo object from the given PropertyDescriptor object. + */ + private PropertyInfo createPropertyInfo(PropertyDescriptor propertyDescriptor) { + try { + // Use reflection to get property information + String name = propertyDescriptor.name(); + String description = propertyDescriptor.description(); + String type = resolvePropertyType(propertyDescriptor); + List defaultValues = getDefaultValues(propertyDescriptor); + List acceptedValues = determineAcceptedValues(propertyDescriptor, defaultValues); + boolean multiple = determineMultiple(propertyDescriptor); + String wrappedType = determineWrappedType(propertyDescriptor, type, defaultValues); + return new PropertyInfo(name, description, type, defaultValues, acceptedValues, multiple, wrappedType); + } catch (Exception e) { + LOGGER.warn("Error creating property info", e); + return null; + } + } + + /** + * Gets the property type from the given PropertyDescriptor object. + */ + private String resolvePropertyType(PropertyDescriptor propertyDescriptor) { + Object o = propertyDescriptor.defaultValue(); + return o == null ? "null" : convertKnownTypes(o); + } + + /** + * Converts class types into simple names, handling empty collection cases. + * If the class name starts with "Empty", it removes this prefix. + * + * @param o The object to get the simplified type name from + * @return The simplified class name as a String + */ + private static @NotNull String convertKnownTypes(Object o) { + String simpleName = o.getClass().getSimpleName(); + // is this needed? there is only: %%% found simplename with Empty: EmptySet + if (simpleName.startsWith("Empty")) { + LOGGER.debug("%%% found simplename with Empty: {}", simpleName); + simpleName = simpleName.substring("Empty".length()); + } + return simpleName; + } + + /** + * Returns the value of the given enum constant as a String. + * Most return toString(), some have an explicit workaround. + */ + private static String enumDisplay(String propertyName, Object enumConst) { + if (enumConst == null) return ""; + + String display = enumConst.toString(); + + if ("checkAddressTypes".equals(propertyName)) { + // workaround for label mapping AvoidUsingHardCodedIPRule AddressKinds enum + display = replace(display ,"IPV4", "IPv4"); + display = replace(display ,"IPV6", "IPv6"); + display = replace(display ,"IPV4_MAPPED_IPV6", "IPv4 mapped IPv6"); + } + else if ("typeAnnotations".equals(propertyName)) { + // workaround for label mapping ModifierOrderRule TypeAnnotationPosition enum + display = replace(display ,"ON_TYPE", "ontype"); + display = replace(display ,"ON_DECL", "ondecl"); + display = replace(display ,"ANYWHERE", "anywhere"); + } + + return display; + } + + private static String replace(String orig, String from, String to) { + return orig.equals(from) ? to : orig; + } + + /** + * Gets the default values from the given PropertyDescriptor object. + */ + private List getDefaultValues(PropertyDescriptor propertyDescriptor) { + try { + // Get the default values from the PropertyDescriptor + Object defaultValue = propertyDescriptor.defaultValue(); + String propertyName = propertyDescriptor.name(); + @SuppressWarnings("unchecked") + List> constraints = (List>) propertyDescriptor.serializer().getConstraints(); + if (!constraints.isEmpty()) { + LOGGER.debug("%%% found constraints: {} for {} (default value: {})", constraints.get(0).getConstraintDescription(), propertyName, defaultValue); + } + if (defaultValue instanceof List) { + @SuppressWarnings("unchecked") + List defaultValueList = (List) defaultValue; + if (!defaultValueList.isEmpty()) { + Object value = defaultValueList.get(0); + Class aClass = value.getClass(); + LOGGER.debug("%%% found list with wrapped class: {} for {} (default value: {})", aClass.getSimpleName(), propertyName, defaultValue); + } + else { + LOGGER.debug("%%% found empty list, cannot determine wrapped type for {} (default value: {})", propertyName, defaultValue); + } + List result = new ArrayList<>(); + for (Object value : defaultValueList) { + String x = (value != null && value.getClass().isEnum()) ? enumDisplay(propertyName, value) : String.valueOf(value); + result.add(x); + } + return result; + } else if (defaultValue instanceof Set) { + @SuppressWarnings("unchecked") + Set defaultValueSet = (Set) defaultValue; + if (!defaultValueSet.isEmpty()) { + LOGGER.debug("%%% found set with wrapped class: {} for {} (default value: {})", defaultValueSet.iterator().next().getClass().getSimpleName(), propertyDescriptor.name(), defaultValue); + } + else { + LOGGER.debug("%%% found empty set, cannot determine wrapped type for {} (default value: {})", propertyDescriptor.name(), defaultValue); + } + List result = new ArrayList<>(); + for (Object value : defaultValueSet) { + String x = (value != null && value.getClass().isEnum()) ? enumDisplay(propertyName, value) : String.valueOf(value); + result.add(x); + } + return result; + } else if (defaultValue instanceof Optional) { + Optional optional = (Optional) defaultValue; + if (optional.isPresent()) { + Object wrappedInOptional = optional.get(); + LOGGER.debug("%%% found optional with wrapped class: {}", wrappedInOptional.getClass().getSimpleName()); + String v = (wrappedInOptional.getClass().isEnum()) ? enumDisplay(propertyName, wrappedInOptional) : wrappedInOptional.toString(); + return Collections.singletonList(v); + } else { + if (!(propertyDescriptor.name().equals("violationSuppressRegex") || propertyDescriptor.name().equals("violationSuppressXPath"))) { + LOGGER.debug("%%% found empty optional for {}", propertyDescriptor); + } + return Collections.emptyList(); + } + } else if (defaultValue != null) { + LOGGER.debug("%%% found default value: {} for {} (type: {})", defaultValue, propertyDescriptor.name(), defaultValue.getClass().getSimpleName()); + String v = (defaultValue.getClass().isEnum()) ? enumDisplay(propertyName, defaultValue) : defaultValue.toString(); + return Collections.singletonList(v); + } + } catch (Exception e) { + LOGGER.error("Error getting default values for {}", propertyDescriptor, e); + } + return Collections.emptyList(); + } + + private boolean determineMultiple(PropertyDescriptor propertyDescriptor) { + try { + Object defaultValue = propertyDescriptor.defaultValue(); + return (defaultValue instanceof List) || (defaultValue instanceof Set); + } catch (Exception e) { + return false; + } + } + + private List determineAcceptedValues(PropertyDescriptor propertyDescriptor, List defaultValues) { + List result = new ArrayList<>(); + try { + Object defaultValue = propertyDescriptor.defaultValue(); + String propertyName = propertyDescriptor.name(); + + // 1) If enum type is discoverable from default values, use enum constants + Class enumClass = null; + if (defaultValue instanceof List) { + List list = (List) defaultValue; + if (!list.isEmpty()) { + Object first = list.get(0); + if (first != null && first.getClass().isEnum()) { + enumClass = first.getClass(); + } + } + } else if (defaultValue instanceof Set) { + Set set = (Set) defaultValue; + if (!set.isEmpty()) { + Object first = set.iterator().next(); + if (first != null && first.getClass().isEnum()) { + enumClass = first.getClass(); + } + } + } else if (defaultValue instanceof Optional) { + Optional opt = (Optional) defaultValue; + if (opt.isPresent()) { + Object inner = opt.get(); + if (inner.getClass().isEnum()) { + enumClass = inner.getClass(); + } + } + } else if (defaultValue != null && defaultValue.getClass().isEnum()) { + enumClass = defaultValue.getClass(); + } + + if (enumClass != null) { + Object[] constants = enumClass.getEnumConstants(); + if (constants != null) { + for (Object c : constants) { + String label = enumDisplay(propertyName, c); + result.add(enumDisplay(propertyName, label)); + } + } + } + + // 2) Otherwise, parse constraints description: "Possible values: [...]" or "Allowed values: [...]" + if (result.isEmpty()) { + @SuppressWarnings("unchecked") + List> constraints = (List>) propertyDescriptor.serializer().getConstraints(); + for (PropertyConstraint c : constraints) { + String desc = String.valueOf(c.getConstraintDescription()); + List fromDesc = parseValuesFromConstraintDescription(propertyName, desc); + if (!fromDesc.isEmpty()) { + result.addAll(fromDesc); + break; + } + } + } + + return List.copyOf(result); + } catch (Exception e) { + LOGGER.debug("Could not determine accepted values for {}", propertyDescriptor.name(), e); + return Collections.emptyList(); + } + } + + private String determineWrappedType(PropertyDescriptor propertyDescriptor, String fallbackType, List defaultValues) { + try { + Object defaultValue = propertyDescriptor.defaultValue(); + if (defaultValue instanceof List) { + List list = (List) defaultValue; + if (!list.isEmpty() && list.get(0) != null) { + return list.get(0).getClass().getSimpleName(); + } else { + return "Object"; // unknown element type + } + } else if (defaultValue instanceof Set) { + Set set = (Set) defaultValue; + if (!set.isEmpty()) { + Object first = set.iterator().next(); + if (first != null) return first.getClass().getSimpleName(); + } + return "Object"; + } else if (defaultValue instanceof Optional) { + Optional opt = (Optional) defaultValue; + return opt.map(o -> o.getClass().getSimpleName()).orElse(fallbackType); + } else if (defaultValue != null) { + return defaultValue.getClass().getSimpleName(); + } + } catch (Exception ignored) { + } + return fallbackType; + } + + private List parseValuesFromConstraintDescription(String propertyName, String desc) { + if (desc == null || desc.isEmpty()) return Collections.emptyList(); + // Look for "Possible values: [a, b, c]" or "Allowed values: [a, b]" + String lower = desc.toLowerCase(Locale.ROOT); + int idx = lower.indexOf("possible values:"); + if (idx < 0) idx = lower.indexOf("allowed values:"); + if (idx >= 0) { + int open = desc.indexOf('[', idx); + int close = desc.indexOf(']', open + 1); + if (open > 0 && close > open) { + String inner = desc.substring(open + 1, close); + String[] parts = inner.split(","); + List values = new ArrayList<>(); + for (String p : parts) { + String v = enumDisplay(propertyName, p.trim()); + if (!v.isEmpty()) values.add(v); + } + return values; + } + } + return Collections.emptyList(); + } + + /** + * Class to hold property information. + */ + public static class PropertyInfo { + private final String name; + private final String description; + private final String type; + private final List defaultValues; + private final List acceptedValues; + private final boolean multiple; + private final String wrappedType; + + public PropertyInfo(String name, String description, String type, List defaultValues) { + this(name, description, type, defaultValues, Collections.emptyList(), false, type); + } + + public PropertyInfo(String name, String description, String type, List defaultValues, List acceptedValues, boolean multiple) { + this(name, description, type, defaultValues, acceptedValues, multiple, type); + } + + public PropertyInfo(String name, String description, String type, List defaultValues, List acceptedValues, boolean multiple, String wrappedType) { + this.name = name; + this.description = description; + this.type = type; + this.defaultValues = List.copyOf(defaultValues); + this.acceptedValues = acceptedValues == null ? Collections.emptyList() : List.copyOf(acceptedValues); + this.multiple = multiple; + this.wrappedType = wrappedType == null ? type : wrappedType; + } + + public String getName() { + return name; + } + + public String getDescription() { + return description; + } + + public String getType() { + return type; + } + + public List getDefaultValues() { + return defaultValues; + } + + public String getDefaultValuesAsString() { + return String.join(",", defaultValues); + } + + public List getAcceptedValues() { + return acceptedValues; + } + + public boolean isMultiple() { + return multiple; + } + + public String getWrappedType() { + return wrappedType; + } + + @Override + public String toString() { + return "PropertyInfo [name=" + name + ", description=" + description + ", type=" + type + ", defaultValues=" + defaultValues + ", acceptedValues=" + acceptedValues + ", multiple=" + multiple + ", wrappedType=" + wrappedType + "]"; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + PropertyInfo that = (PropertyInfo) o; + return multiple == that.multiple && Objects.equals(name, that.name) && Objects.equals(description, that.description) && Objects.equals(type, that.type) && Objects.equals(defaultValues, that.defaultValues) && Objects.equals(acceptedValues, that.acceptedValues) && Objects.equals(wrappedType, that.wrappedType); + } + + @Override + public int hashCode() { + return Objects.hash(name, description, type, defaultValues, acceptedValues, multiple, wrappedType); + } + } + +} diff --git a/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/MarkdownToHtmlConverter.java b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/MarkdownToHtmlConverter.java new file mode 100644 index 00000000..7f4454de --- /dev/null +++ b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/MarkdownToHtmlConverter.java @@ -0,0 +1,1137 @@ +package org.sonar.plugins.pmd.rule; + + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Utility class for converting Markdown text to HTML format. + * This class supports PMD rule documentation patterns and provides + * methods for formatting rule descriptions and converting camelCase to readable text. + */ +public class MarkdownToHtmlConverter { + + // PMD version used for documentation links; configurable from outside to avoid dependency on PMD + private static volatile String PMD_VERSION = System.getProperty("pmd.version", "7.17.0"); + + /** + * Allows external configuration of the PMD version used when building links (e.g., from build scripts). + */ + public static void setPmdVersion(String version) { + if (version != null && !version.trim().isEmpty()) { + PMD_VERSION = version.trim(); + } + } + + /** + * Returns the currently configured PMD version for documentation links. + */ + public static String getPmdVersion() { + return PMD_VERSION; + } + + /** + * Computes the base URL for PMD Javadoc based on the configured PMD version. + */ + private static String jdocBase() { + return "https://docs.pmd-code.org/apidocs/pmd-java/" + PMD_VERSION + "/net/sourceforge/pmd/"; + } + + // Splits paragraphs on double newlines + private static final Pattern PARAGRAPH_SPLITTER_PATTERN = Pattern.compile("\n\\s*\n"); + // Matches paragraphs starting with "1." ordered list + private static final Pattern ORDERED_LIST_PARAGRAPH_PATTERN = Pattern.compile("\\s*1\\...*", Pattern.DOTALL); + // Matches numbered list items like "1. Item", up to 6 digits + private static final Pattern LIST_ITEM_PATTERN = Pattern.compile("(\\d{1,6})\\.(\\s{1,100})([^\r\n]*)"); + // Matches unordered list items starting with * or - + private static final Pattern UNORDERED_LIST_ITEM_PATTERN = Pattern.compile("[ \\t]*[*\\-]([ \\t]++)([^\r\n]*)"); + // Matches indented lines, from 2 up to 100 spaces or tabs, that are continuations of list items + private static final Pattern LIST_ITEM_CONTINUATION_PATTERN = Pattern.compile("^[ \\t]{2,100}([^*\\-][^\r\n]*)$"); + // Matches rule references like {% rule "rulename" %} + private static final Pattern RULE_REFERENCE_PATTERN = Pattern.compile("\\{\\%\\s*rule\\s*\"([^\"]+)\"\\s*\\%\\}"); + // Matches document sections like "Problem:", "Solution:" etc + private static final Pattern SECTION_PATTERN = Pattern.compile("(Problem|Solution|Note|Notes|Exceptions):(.+?)(?=\\s+(Problem|Solution|Note|Notes|Exceptions):|$)", Pattern.DOTALL); + // Matches multi-line code blocks between triple backticks + private static final Pattern MULTI_LINE_CODE_BLOCK_PATTERN = Pattern.compile("```(\\w*)\\s*+(((?!```).)*+)```", Pattern.DOTALL); + // Matches code blocks between quadruple backticks + private static final Pattern QUADRUPLE_BACKTICK_CODE_BLOCK_PATTERN = Pattern.compile("````(\\w*)\\s*+(((?!````).)*+)````", Pattern.DOTALL); + // Matches markdown headers like "# Title" + private static final Pattern HEADER_PATTERN = Pattern.compile("^(#{1,6})\\s++([^\r\n]++)$"); + + // Matches markdown links like [text](url) + private static final Pattern MARKDOWN_LINK_PATTERN = Pattern.compile("\\[([^\\]]+)\\]\\(([^)]+)\\)"); + // Matches PMD rule links like [text](pmd_rules_java.html) + private static final Pattern PMD_RULE_LINK_PATTERN = Pattern.compile("\\[([^\\]]+)\\]\\((pmd_rules_[^.]+\\.html[^)]*)\\)"); + // Matches URLs wrapped in angle brackets like + private static final Pattern URL_TAG_PATTERN = Pattern.compile("<(https?:\\/\\/[^>]+)>"); + // Matches Javadoc references like {% jdoc java::method %} + private static final Pattern JDOC_REFERENCE_PATTERN = Pattern.compile("\\{\\%\\s*jdoc\\s+([\\w-]+)::([\\.\\w#]+)\\s*\\%\\}"); + + // Pattern to split camelCase words like "camelCase" into "camel Case" + private static final Pattern CAMEL_CASE_SPLIT_PATTERN = Pattern.compile("([a-z])([A-Z])"); + // Pattern to identify if word starts with 2 or up to 20 capital letters like "XML" or "API" + private static final Pattern MULTIPLE_CAPITALS_PATTERN = Pattern.compile("^[A-Z]{2,20}[a-zA-Z0-9]*+"); + // Pattern to extract capital letters prefix like "API" from "APITest" + private static final Pattern CAPITALS_REST_PATTERN = Pattern.compile("^([A-Z]+)([a-z][a-zA-Z0-9]*)?"); + // Pattern to add space after digits like "123a" -> "123 a" + private static final Pattern DIGITS_LETTER_PATTERN = Pattern.compile("([a-zA-Z0-9]*?\\d{1,100})([a-zA-Z])"); + // Pattern to match newlines + private static final Pattern NEWLINE_PATTERN = Pattern.compile("\n"); + // Pattern to match and remove trailing whitespace + private static final Pattern TRAILING_WHITESPACE_PATTERN = Pattern.compile("[ \t\n\r]+$"); + // Pattern to match content inside
 tags. DOTALL flag makes dot match newlines too.
+    private static final Pattern PRE_BLOCK_PATTERN = Pattern.compile("(
[\\s\\S]*?
)", Pattern.DOTALL); + // Pattern to match content inside tags, optionally with attributes like class="language-...". + // Use a tempered dot with possessive quantifiers to avoid catastrophic backtracking + // See: https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS + // (?is) enables case-insensitive and DOTALL for the subpattern only + private static final Pattern CODE_TAG_PATTERN = Pattern.compile("(?is)(]++)?>(?:[^<]++|<(?!/code>))++)"); + // Pattern to match markdown italics like *text* + private static final Pattern MARKDOWN_ITALICS_PATTERN = Pattern.compile("\\*([^*]+)\\*"); + // Pattern to match markdown bold like **text** + private static final Pattern MARKDOWN_BOLD_PATTERN = Pattern.compile("\\*\\*([^*]+)\\*\\*"); + + /** + * Converts Markdown text to HTML format. + * + * @param markdownText The Markdown text to convert + * @return The converted HTML text + */ + public static String convertToHtml(String markdownText) { + if (markdownText == null || markdownText.trim().isEmpty()) { + return ""; + } + + // Special case for "_Note:_ This is important." pattern + if (markdownText.trim().startsWith("_Note:_")) { + String content = markdownText.trim().substring("_Note:_".length()).trim(); + return "

Note: " + content + "

"; + } + + String result = markdownText.trim(); + + // Handle multi-line code blocks first (both ``` and ````) + result = handleMultiLineCodeBlocks(result, QUADRUPLE_BACKTICK_CODE_BLOCK_PATTERN); + result = handleMultiLineCodeBlocks(result, MULTI_LINE_CODE_BLOCK_PATTERN); + + // Handle special patterns before general processing + result = handleSpecialPatterns(result); + + // Handle sections with special patterns + result = handleSections(result); + + // Extract and preserve all
 blocks before any processing
+        List preBlocks = new ArrayList<>();
+        result = extractPreBlocks(result, preBlocks);
+
+        // Replace any remaining 
 tags with special markers that won't be processed
+        result = result.replace("
", "PRE_TAG_START");
+        result = result.replace("
", "PRE_TAG_END"); + + // Split into paragraphs + String[] paragraphs = PARAGRAPH_SPLITTER_PATTERN.split(result); + List htmlParagraphs = new ArrayList<>(); + + // First pass: identify consecutive list items and convert them directly + List processedParagraphs = new ArrayList<>(); + List currentListItems = new ArrayList<>(); + boolean inList = false; + String currentParagraphText = null; + + for (String paragraph : paragraphs) { + paragraph = paragraph.trim(); + if (!paragraph.isEmpty()) { + // Check if this paragraph contains list items + String[] lines = paragraph.split("\n"); + + // Check if the paragraph starts with text and then has list items + boolean startsWithText = false; + if (lines.length > 0 && !UNORDERED_LIST_ITEM_PATTERN.matcher(lines[0]).matches()) { + startsWithText = true; + } + + // Count how many lines are list items + int listItemCount = 0; + for (String line : lines) { + if (UNORDERED_LIST_ITEM_PATTERN.matcher(line).matches()) { + listItemCount++; + } + } + + // If the paragraph starts with text and then has list items, split it + if (startsWithText && listItemCount > 0) { + // Add the text part as a regular paragraph + StringBuilder textPart = new StringBuilder(); + for (int j = 0; j < lines.length; j++) { + if (!UNORDERED_LIST_ITEM_PATTERN.matcher(lines[j]).matches()) { + if (textPart.length() > 0) { + textPart.append(" "); + } + textPart.append(lines[j].trim()); + } else { + break; + } + } + // If we were in the middle of a previous list, flush it before starting a new paragraph + if (inList) { + StringBuilder listHtml = new StringBuilder("
    "); + for (String item : currentListItems) { + listHtml.append("
  • ").append(item).append("
  • "); + } + listHtml.append("
"); + processedParagraphs.add(listHtml.toString()); + inList = false; + currentListItems = new ArrayList<>(); + } + currentParagraphText = textPart.toString(); + processedParagraphs.add(currentParagraphText); + + // Process the list items separately + StringBuilder listPart = new StringBuilder(); + for (int j = 0; j < lines.length; j++) { + if (UNORDERED_LIST_ITEM_PATTERN.matcher(lines[j]).matches()) { + listPart.append(lines[j]).append("\n"); + } else if (j > 0 && UNORDERED_LIST_ITEM_PATTERN.matcher(lines[j-1]).matches()) { + // This is a continuation line for a list item + listPart.append(lines[j]).append("\n"); + } + } + paragraph = listPart.toString().trim(); + lines = paragraph.split("\n"); + + // Recalculate list item count + listItemCount = 0; + for (String line : lines) { + if (UNORDERED_LIST_ITEM_PATTERN.matcher(line).matches()) { + listItemCount++; + } + } + } + + // If all lines are list items, or if there are multiple list items, + // treat this paragraph as a list + if (listItemCount > 0 && (listItemCount == lines.length || listItemCount >= 2)) { + // This paragraph contains list items + + // Always start a new list for each paragraph + if (inList) { + // End the current list and add it to processed paragraphs as HTML + StringBuilder listHtml = new StringBuilder("
    "); + for (String item : currentListItems) { + listHtml.append("
  • ").append(item).append("
  • "); + } + listHtml.append("
"); + processedParagraphs.add(listHtml.toString()); + } + + // If there's no current paragraph text, this is a standalone list + if (currentParagraphText == null) { + currentParagraphText = paragraph.trim(); + } + + // Start a new list + currentListItems = new ArrayList<>(); + inList = true; + + // Extract the content of each list item + StringBuilder currentItem = null; + for (String line : lines) { + Matcher matcher = UNORDERED_LIST_ITEM_PATTERN.matcher(line); + if (matcher.matches()) { + // If we have a current item, add it to the list + if (currentItem != null) { + currentListItems.add(currentItem.toString()); + } + // Start a new item + currentItem = new StringBuilder(formatInlineElements(matcher.group(2))); + } else if (line.trim().length() > 0 && currentItem != null) { + // Check if this is a continuation line + Matcher continuationMatcher = LIST_ITEM_CONTINUATION_PATTERN.matcher(line); + if (continuationMatcher.matches()) { + // This is an indented continuation line + currentItem.append(" "); + currentItem.append(formatInlineElements(continuationMatcher.group(1))); + } else { + // Regular continuation line + currentItem.append(" "); + currentItem.append(formatInlineElements(line.trim())); + } + } + } + // Add the last item if we have one + if (currentItem != null) { + currentListItems.add(currentItem.toString()); + } + } else { + // Not a single-line list item + if (inList) { + // End the current list and add it to processed paragraphs as HTML + StringBuilder listHtml = new StringBuilder("
    "); + for (String item : currentListItems) { + listHtml.append("
  • ").append(item).append("
  • "); + } + listHtml.append("
"); + processedParagraphs.add(listHtml.toString()); + inList = false; + } + // Add this paragraph as is + processedParagraphs.add(paragraph); + currentParagraphText = paragraph; + } + } else { + // Empty paragraph + if (inList) { + // End the current list and add it to processed paragraphs as HTML + StringBuilder listHtml = new StringBuilder("
    "); + for (String item : currentListItems) { + listHtml.append("
  • ").append(item).append("
  • "); + } + listHtml.append("
"); + processedParagraphs.add(listHtml.toString()); + inList = false; + currentListItems = new ArrayList<>(); + } + // Reset the current paragraph text when we encounter an empty line + currentParagraphText = null; + // Add an empty paragraph to ensure separation + processedParagraphs.add(""); + } + } + + // If we're still in a list at the end, add it + if (inList) { + StringBuilder listHtml = new StringBuilder("
    "); + for (String item : currentListItems) { + listHtml.append("
  • ").append(item).append("
  • "); + } + listHtml.append("
"); + processedParagraphs.add(listHtml.toString()); + } + + // Second pass: process the paragraphs normally + // First, let's fix the order of paragraphs and lists + List fixedParagraphs = new ArrayList<>(); + String currentParagraph = null; + String bufferedList = null; // holds a list seen before its preceding paragraph + + for (String paragraph : processedParagraphs) { + if (!paragraph.isEmpty()) { + if (paragraph.startsWith("
    ") && paragraph.endsWith("
")) { + // This is a list + if (currentParagraph != null) { + // Add the current paragraph first, then the list + fixedParagraphs.add(currentParagraph); + fixedParagraphs.add(paragraph); + currentParagraph = null; + } else { + // No current paragraph: buffer the list so that a subsequent paragraph can precede it + if (bufferedList == null) { + bufferedList = paragraph; + } else { + // Multiple lists in a row without paragraph: flush previous buffered list + fixedParagraphs.add(bufferedList); + bufferedList = paragraph; + } + } + } else { + // This is a regular paragraph + if (currentParagraph != null) { + // Add the previous paragraph + fixedParagraphs.add(currentParagraph); + currentParagraph = null; + } + if (bufferedList != null) { + // We previously saw a list before its paragraph -> emit paragraph then the buffered list + fixedParagraphs.add(paragraph); + fixedParagraphs.add(bufferedList); + bufferedList = null; + } else { + currentParagraph = paragraph; + } + } + } + } + + // Add the last paragraph or buffered list if there is one + if (currentParagraph != null) { + fixedParagraphs.add(currentParagraph); + } + if (bufferedList != null) { + fixedParagraphs.add(bufferedList); + } + + // Now process the fixed paragraphs + for (String paragraph : fixedParagraphs) { + if (!paragraph.isEmpty()) { + // Check if this paragraph contains a
 block
+                if (paragraph.contains("
")) {
+                    // Process the paragraph specially to preserve 
 blocks
+                    htmlParagraphs.add(processPreBlockParagraph(paragraph));
+                } else if (paragraph.startsWith("
    ") && paragraph.endsWith("
")) { + // This is already a processed list, just add it as is + htmlParagraphs.add(paragraph); + } else { + // Check for headers first + String[] lines = paragraph.split("\n"); + if (lines.length > 0 && HEADER_PATTERN.matcher(lines[0]).matches()) { + htmlParagraphs.add(convertHeader(paragraph)); + } else if (ORDERED_LIST_PARAGRAPH_PATTERN.matcher(paragraph).matches()) { + htmlParagraphs.add(convertParagraphWithOrderedList(paragraph)); + } else if (containsUnorderedListItems(lines)) { + // If the paragraph contains unordered list items but doesn't match the unordered list pattern + htmlParagraphs.add(convertParagraphWithUnorderedList(paragraph)); + } else { + htmlParagraphs.add("

" + formatInlineElements(paragraph) + "

"); + } + } + } + } + + // Join paragraphs with newlines + String html = String.join("\n", htmlParagraphs); + + // Restore the
 blocks
+        for (int i = 0; i < preBlocks.size(); i++) {
+            html = html.replace("PRE_BLOCK_" + i + "_PLACEHOLDER", preBlocks.get(i));
+        }
+
+        // Restore any remaining 
 tags
+        html = html.replace("PRE_TAG_START", "
");
+        html = html.replace("PRE_TAG_END", "
"); + + return html; + } + + /** + * Converts camelCase rule name to readable format with only first letter uppercase. + * For example: "APITest" -> "API test", "XMLHttpRequest" -> "XMLHttp request" + * + * @param ruleName The camelCase rule name to convert + * @return The readable format of the rule name + */ + public static String camelCaseToReadable(String ruleName) { + if (ruleName == null || ruleName.isEmpty()) { + return ""; + } + + // Special cases for specific rule names + if (ruleName.equals("XMLHTTPRequest")) { + return "XMLHTTP request"; + } + if (ruleName.equals("APITest")) { + return "API test"; + } + if (ruleName.equals("isNaN")) { + return "Is NaN"; + } + + // Protect well-known acronyms that shouldn't be split or lowercased + final String NAN_PLACEHOLDER = "N_a_N"; // avoid [a][A] split between a and N + String protectedName = ruleName.replace("NaN", NAN_PLACEHOLDER); + + // Split the rule name into words + String[] words = CAMEL_CASE_SPLIT_PATTERN.matcher(protectedName).replaceAll("$1 $2").trim().split(" "); + List processedWords = new ArrayList<>(); + + for (String word : words) { + if (word.isEmpty()) { + continue; + } + + // Special case for NaN (may be present as placeholder) + if (word.equals("NaN") || word.equals("N_a_N")) { + processedWords.add("NaN"); + continue; + } + + // If word has multiple consecutive capitals at start, preserve them + if (MULTIPLE_CAPITALS_PATTERN.matcher(word).matches()) { + Matcher matcher = CAPITALS_REST_PATTERN.matcher(word); + if (matcher.matches()) { + String capitals = matcher.group(1); + String rest = matcher.group(2) != null ? matcher.group(2) : ""; + processedWords.add(capitals + (rest.isEmpty() ? "" : rest.toLowerCase())); + continue; + } + } + + // Otherwise, lowercase everything + processedWords.add(word.toLowerCase()); + } + + String result = String.join(" ", processedWords); + + // Add space after words ending with consecutive digits + result = DIGITS_LETTER_PATTERN.matcher(result).replaceAll("$1 $2"); + + // Capitalize only the first word + if (!result.isEmpty()) { + result = Character.toUpperCase(result.charAt(0)) + (result.length() > 1 ? result.substring(1) : ""); + } + + // Apply well-known Java name fixes so callers don't need a separate call + result = fixWellKnownJavaNames(ruleName, result); + + return result; + } + + /** + * Applies a set of well-known Java name fixes to a readable rule name. + * This encapsulates all special cases previously implemented in the Groovy generator + * so it can be reused across the project. + * + * Note: camelCaseToReadable already applies these fixes internally. This method remains + * public for backward compatibility and potential reuse in other contexts. + * + * @param ruleKey The original rule key/name (camelCase), used for conditional fixes + * @param readableName The readable name produced by camelCaseToReadable + * @return The normalized readable name with Java-specific fixes + */ + public static String fixWellKnownJavaNames(String ruleKey, String readableName) { + if (readableName == null) { + return null; + } + String result = readableName; + + // Fix known acronym splitting like NaN + if (ruleKey != null && ruleKey.contains("NaN")) { + result = result.replaceAll("(?i)\\bna\\s+n\\b", "NaN"); + } + + // Fix well-known Java type names that should not be split or lowercased + if (ruleKey != null && ruleKey.contains("BigDecimal")) { + result = result.replaceAll("(?i)\\bbig\\s+decimal\\b", "BigDecimal"); + } + if (ruleKey != null && ruleKey.contains("BigInteger")) { + result = result.replaceAll("(?i)\\bbig\\s+integer\\b", "BigInteger"); + } + if (ruleKey != null && ruleKey.contains("Throwable")) { + result = result.replaceAll("(?i)\\bthrowable\\b", "Throwable"); + } + if (ruleKey != null && ruleKey.contains("StringBuilder")) { + result = result.replaceAll("(?i)\\bstring\\s+builder\\b", "StringBuilder"); + } + if (ruleKey != null && ruleKey.contains("StringBuffer")) { + result = result.replaceAll("(?i)\\bstring\\s+buffer\\b", "StringBuffer"); + } + if (ruleKey != null && ruleKey.contains("StringTokenizer")) { + result = result.replaceAll("(?i)\\bstring\\s+tokenizer\\b", "StringTokenizer"); + } + + // Special casing for MDBAnd… rules: split into words correctly + if (ruleKey != null && ruleKey.contains("MDBAnd")) { + result = result.replace("MDBAnd", "MDB and"); + } + + // Additional normalizations for Java class names, acronyms, and method names + result = result + // Class and type names + .replaceAll("(?i)\\bthread\\s+group\\b", "ThreadGroup") + .replaceAll("(?i)\\bnull\\s+pointer\\s+exception\\b", "NullPointerException") + .replaceAll("(?i)\\bclass\\s+cast\\s+exception\\b", "ClassCastException") + .replaceAll("(?i)\\bcloneable\\b", "Cloneable") + .replaceAll("(?i)\\bclass\\s*loader\\b", "ClassLoader") + .replaceAll("(?i)\\bconcurrent\\s*hash\\s*map\\b", "ConcurrentHashMap") + .replaceAll("(?i)\\bfile\\s*item\\b", "FileItem") + // Java packages + .replaceAll("(?i)\\bjava\\s*\\.\\s*lang\\s*\\.\\s*error\\b|\\bjava\\s+lang\\s+error\\b", "java.lang.Error") + .replaceAll("(?i)\\bjava\\s*\\.\\s*lang\\s*\\.\\s*throwable\\b|\\bjava\\s+lang\\s+throwable\\b", "java.lang.Throwable") + // Acronyms and constants + .replaceAll("(?i)\\bcrypto\\s*iv\\b", "crypto IV") + .replaceAll("(?i)\\bncss\\b", "NCSS") + .replaceAll("(?i)\\bserial\\s*version\\s*uid\\b", "serialVersionUID") + .replaceAll("(?i)\\bcharsets\\b", "Charsets") + // Java word capitalization + .replaceAll("(?i)\\bjava\\s+bean\\b", "Java bean") + // Collections / class names + .replaceAll("(?i)\\benumeration\\b", "Enumeration") + .replaceAll("(?i)\\biterator\\b", "Iterator") + .replaceAll("(?i)\\bhashtable\\b", "Hashtable") + .replaceAll("(?i)\\bmap\\b", "Map") + .replaceAll("(?i)\\bvector\\b", "Vector") + .replaceAll("(?i)\\blist\\b", "List") + // Methods and API references + .replaceAll("(?i)\\bto\\s*array\\b", "toArray") + .replaceAll("(?i)\\bcollection\\s*\\.\\s*is\\s*empty\\b|\\bcollection\\s+is\\s+empty\\b", "Collection.isEmpty") + .replaceAll("(?i)\\bnotify\\s*all\\b", "notifyAll") + .replaceAll("(?i)\\bstandard\\s+charsets\\b", "standard Charsets") + .replaceAll("(?i)\\bshort\\s+array\\s+initializer\\b", "short Array initializer") + // Exceptions capitalization + .replaceAll("(?i)\\bthrows\\s+exception\\b", "throws Exception") + // Date/Locale APIs + .replaceAll("(?i)\\bsimple\\s*date\\s*format\\b", "SimpleDateFormat") + .replaceAll("(?i)\\blocale\\b", "Locale"); + + // Special cases based on exact rule keys + if ("UseArrayListInsteadOfVector".equals(ruleKey)) { + result = "Use Arrays.asList"; + } + if ("UselessStringValueOf".equals(ruleKey)) { + result = "Useless String.valueOf"; + } + + return result; + } + + /** + * Escapes special regex replacement characters. + */ + private static String escapeReplacement(String replacement) { + return Matcher.quoteReplacement(replacement); + } + + /** + * Handles multi-line code blocks. + */ + private static String handleMultiLineCodeBlocks(String markdownText, Pattern pattern) { + Matcher matcher = pattern.matcher(markdownText); + StringBuilder sb = new StringBuilder(); + + while (matcher.find()) { + String language = matcher.group(1) != null ? matcher.group(1) : ""; + String code = matcher.group(2) != null ? matcher.group(2) : ""; + + // Format code with proper spacing and trim trailing whitespace + code = " " + NEWLINE_PATTERN.matcher(code).replaceAll("\n "); + code = TRAILING_WHITESPACE_PATTERN.matcher(code).replaceAll(""); + + // Create HTML code block with optional language class + String langClass = language.isEmpty() ? "" : " class=\"language-" + language + "\""; + String html = "
" + escapeHtml(code) + "
"; + + matcher.appendReplacement(sb, escapeReplacement(html)); + } + + matcher.appendTail(sb); + return sb.toString(); + } + + /** + * Handles special patterns in the text. + */ + private static String handleSpecialPatterns(String text) { + String result = text; + + result = handleNoteItalicsPattern(result); + result = handlePmdRuleLinkPattern(result); + result = handleMarkdownLinkPattern(result); + result = handleUrlTagPattern(result); + + return result; + } + + /** + * Handles URL tags like . + */ + private static String handleUrlTagPattern(String result) { + Matcher urlTagMatcher = URL_TAG_PATTERN.matcher(result); + StringBuilder sb = new StringBuilder(); + while (urlTagMatcher.find()) { + String url = urlTagMatcher.group(1); + String replacement = "" + url + ""; + urlTagMatcher.appendReplacement(sb, escapeReplacement(replacement)); + } + urlTagMatcher.appendTail(sb); + return sb.toString(); + } + + /** + * Handles general markdown links. + */ + private static String handleMarkdownLinkPattern(String result) { + Matcher markdownLinkMatcher = MARKDOWN_LINK_PATTERN.matcher(result); + StringBuilder sb = new StringBuilder(); + while (markdownLinkMatcher.find()) { + String replacement = "" + markdownLinkMatcher.group(1) + ""; + markdownLinkMatcher.appendReplacement(sb, escapeReplacement(replacement)); + } + markdownLinkMatcher.appendTail(sb); + return sb.toString(); + } + + /** + * Handles PMD rule links. + */ + private static String handlePmdRuleLinkPattern(String result) { + Matcher ruleLinkMatcher = PMD_RULE_LINK_PATTERN.matcher(result); + StringBuilder sb = new StringBuilder(); + while (ruleLinkMatcher.find()) { + String linkText = ruleLinkMatcher.group(1); + String href = ruleLinkMatcher.group(2); + String replacement = "" + linkText + ""; + ruleLinkMatcher.appendReplacement(sb, escapeReplacement(replacement)); + } + ruleLinkMatcher.appendTail(sb); + return sb.toString(); + } + + /** + * Handles _Note:_ pattern. + */ + private static String handleNoteItalicsPattern(String result) { + // Replace _Note:_ with Note: directly + return result.replace("_Note:_", "Note:"); + } + + /** + * Handles sections with special patterns. + */ + private static String handleSections(String text) { + Matcher matcher = SECTION_PATTERN.matcher(text); + StringBuilder sb = new StringBuilder(); + + while (matcher.find()) { + String sectionType = matcher.group(1); + String content = matcher.group(2) != null ? matcher.group(2).trim() : ""; + String replacement = "

" + sectionType + ": " + formatInlineElements(content) + "

"; + matcher.appendReplacement(sb, escapeReplacement(replacement)); + } + + matcher.appendTail(sb); + return sb.toString(); + } + + /** + * Converts a header paragraph to HTML. + */ + private static String convertHeader(String headerText) { + String[] lines = headerText.split("\n"); + StringBuilder result = new StringBuilder(); + + for (String line : lines) { + Matcher matcher = HEADER_PATTERN.matcher(line.trim()); + if (matcher.matches()) { + String hashes = matcher.group(1); + String content = matcher.group(2); + int level = hashes.length(); + result.append("").append(formatInlineElements(content)).append(""); + } else { + // Handle continuation lines as regular paragraph content + if (!line.trim().isEmpty()) { + result.append("

").append(formatInlineElements(line)).append("

"); + } + } + } + + return result.toString(); + } + + /** + * Converts a paragraph with ordered list to HTML. + */ + private static String convertParagraphWithOrderedList(String paragraph) { + String[] lines = paragraph.split("\n"); + StringBuilder result = new StringBuilder(); + boolean inList = false; + + for (String line : lines) { + line = line.trim(); + if (LIST_ITEM_PATTERN.matcher(line).matches()) { + if (!inList) { + result.append("
    "); + inList = true; + } + Matcher matcher = LIST_ITEM_PATTERN.matcher(line); + if (matcher.find()) { + result.append("
  1. ").append(formatInlineElements(matcher.group(3))).append("
  2. "); + } + } else if (!line.isEmpty() && inList) { + // Continuation of previous list item - add space but no line break + result.append(" ").append(formatInlineElements(line)); + } + } + + if (inList) { + result.append("
"); + } + + return result.toString(); + } + + /** + * Checks if the lines contain unordered list items. + */ + private static boolean containsUnorderedListItems(String[] lines) { + for (String line : lines) { + if (UNORDERED_LIST_ITEM_PATTERN.matcher(line).matches()) { + return true; + } + } + return false; + } + + /** + * Converts a paragraph with unordered list to HTML. + */ + private static String convertParagraphWithUnorderedList(String paragraphText) { + String[] lines = paragraphText.split("\n"); + StringBuilder result = new StringBuilder(); + boolean inList = false; + boolean paragraphStarted = false; + boolean inListItem = false; + StringBuilder currentListItem = new StringBuilder(); + + for (String line : lines) { + String trimmedLine = line.trim(); + + // Skip empty lines + if (trimmedLine.isEmpty()) continue; + + Matcher listItemMatcher = UNORDERED_LIST_ITEM_PATTERN.matcher(line); + + if (listItemMatcher.matches()) { + // Handle list item start + + // Close paragraph if needed + if (paragraphStarted && !inList) { + paragraphStarted = false; + } + + // Close previous list item if needed + if (inListItem) { + result.append("
  • ").append(currentListItem).append("
  • "); + currentListItem = new StringBuilder(); + } + + // Start list if needed + if (!inList) { + result.append("
      "); + inList = true; + } + + // Add content to the new list item + currentListItem.append(formatInlineElements(listItemMatcher.group(2))); + inListItem = true; + + } else if (inList) { + // Handle content within a list + + Matcher continuationMatcher = LIST_ITEM_CONTINUATION_PATTERN.matcher(line); + + if (inListItem) { + // Add continuation content to current list item + currentListItem.append(" "); + + if (continuationMatcher.matches()) { + // Indented continuation line + currentListItem.append(formatInlineElements(continuationMatcher.group(1))); + } else { + // Regular continuation line + currentListItem.append(formatInlineElements(trimmedLine)); + } + } + + } else { + // Handle regular paragraph text + + if (!paragraphStarted) { + result.append("

      "); + paragraphStarted = true; + } + + result.append(formatInlineElements(trimmedLine)); + } + } + + // Close any open elements + if (inListItem) { + result.append("

    • ").append(currentListItem).append("
    • "); + } + + if (inList) { + result.append("
    "); + } + + if (paragraphStarted) { + result.append("

    "); + } + + return result.toString(); + } + + /** + * Formats inline elements in the text. + */ + private static String formatInlineElements(String text) { + if (text == null || text.isEmpty()) return ""; + // Pre blocks are handled elsewhere (globally extracted or via processPreBlockParagraph), + // so we can directly format the text here. + return formatTextWithoutPre(text); + } + + + + + + /** + * Simple class to hold the result of pre-processing text with
     blocks.
    +     */
    +
    +    /**
    +     * Formats text without 
     blocks.
    +     */
    +    private static String formatTextWithoutPre(String text) {
    +        if (text == null || text.isEmpty()) return "";
    +
    +        String result = text;
    +
    +        // First convert backticks to ...
    +        result = handleCodeBlockPattern(result);
    +
    +        // Apply rule and jdoc references only outside of ... blocks
    +        Matcher codeTagMatcher = CODE_TAG_PATTERN.matcher(result);
    +        StringBuilder assembled = new StringBuilder();
    +        int lastEnd = 0;
    +        while (codeTagMatcher.find()) {
    +            String before = result.substring(lastEnd, codeTagMatcher.start());
    +            before = handleRuleReferencePattern(before);
    +            before = handleJdocPattern(before);
    +            assembled.append(before);
    +            assembled.append(codeTagMatcher.group(1));
    +            lastEnd = codeTagMatcher.end();
    +        }
    +        String tail = result.substring(lastEnd);
    +        tail = handleRuleReferencePattern(tail);
    +        tail = handleJdocPattern(tail);
    +        assembled.append(tail);
    +        result = assembled.toString();
    +
    +        // Bold/Italics already avoid  blocks
    +        result = handleMarkdownBoldPattern(result);
    +        result = handleMarkdownItalicsPattern(result);
    +
    +        return result;
    +    }
    +
    +    /**
    +     * Handles markdown italics pattern.
    +     */
    +    private static String handleMarkdownItalicsPattern(String result) {
    +        return applyOutsideCodeTags(result, MARKDOWN_ITALICS_PATTERN, "", "");
    +    }
    +
    +    /**
    +     * Handles markdown bold pattern.
    +     */
    +    private static String handleMarkdownBoldPattern(String result) {
    +        return applyOutsideCodeTags(result, MARKDOWN_BOLD_PATTERN, "", "");
    +    }
    +
    +    /**
    +     * Handles jdoc references.
    +     */
    +    private static String handleJdocPattern(String result) {
    +        Matcher jdocMatcher = JDOC_REFERENCE_PATTERN.matcher(result);
    +        StringBuilder sbJdoc = new StringBuilder();
    +        while (jdocMatcher.find()) {
    +            String replacement = createJdocReference(jdocMatcher);
    +            jdocMatcher.appendReplacement(sbJdoc, escapeReplacement(replacement));
    +        }
    +        jdocMatcher.appendTail(sbJdoc);
    +        return sbJdoc.toString();
    +    }
    +
    +    /**
    +     * Creates a jdoc reference link.
    +     */
    +    private static String createJdocReference(Matcher match) {
    +        String fullyQualifiedName = match.group(2);
    +
    +        // Extract class name and member name if present
    +        int hashIndex = fullyQualifiedName.indexOf('#');
    +        String className = hashIndex > 0 ? fullyQualifiedName.substring(0, hashIndex) : fullyQualifiedName;
    +        String memberName = hashIndex > 0 ? fullyQualifiedName.substring(hashIndex + 1) : "";
    +
    +        // Build URL and determine display text
    +        String urlPath = className.replace('.', '/');
    +        String url = jdocBase() + urlPath + ".html" + (memberName.isEmpty() ? "" : "#" + memberName);
    +        String displayText = memberName.isEmpty() ? className.substring(className.lastIndexOf('.') + 1) : memberName;
    +
    +        return escapeReplacement("" + displayText + "");
    +    }
    +
    +    /**
    +     * Handles rule references.
    +     */
    +    private static String handleRuleReferencePattern(String result) {
    +        Matcher ruleRefMatcher = RULE_REFERENCE_PATTERN.matcher(result);
    +        StringBuilder sb = new StringBuilder();
    +        while (ruleRefMatcher.find()) {
    +            String replacement = "" + escapeHtml(ruleRefMatcher.group(1)) + "";
    +            ruleRefMatcher.appendReplacement(sb, escapeReplacement(replacement));
    +        }
    +        ruleRefMatcher.appendTail(sb);
    +        return sb.toString();
    +    }
    +
    +    /**
    +     * Handles code blocks.
    +     */
    +    private static String handleCodeBlockPattern(String result) {
    +        if (result == null || result.isEmpty()) return "";
    +
    +        StringBuilder out = new StringBuilder();
    +        boolean inHtmlCode = false;
    +        boolean inBacktick = false;
    +        StringBuilder backtickBuf = new StringBuilder();
    +        int i = 0;
    +        while (i < result.length()) {
    +            // Detect start/end of real HTML  blocks to avoid processing inside them
    +            if (!inBacktick && result.startsWith("', i);
    +                if (gt != -1) {
    +                    inHtmlCode = true;
    +                    out.append(result, i, gt + 1);
    +                    i = gt + 1;
    +                    continue;
    +                }
    +            }
    +            if (!inBacktick && inHtmlCode && result.startsWith("", i)) {
    +                inHtmlCode = false;
    +                out.append("");
    +                i += 7;
    +                continue;
    +            }
    +
    +            if (!inHtmlCode) {
    +                char ch = result.charAt(i);
    +                if (ch == '`') {
    +                    if (!inBacktick) {
    +                        inBacktick = true;
    +                        backtickBuf.setLength(0);
    +                    } else {
    +                        // closing backtick -> emit code
    +                        String codeContent = backtickBuf.toString();
    +                        // strip literal  tags inside backticks
    +                        codeContent = codeContent.replaceAll("(?i)", "");
    +                        out.append("").append(escapeHtml(codeContent)).append("");
    +                        inBacktick = false;
    +                    }
    +                    i++;
    +                    continue;
    +                }
    +
    +                if (inBacktick) {
    +                    backtickBuf.append(ch);
    +                } else {
    +                    out.append(ch);
    +                }
    +                i++;
    +            } else {
    +                // inside existing HTML  block: copy as-is
    +                out.append(result.charAt(i));
    +                i++;
    +            }
    +        }
    +
    +        // If we ended while still in backticks, treat as literal text (put back the opening backtick)
    +        if (inBacktick) {
    +            out.append('`').append(backtickBuf);
    +        }
    +
    +        return out.toString();
    +    }
    +
    +    /**
    +     * Escapes HTML special characters.
    +     */
    +    private static String escapeHtml(String text) {
    +        if (text == null || text.isEmpty()) return "";
    +        return text.replace("&", "&")
    +                .replace("<", "<")
    +                .replace(">", ">")
    +                .replace("\"", """)
    +                .replace("'", "'");
    +    }
    +
    +
    +    /**
    +     * Extract 
     blocks and replace them with placeholders.
    +     */
    +    private static String extractPreBlocks(String text, List preBlocks) {
    +        Matcher matcher = PRE_BLOCK_PATTERN.matcher(text);
    +        StringBuilder sb = new StringBuilder();
    +
    +        while (matcher.find()) {
    +            preBlocks.add(matcher.group(0));
    +            matcher.appendReplacement(sb, "PRE_BLOCK_" + (preBlocks.size() - 1) + "_PLACEHOLDER");
    +        }
    +        matcher.appendTail(sb);
    +        return sb.toString();
    +    }
    +
    +    /**
    +     * Process a paragraph that contains 
     blocks.
    +     */
    +    private static String processPreBlockParagraph(String paragraph) {
    +        // Extract all 
     blocks from the paragraph
    +        List preBlocks = new ArrayList<>();
    +        Matcher matcher = PRE_BLOCK_PATTERN.matcher(paragraph);
    +        StringBuilder sb = new StringBuilder();
    +
    +        // Replace 
     blocks with placeholders
    +        int index = 0;
    +        while (matcher.find()) {
    +            preBlocks.add(matcher.group(0));
    +            matcher.appendReplacement(sb, "PRE_BLOCK_" + index++ + "_PLACEHOLDER");
    +        }
    +        matcher.appendTail(sb);
    +
    +        // Process the text outside 
     blocks
    +        String textWithoutPre = sb.toString();
    +        String[] lines = textWithoutPre.split("\n");
    +
    +        // Process as header or regular paragraph
    +        String processedText = lines.length > 0 && HEADER_PATTERN.matcher(lines[0].trim()).matches()
    +                ? convertHeader(textWithoutPre)
    +                : "

    " + formatInlineElements(textWithoutPre) + "

    "; + + // Restore
     blocks
    +        for (int i = 0; i < preBlocks.size(); i++) {
    +            processedText = processedText.replace("PRE_BLOCK_" + i + "_PLACEHOLDER", preBlocks.get(i));
    +        }
    +
    +        return processedText;
    +    }
    +
    +    /**
    +     * Applies a markdown pattern replacement only outside of ... blocks.
    +     * The replacement wraps the matched group(1) with the provided tags after escaping HTML.
    +     */
    +    private static String applyOutsideCodeTags(String text, Pattern markdownPattern, String openTag, String closeTag) {
    +        if (text == null || text.isEmpty()) return "";
    +        Matcher codeTagMatcher = CODE_TAG_PATTERN.matcher(text);
    +        StringBuilder out = new StringBuilder();
    +        int lastEnd = 0;
    +        while (codeTagMatcher.find()) {
    +            // Process text before the  block
    +            String before = text.substring(lastEnd, codeTagMatcher.start());
    +            out.append(applyMarkdownPattern(before, markdownPattern, openTag, closeTag));
    +            // Append the  block unchanged
    +            out.append(codeTagMatcher.group(1));
    +            lastEnd = codeTagMatcher.end();
    +        }
    +        // Process the remaining text after the last  block
    +        String after = text.substring(lastEnd);
    +        out.append(applyMarkdownPattern(after, markdownPattern, openTag, closeTag));
    +        return out.toString();
    +    }
    +
    +    /**
    +     * Applies a single markdown regex replacement to the given text.
    +     */
    +    private static String applyMarkdownPattern(String text, Pattern markdownPattern, String openTag, String closeTag) {
    +        if (text == null || text.isEmpty()) return "";
    +        Matcher m = markdownPattern.matcher(text);
    +        StringBuilder sb = new StringBuilder();
    +        while (m.find()) {
    +            String replacement = openTag + escapeHtml(m.group(1)) + closeTag;
    +            m.appendReplacement(sb, escapeReplacement(replacement));
    +        }
    +        m.appendTail(sb);
    +        return sb.toString();
    +    }
    +
    +}
    \ No newline at end of file
    diff --git a/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/PmdRuleScopeRegistry.java b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/PmdRuleScopeRegistry.java
    new file mode 100644
    index 00000000..749f6e8d
    --- /dev/null
    +++ b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/PmdRuleScopeRegistry.java
    @@ -0,0 +1,251 @@
    +/*
    + * SonarQube PMD7 Plugin
    + * Copyright (C) 2012-2021 SonarSource SA and others
    + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl
    + *
    + * This program is free software; you can redistribute it and/or
    + * modify it under the terms of the GNU Lesser General Public
    + * License as published by the Free Software Foundation; either
    + * version 3 of the License, or (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    + * Lesser General Public License for more details.
    + *
    + * You should have received a copy of the GNU Lesser General Public License
    + * along with this program; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    + */
    +package org.sonar.plugins.pmd.rule;
    +
    +import org.slf4j.Logger;
    +import org.slf4j.LoggerFactory;
    +import org.sonar.api.rule.RuleScope;
    +
    +import javax.xml.namespace.QName;
    +import javax.xml.stream.XMLEventReader;
    +import javax.xml.stream.XMLInputFactory;
    +import javax.xml.stream.XMLStreamException;
    +import javax.xml.stream.events.Attribute;
    +import javax.xml.stream.events.StartElement;
    +import javax.xml.stream.events.XMLEvent;
    +import java.io.InputStream;
    +import java.io.InputStreamReader;
    +import java.io.Reader;
    +import java.nio.charset.Charset;
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.HashMap;
    +import java.util.HashSet;
    +import java.util.List;
    +import java.util.Map;
    +import java.util.Set;
    +import java.net.URL;
    +
    +/**
    + * Registry that stores the scope (MAIN, TEST, ALL) for each PMD rule by parsing the XML rule definitions.
    + * This allows accurate scope determination during batch analysis without relying on heuristics.
    + * Uses the same scope determination logic as {@link RulesDefinitionXmlLoader}.
    + */
    +public class PmdRuleScopeRegistry {
    +
    +    private static final Logger LOGGER = LoggerFactory.getLogger(PmdRuleScopeRegistry.class);
    +
    +    private static final String ELEMENT_RULE = "rule";
    +
    +    private final Map ruleScopeMap = new HashMap<>();
    +    private final Set loadedResources = new HashSet<>();
    +
    +    private static volatile PmdRuleScopeRegistry INSTANCE;
    +
    +    public static PmdRuleScopeRegistry getInstance() {
    +        if (INSTANCE == null) {
    +            synchronized (PmdRuleScopeRegistry.class) {
    +                if (INSTANCE == null) {
    +                    INSTANCE = new PmdRuleScopeRegistry();
    +                }
    +            }
    +        }
    +        return INSTANCE;
    +    }
    +
    +    /**
    +     * Creates an empty registry. Use addXmlResources(...) to load rule scopes.
    +     */
    +    public PmdRuleScopeRegistry() {
    +        // empty
    +    }
    +
    +    public synchronized void addXmlResources(String... xmlResourcePaths) {
    +        if (xmlResourcePaths == null) {
    +            return;
    +        }
    +        for (String path : xmlResourcePaths) {
    +            LOGGER.info("Loading rule scopes from XML '{}'", path);
    +            if (path == null) {
    +                continue;
    +            }
    +            if (loadedResources.add(path)) { // only load once
    +                loadRulesFromXml(path);
    +            } else {
    +                LOGGER.debug("Rule scopes for XML '{}' already loaded, skipping.", path);
    +            }
    +        }
    +    }
    +
    +    /**
    +     * Add XML resources provided as URLs, allowing multiple resources with the same path
    +     * to be loaded from different classpath entries (e.g., child plugins).
    +     */
    +    public synchronized void addXmlUrls(URL... urls) {
    +        if (urls == null) {
    +            return;
    +        }
    +        for (URL url : urls) {
    +            if (url == null) {
    +                continue;
    +            }
    +            String id = url.toExternalForm();
    +            if (loadedResources.add(id)) {
    +                LOGGER.info("Loading rule scopes from URL '{}'", id);
    +                loadRulesFromUrl(url);
    +            } else {
    +                LOGGER.debug("Rule scopes for URL '{}' already loaded, skipping.", id);
    +            }
    +        }
    +    }
    +
    +
    +    /**
    +     * Gets the scope for a rule key.
    +     *
    +     * @param ruleKey The rule key
    +     * @return The rule scope, or RuleScope.ALL if not found
    +     */
    +    public RuleScope getScope(String ruleKey) {
    +        return ruleScopeMap.getOrDefault(ruleKey, RuleScope.ALL);
    +    }
    +
    +    private void loadRulesFromXml(String xmlResourcePath) {
    +        try (InputStream inputStream = getClass().getResourceAsStream(xmlResourcePath)) {
    +            if (inputStream == null) {
    +                LOGGER.warn("Cannot find XML resource: {}", xmlResourcePath);
    +                return;
    +            }
    +
    +            Map scopes = loadRuleScopesFromStream(inputStream, StandardCharsets.UTF_8);
    +            ruleScopeMap.putAll(scopes);
    +
    +            LOGGER.debug("Loaded {} rule scopes from {}", scopes.size(), xmlResourcePath);
    +        } catch (Exception e) {
    +            LOGGER.error("Failed to load rule scopes from {}", xmlResourcePath, e);
    +        }
    +    }
    +
    +    private void loadRulesFromUrl(URL url) {
    +        try (InputStream inputStream = url.openStream()) {
    +            Map scopes = loadRuleScopesFromStream(inputStream, StandardCharsets.UTF_8);
    +            ruleScopeMap.putAll(scopes);
    +            LOGGER.debug("Loaded {} rule scopes from URL {}", scopes.size(), url);
    +        } catch (Exception e) {
    +            LOGGER.error("Failed to load rule scopes from URL {}", url, e);
    +        }
    +    }
    +
    +    private Map loadRuleScopesFromStream(InputStream input, Charset charset) {
    +        Map scopeMap = new HashMap<>();
    +        try (Reader reader = new InputStreamReader(input, charset)) {
    +            XMLInputFactory xmlFactory = XMLInputFactory.newInstance();
    +            xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
    +            // Enable namespace awareness to correctly handle files with default or prefixed namespaces on  or children
    +            xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.TRUE);
    +            // just so it won't try to load DTD in if there's DOCTYPE
    +            xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
    +            xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE);
    +            XMLEventReader xmlReader = xmlFactory.createXMLEventReader(reader);
    +
    +            parseRuleScopesOnly(scopeMap, xmlReader);
    +
    +        } catch (Exception e) {
    +            throw new IllegalStateException("Failed to load rule scopes from XML", e);
    +        }
    +        return scopeMap;
    +    }
    +
    +    private static void parseRuleScopesOnly(Map scopeMap, XMLEventReader reader) throws XMLStreamException {
    +        while (reader.hasNext()) {
    +            XMLEvent event = reader.nextEvent();
    +            if (event.isStartElement()) {
    +                StartElement element = event.asStartElement();
    +                String elementName = element.getName().getLocalPart();
    +                if (ELEMENT_RULE.equalsIgnoreCase(elementName)) {
    +                    processRuleScopeOnly(scopeMap, element, reader);
    +                }
    +            }
    +        }
    +    }
    +
    +    private static void processRuleScopeOnly(Map scopeMap, StartElement ruleElement, XMLEventReader reader) throws XMLStreamException {
    +        String key = null;
    +        String name = null;
    +        List tags = new ArrayList<>();
    +
    +        // Support legacy format: 
    +        QName qn = new QName("key");
    +        Attribute keyAttr = ruleElement.getAttributeByName(qn);
    +        if (keyAttr != null && keyAttr.getValue() != null && !keyAttr.getValue().isEmpty()) {
    +            key = keyAttr.getValue().trim();
    +        }
    +
    +        while (reader.hasNext()) {
    +            XMLEvent event = reader.nextEvent();
    +            if (event.isEndElement() && ELEMENT_RULE.equalsIgnoreCase(event.asEndElement().getName().getLocalPart())) {
    +                break;
    +            }
    +            if (event.isStartElement()) {
    +                StartElement element = event.asStartElement();
    +                String elementName = element.getName().getLocalPart();
    +
    +                if ("key".equalsIgnoreCase(elementName)) {
    +                    String text = reader.getElementText();
    +                    key = text;
    +                } else if ("name".equalsIgnoreCase(elementName) || "title".equalsIgnoreCase(elementName)) {
    +                    String text = reader.getElementText();
    +                    name = text;
    +                } else if ("tag".equalsIgnoreCase(elementName)) {
    +                    String text = reader.getElementText();
    +                    if (text != null && !text.isEmpty()) {
    +                        tags.add(text);
    +                    }
    +                } else {
    +                    // Unhandled element like  may contain nested elements: skip safely
    +                    skipElement(reader, elementName);
    +                }
    +            }
    +        }
    +
    +        if (key != null) {
    +            RuleScope scope = RulesDefinitionXmlLoader.determineScope(name, tags);
    +            scopeMap.put(key, scope);
    +        }
    +    }
    +
    +    // Skips over the current element, consuming all nested content until its matching end tag
    +    private static void skipElement(XMLEventReader reader, String elementName) throws XMLStreamException {
    +        int depth = 0;
    +        while (reader.hasNext()) {
    +            XMLEvent e = reader.nextEvent();
    +            if (e.isStartElement()) {
    +                depth++;
    +            } else if (e.isEndElement()) {
    +                if (depth == 0 && e.asEndElement().getName().getLocalPart().equalsIgnoreCase(elementName)) {
    +                    return;
    +                }
    +                if (depth > 0) {
    +                    depth--;
    +                }
    +            }
    +        }
    +    }
    +}
    diff --git a/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoader.java b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoader.java
    new file mode 100644
    index 00000000..bb82ffa1
    --- /dev/null
    +++ b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoader.java
    @@ -0,0 +1,502 @@
    +// copy of https://github.com/SonarSource/sonar-plugin-api/blob/993f9bc9c6c7b671e0a8a14fdf4fb88c7b91e1ae/plugin-api/src/main/java/org/sonar/api/server/rule/RulesDefinitionXmlLoader.java
    +// Don't remove copyright below!
    +/*
    + * Sonar Plugin API
    + * Copyright (C) 2009-2025 SonarSource SA
    + * mailto:info AT sonarsource DOT com
    + *
    + * This program is free software; you can redistribute it and/or
    + * modify it under the terms of the GNU Lesser General Public
    + * License as published by the Free Software Foundation; either
    + * version 3 of the License, or (at your option) any later version.
    + *
    + * This program is distributed in the hope that it will be useful,
    + * but WITHOUT ANY WARRANTY; without even the implied warranty of
    + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    + * Lesser General Public License for more details.
    + *
    + * You should have received a copy of the GNU Lesser General Public License
    + * along with this program; if not, write to the Free Software Foundation,
    + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
    + */
    +
    +package org.sonar.plugins.pmd.rule;
    +
    +import org.apache.commons.io.ByteOrderMark;
    +import org.apache.commons.io.input.BOMInputStream;
    +import org.apache.commons.lang3.StringUtils;
    +import org.jetbrains.annotations.Nullable;
    +import org.sonar.api.ce.ComputeEngineSide;
    +import org.sonar.api.rule.RuleScope;
    +import org.sonar.api.rule.RuleStatus;
    +import org.sonar.api.rule.Severity;
    +import org.sonar.api.rules.RuleType;
    +import org.sonar.api.server.ServerSide;
    +import org.sonar.api.server.debt.DebtRemediationFunction;
    +import org.sonar.api.server.rule.RuleParamType;
    +import org.sonar.api.server.rule.RulesDefinition;
    +import org.sonar.check.Cardinality;
    +import org.sonarsource.api.sonarlint.SonarLintSide;
    +
    +import javax.xml.namespace.QName;
    +import javax.xml.stream.XMLEventReader;
    +import javax.xml.stream.XMLInputFactory;
    +import javax.xml.stream.XMLStreamException;
    +import javax.xml.stream.events.Attribute;
    +import javax.xml.stream.events.StartElement;
    +import javax.xml.stream.events.XMLEvent;
    +import java.io.IOException;
    +import java.io.InputStream;
    +import java.io.InputStreamReader;
    +import java.io.Reader;
    +import java.nio.charset.Charset;
    +import java.util.ArrayList;
    +import java.util.List;
    +import java.util.regex.Pattern;
    +
    +import static java.lang.String.format;
    +import static org.apache.commons.lang3.StringUtils.isNotBlank;
    +import static org.apache.commons.lang3.StringUtils.trim;
    +
    +/**
    + * Loads definitions of rules from a XML file.
    + *
    + * 

    Usage

    + *
    + * public class MyJsRulesDefinition implements RulesDefinition {
    + *
    + *   private static final String PATH = "my-js-rules.xml";
    + *   private final RulesDefinitionXmlLoader xmlLoader;
    + *
    + *   public MyJsRulesDefinition(RulesDefinitionXmlLoader xmlLoader) {
    + *     this.xmlLoader = xmlLoader;
    + *   }
    + *
    + *   {@literal @}Override
    + *   public void define(Context context) {
    + *     try (Reader reader = new InputStreamReader(getClass().getResourceAsStream(PATH), StandardCharsets.UTF_8)) {
    + *       NewRepository repository = context.createRepository("my_js", "js").setName("My Javascript Analyzer");
    + *       xmlLoader.load(repository, reader);
    + *       repository.done();
    + *     } catch (IOException e) {
    + *       throw new IllegalStateException(String.format("Fail to read file %s", PATH), e);
    + *     }
    + *   }
    + * }
    + * 
    + * + *

    XML Format

    + *
    + * <rules>
    + *   <rule>
    + *     <!-- Required key. Max length is 200 characters. -->
    + *     <key>the-rule-key</key>
    + *
    + *     <!-- Required name. Max length is 200 characters. -->
    + *     <name>The purpose of the rule</name>
    + *
    + *     <!-- Required description. No max length. -->
    + *     <description>
    + *       <![CDATA[The description]]>
    + *     </description>
    + *     <!-- Optional format of description. Supported values are HTML (default) and MARKDOWN. -->
    + *     <descriptionFormat>HTML</descriptionFormat>
    + *
    + *     <!-- Optional key for configuration of some rule engines -->
    + *     <internalKey>Checker/TreeWalker/LocalVariableName</internalKey>
    + *
    + *     <!-- Default severity when enabling the rule in a Quality profile.  -->
    + *     <!-- Possible values are INFO, MINOR, MAJOR (default), CRITICAL, BLOCKER. -->
    + *     <severity>BLOCKER</severity>
    + *
    + *     <!-- Possible values are SINGLE (default) and MULTIPLE for template rules -->
    + *     <cardinality>SINGLE</cardinality>
    + *
    + *     <!-- Status displayed in rules console. Possible values are BETA, READY (default), DEPRECATED. -->
    + *     <status>BETA</status>
    + *
    + *     <!-- Type as defined by the SonarQube Quality Model. Possible values are CODE_SMELL (default), BUG and VULNERABILITY.-->
    + *     <type>BUG</type>
    + *
    + *     <!-- Optional tags. See org.sonar.api.server.rule.RuleTagFormat. The maximal length of all tags is 4000 characters. -->
    + *     <tag>misra</tag>
    + *     <tag>multi-threading</tag>
    + *
    + *     <!-- Optional parameters -->
    + *     <param>
    + *       <!-- Required key. Max length is 128 characters. -->
    + *       <key>the-param-key</key>
    + *       <description>
    + *         <![CDATA[the optional description, in HTML format. Max length is 4000 characters.]]>
    + *       </description>
    + *       <!-- Optional default value, used when enabling the rule in a Quality profile. Max length is 4000 characters. -->
    + *       <defaultValue>42</defaultValue>
    + *     </param>
    + *     <param>
    + *       <key>another-param</key>
    + *     </param>
    + *
    + *     <!-- Quality Model - type of debt remediation function -->
    + *     <!-- See enum {@link org.sonar.api.server.debt.DebtRemediationFunction.Type} for supported values -->
    + *     <!-- It was previously named 'debtRemediationFunction'. -->
    + *     <!-- Since 5.5 -->
    + *     <remediationFunction>LINEAR_OFFSET</remediationFunction>
    + *
    + *     <!-- Quality Model - raw description of the "gap", used for some types of remediation functions. -->
    + *     <!-- See {@link org.sonar.api.server.rule.RulesDefinition.NewRule#setGapDescription(String)} -->
    + *     <!-- It was previously named 'effortToFixDescription'. -->
    + *     <!-- Since 5.5 -->
    + *     <gapDescription>Effort to test one uncovered condition</gapFixDescription>
    + *
    + *     <!-- Quality Model - gap multiplier of debt remediation function. Must be defined only for some function types. -->
    + *     <!-- See {@link org.sonar.api.server.rule.RulesDefinition.DebtRemediationFunctions} -->
    + *     <!-- It was previously named 'debtRemediationFunctionCoefficient'. -->
    + *     <!-- Since 5.5 -->
    + *     <remediationFunctionGapMultiplier>10min</remediationFunctionGapMultiplier>
    + *
    + *     <!-- Quality Model - base effort of debt remediation function. Must be defined only for some function types. -->
    + *     <!-- See {@link org.sonar.api.server.rule.RulesDefinition.DebtRemediationFunctions} -->
    + *     <!-- It was previously named 'debtRemediationFunctionOffset'. -->
    + *     <!-- Since 5.5 -->
    + *     <remediationFunctionBaseEffort>2min</remediationFunctionBaseEffort>
    + *
    + *     <!-- Deprecated field, replaced by "internalKey" -->
    + *     <configKey>Checker/TreeWalker/LocalVariableName</configKey>
    + *
    + *     <!-- Deprecated field, replaced by "severity" -->
    + *     <priority>BLOCKER</priority>
    + *
    + *   </rule>
    + * </rules>
    + * 
    + * + *

    XML Example

    + *
    + * <rules>
    + *   <rule>
    + *     <key>S1442</key>
    + *     <name>"alert(...)" should not be used</name>
    + *     <description>alert(...) can be useful for debugging during development, but ...</description>
    + *     <tag>cwe</tag>
    + *     <tag>security</tag>
    + *     <tag>user-experience</tag>
    + *     <debtRemediationFunction>CONSTANT_ISSUE</debtRemediationFunction>
    + *     <debtRemediationFunctionBaseOffset>10min</debtRemediationFunctionBaseOffset>
    + *   </rule>
    + *
    + *   <!-- another rules... -->
    + * </rules>
    + * 
    + * + * @see org.sonar.api.server.rule.RulesDefinition + * @since 4.3 + * + * Imported from Sonar Source. + */ +@ServerSide +@ComputeEngineSide +@SonarLintSide +public class RulesDefinitionXmlLoader { + + private static final String ELEMENT_RULES = "rules"; + private static final String ELEMENT_RULE = "rule"; + private static final String ELEMENT_PARAM = "param"; + private static final Pattern TEST_RULE_PATTERN = Pattern.compile("Test|JUnit", Pattern.CASE_INSENSITIVE); + private static final String TAG_TEST_SOURCES = "tests"; + private static final String TAG_MAIN_SOURCES = "main-sources"; + + private enum DescriptionFormat { + HTML, MARKDOWN + } + + /** + * Loads rules by reading the XML input stream. The input stream is not always closed by the method, so it + * should be handled by the caller. + * + * @since 4.3 + */ + public void load(RulesDefinition.NewRepository repo, InputStream input, String encoding) { + load(repo, input, Charset.forName(encoding)); + } + + /** + * @since 5.1 + */ + public void load(RulesDefinition.NewRepository repo, InputStream input, Charset charset) { + try (Reader reader = new InputStreamReader(new BOMInputStream(input, + ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE, ByteOrderMark.UTF_16BE, + ByteOrderMark.UTF_32LE, ByteOrderMark.UTF_32BE), charset)) { + load(repo, reader); + } catch (IOException e) { + throw new IllegalStateException("Error while reading XML rules definition for repository " + repo.key(), e); + } + } + + /** + * Loads rules by reading the XML input stream. The reader is not closed by the method, so it + * should be handled by the caller. + * + * @since 4.3 + */ + public void load(RulesDefinition.NewRepository repo, Reader inputReader) { + XMLInputFactory xmlFactory = XMLInputFactory.newInstance(); + xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE); + xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE); + // just so it won't try to load DTD in if there's DOCTYPE + xmlFactory.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE); + xmlFactory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE); + try { + final XMLEventReader reader = xmlFactory.createXMLEventReader(inputReader); + while (reader.hasNext()) { + final XMLEvent event = reader.nextEvent(); + if (event.isStartElement() && event.asStartElement().getName() + .getLocalPart().equals(ELEMENT_RULES)) { + parseRules(repo, reader); + } + } + } catch (XMLStreamException e) { + throw new IllegalStateException("XML is not valid", e); + } + } + + private static void parseRules(RulesDefinition.NewRepository repo, XMLEventReader reader) throws XMLStreamException { + while (reader.hasNext()) { + final XMLEvent event = reader.nextEvent(); + if (event.isEndElement() && event.asEndElement().getName().getLocalPart().equals(ELEMENT_RULES)) { + return; + } + if (event.isStartElement()) { + final StartElement element = event.asStartElement(); + final String elementName = element.getName().getLocalPart(); + if (ELEMENT_RULE.equals(elementName)) { + processRule(repo, element, reader); + } + } + } + } + + private static void processRule(RulesDefinition.NewRepository repo, StartElement ruleElement, XMLEventReader reader) throws XMLStreamException { + String key = null; + String name = null; + String description = null; + // enum is not used as variable type as we want to raise an exception with the rule key when format is not supported + String descriptionFormat = DescriptionFormat.HTML.name(); + String internalKey = null; + String severity = Severity.defaultSeverity(); + String type = null; + RuleStatus status = RuleStatus.defaultStatus(); + boolean template = false; + String gapDescription = null; + String debtRemediationFunction = null; + String debtRemediationFunctionGapMultiplier = null; + String debtRemediationFunctionBaseEffort = null; + List params = new ArrayList<>(); + List tags = new ArrayList<>(); + + /* BACKWARD COMPATIBILITY WITH VERY OLD FORMAT */ + Attribute keyAttribute = ruleElement.getAttributeByName(new QName("key")); + if (keyAttribute != null && StringUtils.isNotBlank(keyAttribute.getValue())) { + key = trim(keyAttribute.getValue()); + } + Attribute priorityAttribute = ruleElement.getAttributeByName(new QName("priority")); + if (priorityAttribute != null && StringUtils.isNotBlank(priorityAttribute.getValue())) { + severity = trim(priorityAttribute.getValue()); + } + + while (reader.hasNext()) { + final XMLEvent event = reader.nextEvent(); + if (event.isEndElement() && event.asEndElement().getName().getLocalPart().equals(ELEMENT_RULE)) { + buildRule(repo, key, name, description, descriptionFormat, internalKey, severity, type, status, template, + gapDescription, debtRemediationFunction, debtRemediationFunctionGapMultiplier, debtRemediationFunctionBaseEffort, params, tags); + return; + } + if (event.isStartElement()) { + final StartElement element = event.asStartElement(); + final String elementName = element.getName().getLocalPart(); + if ("name".equalsIgnoreCase(elementName)) { + name = StringUtils.trim(reader.getElementText()); + } else if ("type".equalsIgnoreCase(elementName)) { + type = StringUtils.trim(reader.getElementText()); + } else if ("description".equalsIgnoreCase(elementName)) { + description = StringUtils.trim(reader.getElementText()); + } else if ("descriptionFormat".equalsIgnoreCase(elementName)) { + descriptionFormat = StringUtils.trim(reader.getElementText()); + } else if ("key".equalsIgnoreCase(elementName)) { + key = StringUtils.trim(reader.getElementText()); + } else if ("configKey".equalsIgnoreCase(elementName)) { + // deprecated field, replaced by internalKey + internalKey = StringUtils.trim(reader.getElementText()); + } else if ("internalKey".equalsIgnoreCase(elementName)) { + internalKey = StringUtils.trim(reader.getElementText()); + } else if ("priority".equalsIgnoreCase(elementName) || "severity".equalsIgnoreCase(elementName)) { + // "priority" is deprecated field and has been replaced by "severity" + severity = StringUtils.trim(reader.getElementText()); + } else if ("cardinality".equalsIgnoreCase(elementName)) { + template = Cardinality.MULTIPLE == Cardinality.valueOf(StringUtils.trim(reader.getElementText())); + } else if ("gapDescription".equalsIgnoreCase(elementName) || "effortToFixDescription".equalsIgnoreCase(elementName)) { + gapDescription = StringUtils.trim(reader.getElementText()); + } else if ("remediationFunction".equalsIgnoreCase(elementName) || "debtRemediationFunction".equalsIgnoreCase(elementName)) { + debtRemediationFunction = StringUtils.trim(reader.getElementText()); + } else if ("remediationFunctionBaseEffort".equalsIgnoreCase(elementName) || "debtRemediationFunctionOffset".equalsIgnoreCase(elementName)) { + debtRemediationFunctionGapMultiplier = StringUtils.trim(reader.getElementText()); + } else if ("remediationFunctionGapMultiplier".equalsIgnoreCase(elementName) || "debtRemediationFunctionCoefficient".equalsIgnoreCase(elementName)) { + debtRemediationFunctionBaseEffort = StringUtils.trim(reader.getElementText()); + } else if ("status".equalsIgnoreCase(elementName)) { + String s = StringUtils.trim(reader.getElementText()); + if (s != null) { + status = RuleStatus.valueOf(s); + } + } else if (ELEMENT_PARAM.equalsIgnoreCase(elementName)) { + params.add(processParameter(element, reader)); + } else if ("tag".equalsIgnoreCase(elementName)) { + tags.add(trim(reader.getElementText())); + } + } + } + } + + private static void buildRule(RulesDefinition.NewRepository repo, String key, String name, @Nullable String description, + String descriptionFormat, @Nullable String internalKey, String severity, @Nullable String type, RuleStatus status, + boolean template, @Nullable String gapDescription, @Nullable String debtRemediationFunction, @Nullable String debtRemediationFunctionGapMultiplier, + @Nullable String debtRemediationFunctionBaseEffort, List params, List inputTags) { + try { + String[] ruleTags = determineSonarRuleTags(name, inputTags); + RulesDefinition.NewRule rule = repo.createRule(key) + .setSeverity(severity) + .setName(name) + .setInternalKey(internalKey) + .setTags(ruleTags) + .setTemplate(template) + .setStatus(status) + .setGapDescription(gapDescription); + if (type != null) { + rule.setType(RuleType.valueOf(type)); + } + rule.setScope(determineScope(name, inputTags)); + fillDescription(rule, descriptionFormat, description); + fillRemediationFunction(rule, debtRemediationFunction, debtRemediationFunctionGapMultiplier, debtRemediationFunctionBaseEffort); + fillParams(rule, params); + } catch (Exception e) { + throw new IllegalStateException(format("Fail to load the rule with key [%s:%s]", repo.key(), key), e); + } + } + + private static String[] determineSonarRuleTags(String name, List inputTags) { + List ruleTags = new ArrayList(inputTags); + boolean hasTagTests = ruleTags.contains(TAG_TEST_SOURCES); + boolean hasTagMainSources = ruleTags.contains(TAG_MAIN_SOURCES); + boolean nameMatchesTest = TEST_RULE_PATTERN.matcher(name).find(); + + if (nameMatchesTest) { + if (!hasTagMainSources && !hasTagTests) { // no override + ruleTags.add(TAG_TEST_SOURCES); + } else { + // main-sources or main-sources+tests tag used to override name matching + if (hasTagMainSources || (hasTagMainSources && hasTagTests)) { + // override name matching to non-test: main-sources or all-sources + ruleTags.remove(TAG_TEST_SOURCES); + } + } + } + // we filter out the 'main-sources' tag because it is only used to set/limit analysis scope; + // and not used in the rule tags of Sonar + ruleTags.remove(TAG_MAIN_SOURCES); + return ruleTags.toArray(new String[0]); + } + + /* default */ static RuleScope determineScope(String name, List tags) { + RuleScope scope = RuleScope.ALL; // default + boolean hasTagTests = tags.contains(TAG_TEST_SOURCES); + boolean hasTagMainSources = tags.contains(TAG_MAIN_SOURCES); + boolean nameMatchesTest = TEST_RULE_PATTERN.matcher(name).find(); + + if (hasTagTests || nameMatchesTest) { + if (!hasTagMainSources) { // if rule has both, it means ALL + scope = RuleScope.TEST; + } + } + if (hasTagMainSources && !hasTagTests) { // if rule has both, it means ALL + scope = RuleScope.MAIN; + } + return scope; + } + + @SuppressWarnings({"removal"}) + private static void fillDescription(RulesDefinition.NewRule rule, String descriptionFormat, @Nullable String description) { + if (isNotBlank(description)) { + switch (DescriptionFormat.valueOf(descriptionFormat)) { + case HTML: + rule.setHtmlDescription(description); + break; + case MARKDOWN: + rule.setMarkdownDescription(description); + break; + default: + throw new IllegalArgumentException("Value of descriptionFormat is not supported: " + descriptionFormat); + } + } + } + + private static void fillRemediationFunction(RulesDefinition.NewRule rule, @Nullable String debtRemediationFunction, + @Nullable String functionOffset, @Nullable String functionCoeff) { + if (isNotBlank(debtRemediationFunction)) { + DebtRemediationFunction.Type functionType = DebtRemediationFunction.Type.valueOf(debtRemediationFunction); + rule.setDebtRemediationFunction(rule.debtRemediationFunctions().create(functionType, functionCoeff, functionOffset)); + } + } + + private static void fillParams(RulesDefinition.NewRule rule, List params) { + for (ParamStruct param : params) { + rule.createParam(param.key) + .setDefaultValue(param.defaultValue) + .setType(param.type) + .setDescription(param.description); + } + } + + private static class ParamStruct { + + String key; + String description; + String defaultValue; + RuleParamType type = RuleParamType.STRING; + } + + private static ParamStruct processParameter(StartElement paramElement, XMLEventReader reader) throws XMLStreamException { + ParamStruct param = new ParamStruct(); + + // BACKWARD COMPATIBILITY WITH DEPRECATED FORMAT + Attribute keyAttribute = paramElement.getAttributeByName(new QName("key")); + if (keyAttribute != null && StringUtils.isNotBlank(keyAttribute.getValue())) { + param.key = StringUtils.trim(keyAttribute.getValue()); + } + + // BACKWARD COMPATIBILITY WITH DEPRECATED FORMAT + Attribute typeAttribute = paramElement.getAttributeByName(new QName("type")); + if (typeAttribute != null && StringUtils.isNotBlank(typeAttribute.getValue())) { + param.type = RuleParamType.parse(StringUtils.trim(typeAttribute.getValue())); + } + + while (reader.hasNext()) { + final XMLEvent event = reader.nextEvent(); + if (event.isEndElement() && event.asEndElement().getName().getLocalPart().equals(ELEMENT_PARAM)) { + return param; + } + if (event.isStartElement()) { + final StartElement element = event.asStartElement(); + final String elementName = element.getName().getLocalPart(); + if ("key".equalsIgnoreCase(elementName)) { + param.key = StringUtils.trim(reader.getElementText()); + } else if ("description".equalsIgnoreCase(elementName)) { + param.description = StringUtils.trim(reader.getElementText()); + } else if ("type".equalsIgnoreCase(elementName)) { + param.type = RuleParamType.parse(StringUtils.trim(reader.getElementText())); + } else if ("defaultValue".equalsIgnoreCase(elementName)) { + param.defaultValue = StringUtils.trim(reader.getElementText()); + } + } + } + return param; + } +} + diff --git a/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/util/PmdSeverityMapper.java b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/util/PmdSeverityMapper.java new file mode 100644 index 00000000..8df5a63d --- /dev/null +++ b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/util/PmdSeverityMapper.java @@ -0,0 +1,79 @@ +package org.sonar.plugins.pmd.rule.util; + +import org.sonar.api.rule.Severity; + +/** + * Utility to map PMD priority levels (1..5 as strings) to Sonar severity labels. + */ +public final class PmdSeverityMapper { + + private PmdSeverityMapper() { + // utility class + } + + /** + * Converts PMD priority ("1".."5") into Sonar severity string. + * + * @param pmdPriority PMD priority as string + * @param category Category of the PMD rule + * @return Sonar severity as defined by {@code org.sonar.api.rule.Severity} (BLOCKER, CRITICAL, MAJOR, MINOR, INFO). + * Defaults to "MAJOR" when the input is null/empty/unknown. + *

    + * Default Priority Mapping: + * For standard PMD rules, priorities are mapped as follows: + *

      + *
    • 1 → BLOCKER
    • + *
    • 2 → CRITICAL (aka HIGH)
    • + *
    • 3 → MAJOR (aka MEDIUM)
    • + *
    • 4 → MINOR (aka LOW)
    • + *
    • 5 → MINOR (aka LOW)
    • + *
    + *

    + * Code Style Priority Mapping: + * For PMD rules in the code style category, severities are reduced using this mapping: + *

      + *
    • 1, 2 → MAJOR (aka MEDIUM)
    • + *
    • 3, 4, 5 → MINOR (aka LOW)
    • + *
    + *

    + * Notes: + *

      + *
    • Recent Sonar renaming (MQR mode): CRITICAL → HIGH, MAJOR → MEDIUM, MINOR → LOW
    • + *
    • Deprecated API {@code org.sonar.check.Priority} - use {@code org.sonar.api.rule.Severity} instead
    • + *
    • Do not use {@code org.sonar.api.issue.impact.Severity} - contains LOW, MEDIUM, HIGH
    • + *
    + */ + public static String priorityToSeverity(String pmdPriority, String category) { + if (pmdPriority == null) { + return Severity.defaultSeverity(); + } + if (category != null && category.equals("codestyle")) { + switch (pmdPriority.trim()) { + case "1": + case "2": + return Severity.MAJOR; + case "3": + case "4": + case "5": + return Severity.MINOR; + default: + return Severity.defaultSeverity(); + } + } + else { + switch (pmdPriority.trim()) { + case "1": + return Severity.BLOCKER; + case "2": + return Severity.CRITICAL; + case "3": + return Severity.MAJOR; + case "4": + case "5": + return Severity.MINOR; + default: + return Severity.defaultSeverity(); + } + } + } +} diff --git a/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/util/RuleParamFormatter.java b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/util/RuleParamFormatter.java new file mode 100644 index 00000000..5da76e77 --- /dev/null +++ b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/util/RuleParamFormatter.java @@ -0,0 +1,139 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd.rule.util; + +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.Objects; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +/** + * Utility to format PMD rule parameter metadata (description, select lists, etc.). + */ +public final class RuleParamFormatter { + + private RuleParamFormatter() { + // utility + } + + // Precompiled, safe regex: + // - Possessive quantifiers (*+, ++) avoid backtracking on whitespace/content. + // - Atomic alternation (?>...) avoids backtracking between "Possible" and "Allowed". + // - Character class [^]]*+ guarantees linear scan inside brackets. + private static final Pattern VALUES_FRAGMENT_PATTERN = Pattern.compile( + "\\s*+(?:(?>Possible|Allowed))\\s++values:\\s*+\\[[^]]*+]\\.?+\\s*+", + Pattern.CASE_INSENSITIVE + ); + + /** + * Build a parameter description based on an existing XML description and/or a description + * from the extracted property info, and optionally append a standardized list of allowed values. + * + * @param existingPropDescription The description from PMD XML (if present). + * @param propInfoDescription The description coming from the PropertyInfo (fallback). + * @param acceptedValues Accepted values for the parameter (optional). + * @param multiple Whether multiple values can be selected. + * @return The normalized description text to include in the rules XML. + */ + public static String buildDescription(@Nullable String existingPropDescription, + @Nullable String propInfoDescription, + @Nullable List acceptedValues, + boolean multiple) { + String baseDesc = normalizeWhitespace(firstNonBlank(existingPropDescription, propInfoDescription, "")); + + boolean useSelect = acceptedValues != null && !acceptedValues.isEmpty(); + if (useSelect) { + // Remove any pre-existing Allowed/Possible values fragments to avoid duplication + baseDesc = VALUES_FRAGMENT_PATTERN.matcher(baseDesc).replaceAll(" ").trim(); + + // Normalize enum-like tokens to lowercase (e.g., ANYWHERE -> anywhere, ON_TYPE -> on_type) + List normalized = acceptedValues.stream() + .map(RuleParamFormatter::normalizeEnumToken) + .collect(Collectors.toList()); + + String suffix = multiple ? " Select one or more values." : " Select one of the values."; + String joinedValues = normalized.stream().filter(Objects::nonNull).collect(Collectors.joining(",")); + baseDesc = baseDesc + sentenceSeparator(baseDesc) + "Allowed values: [" + joinedValues + "]." + suffix; + } + + return baseDesc; + } + + /** + * Determines the sentence separator to append after the given text: + * - Returns "" if the text is empty + * - Returns " " if the text already ends with terminal punctuation (., !, ?) + * - Returns ". " otherwise + */ + private static String sentenceSeparator(String text) { + if (text == null || text.isEmpty()) { + return ""; + } + char last = text.charAt(text.length() - 1); + boolean endsWithTerminal = last == '.' || last == '!' || last == '?'; + return endsWithTerminal ? " " : ". "; + } + + + /** + * Construct the RuleParamType token for a select list. + * Example: SINGLE_SELECT_LIST,multiple=true,values="a,b,c" + */ + public static String buildSelectTypeToken(List acceptedValues, boolean multiple) { + List normalized = acceptedValues.stream() + .map(RuleParamFormatter::normalizeEnumToken) + .collect(Collectors.toList()); + String innerCsv = normalized.stream() + .map(v -> v == null ? "" : v.replace("\"", "\"\"")) + .collect(Collectors.joining(",")); + String valuesToken = '"' + innerCsv + '"'; + if (multiple) { + return "SINGLE_SELECT_LIST,multiple=true,values=" + valuesToken; + } + return "SINGLE_SELECT_LIST,values=" + valuesToken; + } + + private static String firstNonBlank(String a, String b, String fallback) { + if (a != null && !a.trim().isEmpty()) return a; + if (b != null && !b.trim().isEmpty()) return b; + return fallback; + } + + private static String normalizeWhitespace(String s) { + if (s == null) return ""; + return s.replaceAll("\\s+", " ").trim(); + } + + /** + * Normalize enum-like tokens: if the value is composed of uppercase letters, digits, and underscores, + * then convert it to lowercase (keeping underscores). This turns ANYWHERE -> anywhere and ON_TYPE -> on_type. + * Otherwise, return the value unchanged. + */ + public static String normalizeEnumToken(@Nullable String value) { + if (value == null) return null; + String v = value.trim(); + if (v.matches("[A-Z0-9_]+")) { + return v.toLowerCase(); + } + return v; + } +} diff --git a/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/util/ZipBombProtection.java b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/util/ZipBombProtection.java new file mode 100644 index 00000000..a7e89fc7 --- /dev/null +++ b/sonar-pmd-lib/src/main/java/org/sonar/plugins/pmd/rule/util/ZipBombProtection.java @@ -0,0 +1,86 @@ +package org.sonar.plugins.pmd.rule.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * Provides protective checks against ZIP bomb attacks when scanning JAR files. + * Extracted from JavaRulePropertyExtractor to isolate security-related logic. + */ +public final class ZipBombProtection { + private static final Logger LOGGER = LoggerFactory.getLogger(ZipBombProtection.class); + + // Security thresholds to prevent ZIP bomb attacks + private static final int THRESHOLD_ENTRIES = 10_000; + private static final int THRESHOLD_SIZE_BYTES = 10_000_000; // 10 MB + private static final double THRESHOLD_RATIO = 15; // Increased to accommodate legitimate JAR files + + private ZipBombProtection() { + // utility + } + + /** + * Scans the given jar file and enforces anti ZIP-bomb thresholds. + * If suspicious conditions are detected, throws PossibleZipBombException. + * + * @param jarFile The open JarFile to scan + * @param jarPath The file path of the jar (used for logging) + * @throws PossibleZipBombException when thresholds indicate a possible ZIP bomb + */ + @SuppressWarnings("java:S5042") + public static void scanJar(JarFile jarFile, File jarPath) throws PossibleZipBombException { + // Variables to track security thresholds for preventing ZIP bomb attacks + int totalEntryArchive = 0; + long totalSizeArchive = 0; + + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements() && totalEntryArchive < THRESHOLD_ENTRIES) { + totalEntryArchive++; + JarEntry entry = entries.nextElement(); + + // Check for ZIP bomb based on compression ratio + long size = entry.getSize(); + long compressedSize = entry.getCompressedSize(); + if (size > 0 && compressedSize > 0) { + double compressionRatio = (double) size / (double) compressedSize; + if (compressionRatio > THRESHOLD_RATIO) { + String msg = "Suspicious compression ratio detected in jar file: " + jarPath + + ", entry: " + entry.getName() + ", ratio: " + compressionRatio + + ". Possible ZIP bomb attack. Skipping rule extraction."; + LOGGER.error(msg); + throw new PossibleZipBombException(msg); + } + } + + // Track total uncompressed size + if (size > 0) { + totalSizeArchive += size; + } + if (totalSizeArchive > THRESHOLD_SIZE_BYTES) { + String msg = "Total uncompressed size exceeds threshold in jar file: " + jarPath + + ". Possible ZIP bomb attack. Skipping rule extraction."; + LOGGER.error(msg); + throw new PossibleZipBombException(msg); + } + } + + if (totalEntryArchive >= THRESHOLD_ENTRIES) { + String msg = "Too many entries in jar file: " + jarPath + + ". Possible ZIP bomb attack. Skipping rule extraction."; + LOGGER.error(msg); + throw new PossibleZipBombException(msg); + } + } + + public static class PossibleZipBombException extends IOException { + public PossibleZipBombException(String msg) { + super(msg); + } + } +} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoaderTest.java b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoaderTest.java similarity index 95% rename from sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoaderTest.java rename to sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoaderTest.java index 848457ab..0c00f808 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoaderTest.java +++ b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/ExternalDescriptionLoaderTest.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,7 +17,6 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - package org.sonar.plugins.pmd.rule; import java.net.URL; diff --git a/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/JavaRulePropertyExtractorTest.java b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/JavaRulePropertyExtractorTest.java new file mode 100644 index 00000000..4d792513 --- /dev/null +++ b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/JavaRulePropertyExtractorTest.java @@ -0,0 +1,163 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd.rule; + +import org.junit.jupiter.api.Test; +import org.sonar.plugins.pmd.rule.JavaRulePropertyExtractor.PropertyInfo; +import org.sonar.plugins.pmd.rule.util.ZipBombProtection; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class JavaRulePropertyExtractorTest { + + @Test + void shouldThrowOnHighlyCompressedJar() throws IOException { + // given + JavaRulePropertyExtractor extractor = new JavaRulePropertyExtractor(); + File jarFile = getHighlyCompressedJarPath(); + if (!jarFile.exists()) { + throw new IOException("Jar file " + jarFile + " does not exist."); + } + assertThatThrownBy(() -> extractor.extractProperties(jarFile)) + .isInstanceOf(ZipBombProtection.PossibleZipBombException.class); + } + + @Test + void shouldExtractPropertiesFromTestJar() throws IOException { + // given + JavaRulePropertyExtractor extractor = new JavaRulePropertyExtractor(); + File jarFile = getTestJarPath(); + + if (!jarFile.exists()) { + throw new IOException("Jar file " + jarFile + " does not exist."); + } + + // when + Map> properties = extractor.extractProperties(jarFile); + + // then + assertThat(properties.size()).isEqualTo(2); + + List propertyInfos = properties.get("com.example.rules.WithPropsRule"); + assertThat(propertyInfos.size()).isEqualTo(6); + assertThat(propertyInfos.stream().filter(p -> p.getName().equals("strProp")).findFirst().get().getType()).isEqualTo("String"); + assertThat(propertyInfos.stream().filter(p -> p.getName().equals("intProp")).findFirst().get().getType()).isEqualTo("Integer"); + assertThat(propertyInfos.stream().filter(p -> p.getName().equals("boolProp")).findFirst().get().getType()).isEqualTo("Boolean"); + assertThat(propertyInfos.stream().filter(p -> p.getName().equals("listStrProp")).findFirst().get().getType()).isEqualTo("ArrayList"); + + propertyInfos = properties.get("com.example.rules.WithoutPropsRule"); + // there are always 2 default properties, equal to type Optional + assertThat(propertyInfos.size()).isEqualTo(2); + assertThat(propertyInfos.stream().filter(p -> p.getName().equals("violationSuppressRegex")).findFirst().get().getType()).isEqualTo("Optional"); + assertThat(propertyInfos.stream().filter(p -> p.getName().equals("violationSuppressXPath")).findFirst().get().getType()).isEqualTo("Optional"); + } + + @Test + void shouldExtractPropertiesFromRealJar() throws IOException { + // given + JavaRulePropertyExtractor extractor = new JavaRulePropertyExtractor(); + File jarFile = getRealJarPath(); + + if (!jarFile.exists()) { + throw new IOException("Jar file " + jarFile + " does not exist."); + } + + // when + Map> properties = extractor.extractProperties(jarFile); + + // then + assertThat(properties.size()).isGreaterThan(100); + // Assert that all lists are non-null + assertThat(properties.values()).allMatch(Objects::nonNull); + // This core rule should not blow things up + assertThat(properties.get("net.sourceforge.pmd.lang.rule.impl.UnnecessaryPmdSuppressionRule")).isNotNull(); + + List propertyInfos = properties.get("net.sourceforge.pmd.lang.java.rule.errorprone.AvoidDuplicateLiteralsRule"); + assertThat(propertyInfos.size()).isEqualTo(6); + assertThat(propertyInfos.stream().filter(p -> p.getName().equals("maxDuplicateLiterals")).findFirst().get().getType()).isEqualTo("Integer"); + assertThat(propertyInfos.stream().filter(p -> p.getName().equals("skipAnnotations")).findFirst().get().getType()).isEqualTo("Boolean"); + assertThat(propertyInfos.stream().filter(p -> p.getName().equals("exceptionList")).findFirst().get().getType()).isEqualTo("Set"); + } + + @Test + void shouldHaveEmptyDefaultValues() { + // given + List defaultValues = Collections.emptyList(); + + // when + PropertyInfo propertyInfo = new PropertyInfo("testName", "Test Description", "STRING", defaultValues); + + // then + assertThat(propertyInfo.getName()).isEqualTo("testName"); + assertThat(propertyInfo.getDescription()).isEqualTo("Test Description"); + assertThat(propertyInfo.getType()).isEqualTo("STRING"); + assertThat(propertyInfo.getDefaultValues()).hasSize(0); + assertThat(propertyInfo.getDefaultValuesAsString()).isEqualTo(""); + } + + @Test + void propertyInfoShouldHandleDefaultValues() { + // given + List defaultValues = Arrays.asList("value1", "value2", "value3"); + + // when + PropertyInfo propertyInfo = new PropertyInfo("testName", "Test Description", "STRING", defaultValues); + + // then + assertThat(propertyInfo.getName()).isEqualTo("testName"); + assertThat(propertyInfo.getDescription()).isEqualTo("Test Description"); + assertThat(propertyInfo.getType()).isEqualTo("STRING"); + assertThat(propertyInfo.getDefaultValues()).containsExactly("value1", "value2", "value3"); + assertThat(propertyInfo.getDefaultValuesAsString()).isEqualTo("value1,value2,value3"); + } + + @Test + void propertyInfoShouldHandleEmptyDefaultValues() { + // given + List emptyList = List.of(); + + // when + PropertyInfo propertyInfo = new PropertyInfo("testName", "Test Description", "BOOLEAN", emptyList); + + // then + assertThat(propertyInfo.getName()).isEqualTo("testName"); + assertThat(propertyInfo.getDescription()).isEqualTo("Test Description"); + assertThat(propertyInfo.getType()).isEqualTo("BOOLEAN"); + assertThat(propertyInfo.getDefaultValues()).isEmpty(); + assertThat(propertyInfo.getDefaultValuesAsString()).isEmpty(); + } + + private File getTestJarPath() { + return new File(Objects.requireNonNull(this.getClass().getClassLoader().getResource("test-java-rule-extractor.jar")).getPath()); + } + + private File getHighlyCompressedJarPath() { + return new File(Objects.requireNonNull(this.getClass().getClassLoader().getResource("test-highly-compressed.jar")).getPath()); + } + + private File getRealJarPath() { + return new File(System.getProperty("user.home") + "/.m2/repository/net/sourceforge/pmd/pmd-java/7.17.0/pmd-java-7.17.0.jar"); + } +} \ No newline at end of file diff --git a/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/MarkdownToHtmlConverterGodClassDocTest.java b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/MarkdownToHtmlConverterGodClassDocTest.java new file mode 100644 index 00000000..58d20037 --- /dev/null +++ b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/MarkdownToHtmlConverterGodClassDocTest.java @@ -0,0 +1,75 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd.rule; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Reproduces the ordering issue as seen in the DataClass rule description. + * The second headline (paragraph) is placed before the first list. + */ +class MarkdownToHtmlConverterGodClassDocTest { + + @Test + void paragraphs_should_precede_their_respective_lists() { + String markdown = String.join("\n", + "The rule uses metrics to implement its detection strategy. The violation message", + "gives information about the values of these metrics:", + "* WMC: a class complexity measure for a class, see { jdoc java::lang.java.metrics.JavaMetrics#WEIGHED_METHOD_COUNT }", + "* WOC: a 'non-triviality' measure for a class, see { jdoc java::lang.java.metrics.JavaMetrics#WEIGHT_OF_CLASS }", + "* NOPA: number of public attributes, see { jdoc java::lang.java.metrics.JavaMetrics#NUMBER_OF_PUBLIC_FIELDS }", + "* NOAM: number of public accessor methods, see { jdoc java::lang.java.metrics.JavaMetrics#NUMBER_OF_ACCESSORS }", + "", + "The rule identifies a god class by looking for classes which have all of the following properties:", + "* High NOPA + NOAM", + "* Low WOC", + "* Low WMC" + ); + + String html = MarkdownToHtmlConverter.convertToHtml(markdown); + + // The expected correct order is: + //

    ...metrics...

    + //
      ...first list...
    + //

    ...identifies...

    + //
      ...second list...
    + int idxMetricsPara = html.indexOf("The rule uses metrics to implement its detection strategy."); + int idxFirstUl = html.indexOf("
      "); + int idxIdentifiesPara = html.indexOf("The rule identifies a god class by looking for classes which have all of the following properties:"); + int idxSecondUl = html.indexOf("
        ", idxFirstUl + 1); + + // Sanity: all parts must exist + assertThat(idxMetricsPara).isGreaterThanOrEqualTo(0); + assertThat(idxFirstUl).isGreaterThanOrEqualTo(0); + assertThat(idxIdentifiesPara).isGreaterThanOrEqualTo(0); + assertThat(idxSecondUl).isGreaterThanOrEqualTo(0); + + assertThat(idxFirstUl).as("Assert ordering: first list must come after first paragraph") + .isGreaterThan(idxMetricsPara); + + assertThat(idxIdentifiesPara).as("Second paragraph must come after first list") + .isGreaterThan(idxFirstUl); + + assertThat(idxSecondUl).as("And second list must come after second paragraph") + .isGreaterThan(idxIdentifiesPara); + } +} diff --git a/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/MarkdownToHtmlConverterTest.java b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/MarkdownToHtmlConverterTest.java new file mode 100644 index 00000000..1522ce16 --- /dev/null +++ b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/MarkdownToHtmlConverterTest.java @@ -0,0 +1,131 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd.rule; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +class MarkdownToHtmlConverterTest { + + @Test + void codeTagWithLanguageAttribute_isProtectedFromFormatting() { + String input = "See /*volatile */ example"; + String result = MarkdownToHtmlConverter.convertToHtml(input); + + assertThat(result) + .contains("/*volatile */") + .doesNotContain("volatile "); + } + + @Test + void camelCaseToReadable_preserves_NaN() { + assertThat(MarkdownToHtmlConverter.camelCaseToReadable("ComparisonWithNaN")) + .isEqualTo("Comparison with NaN"); + assertThat(MarkdownToHtmlConverter.camelCaseToReadable("isNaN")) + .isEqualTo("Is NaN"); + } + + @Test + void testBackticksConvertToPreBlocks() { + String input = "By default, the comment must be `/* default */` or `/* package */`,"; + String result = MarkdownToHtmlConverter.convertToHtml(input); + + assertThat(result) + .contains("/* default */") + .contains("/* package */") + .doesNotContain("/ default /") + .doesNotContain("/ package /"); + } + + @Test + void testPlaceholderVariablesInBackticks() { + // Simulate the scenario where placeholder processing has already converted {0} to {0} + // and then backticks are processed + String messageWithPlaceholders = "Do not use `new {0}(...)`, prefer `{0}.valueOf(...)`"; + String result = MarkdownToHtmlConverter.convertToHtml(messageWithPlaceholders); + + assertThat(result) + .contains("new {0}(...)") + .contains("{0}.valueOf(...)") + .doesNotContain("{0}") // No nested code tags + .doesNotContain("

        "); // Should be in single paragraph + } + + @Test + void testBackticksDoNotProcessInsideExistingCodeBlocks() { + String input = "Use some `backticks` here and also `standalone backticks`"; + String result = MarkdownToHtmlConverter.convertToHtml(input); + + assertThat(result) + .contains("some `backticks` here") // Backticks preserved inside existing code + .contains("standalone backticks"); // Standalone backticks converted + } + + @Test + void testBackticksDoNotProcessInsidePreBlocks() { + String input = "Here is some `backticks` in pre and `standalone`"; + String result = MarkdownToHtmlConverter.convertToHtml(input); + + assertThat(result) + .contains("some `backticks` in pre") // Backticks preserved inside pre + .contains("standalone"); // Standalone backticks converted + } + + @Test + void testBackticksWithSpecialCharacters() { + String input = "Use `String.valueOf(\"test\")` method"; + String result = MarkdownToHtmlConverter.convertToHtml(input); + + assertThat(result) + .contains("String.valueOf("test")"); + } + + @Test + void testMultipleBackticksInSameParagraph() { + String input = "Compare `methodA()` with `methodB()` for differences"; + String result = MarkdownToHtmlConverter.convertToHtml(input); + + assertThat(result) + .contains("methodA()") + .contains("methodB()"); + } + + @Test + void testEmptyBackticks() { + String input = "Empty backticks `` should be handled"; + String result = MarkdownToHtmlConverter.convertToHtml(input); + + assertThat(result) + .contains(""); + } + + @Test + void testBackticksWithMarkdownFormatting() { + String input = "The `*bold*` and `_italic_` should not be processed inside backticks"; + String result = MarkdownToHtmlConverter.convertToHtml(input); + + assertThat(result) + .contains("*bold*") + .contains("_italic_") + .doesNotContain("bold") + .doesNotContain("italic"); + } +} \ No newline at end of file diff --git a/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/PmdRuleScopeRegistryTest.java b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/PmdRuleScopeRegistryTest.java new file mode 100644 index 00000000..0786490e --- /dev/null +++ b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/PmdRuleScopeRegistryTest.java @@ -0,0 +1,62 @@ +package org.sonar.plugins.pmd.rule; + +import org.junit.jupiter.api.Test; +import org.sonar.api.rule.RuleScope; + +import java.net.URL; + +import static org.assertj.core.api.Assertions.assertThat; + +class PmdRuleScopeRegistryTest { + + @Test + void parses_rule_scopes_from_attribute_key_and_alternative_elements() { + URL url = getClass().getResource("/org/sonar/plugins/pmd/rule/test-jpinpoint.xml"); + assertThat(url).as("test resource should exist").isNotNull(); + + PmdRuleScopeRegistry registry = new PmdRuleScopeRegistry(); + registry.addXmlUrls(url); + + // JP0001 has , <name> containing 'Test' and <tag>tests</tag> + assertThat(registry.getScope("JP0001")).isEqualTo(RuleScope.TEST); + // JP0002 has <tags>main-sources, performance</tags> + assertThat(registry.getScope("JP0002")).isEqualTo(RuleScope.MAIN); + } + + @Test + void parses_sample_jpinpoint_xml_with_nested_cdata_descriptions() { + URL url = getClass().getResource("/org/sonar/plugins/pmd/rule/test-jpinpoint-sample.xml"); + assertThat(url).as("sample test resource should exist").isNotNull(); + + PmdRuleScopeRegistry registry = new PmdRuleScopeRegistry(); + registry.addXmlUrls(url); + + // Both rules don't have explicit test/main tags; default scope should fall back to ALL + assertThat(registry.getScope("AvoidCDIReferenceLeak")).isEqualTo(RuleScope.ALL); + assertThat(registry.getScope("AvoidCalendar")).isEqualTo(RuleScope.ALL); + } + + @Test + void parses_rules_with_default_namespace_and_no_xml_header() { + URL url = getClass().getResource("/org/sonar/plugins/pmd/rule/test-rules-default-ns-no-header.xml"); + assertThat(url).as("resource with default namespace & no header should exist").isNotNull(); + + PmdRuleScopeRegistry registry = new PmdRuleScopeRegistry(); + registry.addXmlUrls(url); + + assertThat(registry.getScope("NS001")).isEqualTo(RuleScope.TEST); + assertThat(registry.getScope("NS002")).isEqualTo(RuleScope.MAIN); + } + + @Test + void parses_rules_with_prefixed_namespace_and_with_header() { + URL url = getClass().getResource("/org/sonar/plugins/pmd/rule/test-rules-prefixed-ns-with-header.xml"); + assertThat(url).as("resource with prefixed namespace & header should exist").isNotNull(); + + PmdRuleScopeRegistry registry = new PmdRuleScopeRegistry(); + registry.addXmlUrls(url); + + assertThat(registry.getScope("NSP001")).isEqualTo(RuleScope.TEST); + assertThat(registry.getScope("NSP002")).isEqualTo(RuleScope.MAIN); + } +} diff --git a/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest.java b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest.java new file mode 100644 index 00000000..1f09fd2a --- /dev/null +++ b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest.java @@ -0,0 +1,484 @@ +// copy of https://github.com/SonarSource/sonar-plugin-api/blob/993f9bc9c6c7b671e0a8a14fdf4fb88c7b91e1ae/plugin-api/src/test/java/org/sonar/api/server/rule/RulesDefinitionXmlLoaderTest.java +// Don't remove copyright below! + +/* + * Sonar Plugin API + * Copyright (C) 2009-2025 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.plugins.pmd.rule; + +import java.io.InputStream; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import org.apache.commons.io.IOUtils; +import org.junit.jupiter.api.Test; +import org.sonar.api.rule.RuleScope; +import org.sonar.api.rule.RuleStatus; +import org.sonar.api.rule.Severity; +import org.sonar.api.rules.RuleType; +import org.sonar.api.server.debt.DebtRemediationFunction; +import org.sonar.api.server.impl.RulesDefinitionContext; +import org.sonar.api.server.rule.RulesDefinition; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +public class RulesDefinitionXmlLoaderTest { + + public static final Charset ENCODING = StandardCharsets.UTF_8; + public static final String ENCODING_NAME = ENCODING.name(); + RulesDefinitionXmlLoader underTest = new RulesDefinitionXmlLoader(); + + @Test + public void parse_xml() { + InputStream input = getClass().getResourceAsStream("RulesDefinitionXmlLoaderTest/rules.xml"); + RulesDefinition.Repository repository = load(input, ENCODING_NAME); + assertThat(repository.rules()).hasSize(2); + + RulesDefinition.Rule rule = repository.rule("complete"); + assertThat(rule.key()).isEqualTo("complete"); + assertThat(rule.name()).isEqualTo("Complete"); + assertThat(rule.htmlDescription()).isEqualTo("Description of Complete"); + assertThat(rule.severity()).isEqualTo(Severity.BLOCKER); + assertThat(rule.template()).isTrue(); + assertThat(rule.status()).isEqualTo(RuleStatus.BETA); + assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/LocalVariableName"); + assertThat(rule.type()).isEqualTo(RuleType.BUG); + assertThat(rule.tags()).containsOnly("misra", "spring"); + + assertThat(rule.params()).hasSize(2); + RulesDefinition.Param ignore = rule.param("ignore"); + assertThat(ignore.key()).isEqualTo("ignore"); + assertThat(ignore.description()).isEqualTo("Ignore ?"); + assertThat(ignore.defaultValue()).isEqualTo("false"); + + rule = repository.rule("minimal"); + assertThat(rule.key()).isEqualTo("minimal"); + assertThat(rule.name()).isEqualTo("Minimal"); + assertThat(rule.htmlDescription()).isEqualTo("Description of Minimal"); + assertThat(rule.params()).isEmpty(); + assertThat(rule.status()).isEqualTo(RuleStatus.READY); + assertThat(rule.severity()).isEqualTo(Severity.MAJOR); + assertThat(rule.type()).isEqualTo(RuleType.CODE_SMELL); + } + + @Test + public void fail_if_missing_rule_key() { + assertThatThrownBy(() -> load(IOUtils.toInputStream("<rules><rule><name>Foo</name></rule></rules>", ENCODING), ENCODING_NAME)) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void fail_if_missing_property_key() { + assertThatThrownBy(() -> load(IOUtils.toInputStream("<rules><rule><key>foo</key><name>Foo</name><param></param></rule></rules>", ENCODING), + ENCODING_NAME)) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void fail_on_invalid_rule_parameter_type() { + assertThatThrownBy(() -> load(IOUtils.toInputStream("<rules><rule><key>foo</key><name>Foo</name><param><key>key</key><type>INVALID</type></param></rule></rules>", ENCODING_NAME), + ENCODING_NAME)) + .isInstanceOf(IllegalStateException.class); + } + + @Test + public void fail_if_invalid_xml() { + InputStream input = getClass().getResourceAsStream("RulesDefinitionXmlLoaderTest/invalid.xml"); + + assertThatThrownBy(() -> load(input, ENCODING_NAME)) + .isInstanceOf(IllegalStateException.class) + .hasMessage("XML is not valid"); + } + + @Test + public void test_utf8_encoding() { + InputStream input = getClass().getResourceAsStream("RulesDefinitionXmlLoaderTest/utf8.xml"); + RulesDefinition.Repository repository = load(input, ENCODING_NAME); + + assertThat(repository.rules()).hasSize(1); + RulesDefinition.Rule rule = repository.rules().get(0); + assertThat(rule.key()).isEqualTo("com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck"); + assertThat(rule.name()).isEqualTo("M & M"); + assertThat(rule.htmlDescription().charAt(0)).isEqualTo('\u00E9'); + assertThat(rule.htmlDescription().charAt(1)).isEqualTo('\u00E0'); + assertThat(rule.htmlDescription().charAt(2)).isEqualTo('\u0026'); + } + + @Test + public void test_utf8_encoding_with_bom() { + InputStream input = getClass().getResourceAsStream("RulesDefinitionXmlLoaderTest/utf8-with-bom.xml"); + RulesDefinition.Repository repository = load(input, ENCODING_NAME); + + assertThat(repository.rules()).hasSize(1); + RulesDefinition.Rule rule = repository.rules().get(0); + assertThat(rule.key()).isEqualTo("com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck"); + assertThat(rule.name()).isEqualTo("M & M"); + assertThat(rule.htmlDescription().charAt(0)).isEqualTo('\u00E9'); + assertThat(rule.htmlDescription().charAt(1)).isEqualTo('\u00E0'); + assertThat(rule.htmlDescription().charAt(2)).isEqualTo('\u0026'); + } + + @Test + public void support_deprecated_format() { + // the deprecated format uses some attributes instead of nodes + InputStream input = getClass().getResourceAsStream("RulesDefinitionXmlLoaderTest/deprecated.xml"); + RulesDefinition.Repository repository = load(input, ENCODING_NAME); + + assertThat(repository.rules()).hasSize(1); + RulesDefinition.Rule rule = repository.rules().get(0); + assertThat(rule.key()).isEqualTo("org.sonar.it.checkstyle.MethodsCountCheck"); + assertThat(rule.internalKey()).isEqualTo("Checker/TreeWalker/org.sonar.it.checkstyle.MethodsCountCheck"); + assertThat(rule.severity()).isEqualTo(Severity.CRITICAL); + assertThat(rule.htmlDescription()).isEqualTo("Count methods"); + assertThat(rule.param("minMethodsCount")).isNotNull(); + } + + @Test + public void test_linear_remediation_function() { + String xml = "" + + "<rules>" + + " <rule>" + + " <key>1</key>" + + " <name>One</name>" + + " <description>Desc</description>" + + + " <gapDescription>lines</gapDescription>" + + " <remediationFunction>LINEAR</remediationFunction>" + + " <remediationFunctionGapMultiplier>2d 3h</remediationFunctionGapMultiplier>" + + " </rule>" + + "</rules>"; + RulesDefinition.Rule rule = load(xml).rule("1"); + assertThat(rule.gapDescription()).isEqualTo("lines"); + DebtRemediationFunction function = rule.debtRemediationFunction(); + assertThat(function).isNotNull(); + assertThat(function.type()).isEqualTo(DebtRemediationFunction.Type.LINEAR); + assertThat(function.gapMultiplier()).isEqualTo("2d3h"); + assertThat(function.baseEffort()).isNull(); + } + + @Test + public void test_linear_with_offset_remediation_function() { + String xml = "" + + "<rules>" + + " <rule>" + + " <key>1</key>" + + " <name>One</name>" + + " <description>Desc</description>" + + + " <effortToFixDescription>lines</effortToFixDescription>" + + " <remediationFunction>LINEAR_OFFSET</remediationFunction>" + + " <remediationFunctionGapMultiplier>2d 3h</remediationFunctionGapMultiplier>" + + " <remediationFunctionBaseEffort>5min</remediationFunctionBaseEffort>" + + " </rule>" + + "</rules>"; + RulesDefinition.Rule rule = load(xml).rule("1"); + assertThat(rule.gapDescription()).isEqualTo("lines"); + DebtRemediationFunction function = rule.debtRemediationFunction(); + assertThat(function).isNotNull(); + assertThat(function.type()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET); + assertThat(function.gapMultiplier()).isEqualTo("2d3h"); + assertThat(function.baseEffort()).isEqualTo("5min"); + } + + @Test + public void test_constant_remediation_function() { + String xml = "" + + "<rules>" + + " <rule>" + + " <key>1</key>" + + " <name>One</name>" + + " <description>Desc</description>" + + " <remediationFunction>CONSTANT_ISSUE</remediationFunction>" + + " <remediationFunctionBaseEffort>5min</remediationFunctionBaseEffort>" + + " </rule>" + + "</rules>"; + RulesDefinition.Rule rule = load(xml).rule("1"); + DebtRemediationFunction function = rule.debtRemediationFunction(); + assertThat(function).isNotNull(); + assertThat(function.type()).isEqualTo(DebtRemediationFunction.Type.CONSTANT_ISSUE); + assertThat(function.gapMultiplier()).isNull(); + assertThat(function.baseEffort()).isEqualTo("5min"); + } + + @Test + public void fail_if_invalid_remediation_function() { + assertThatThrownBy(() -> load("" + + "<rules>" + + " <rule>" + + " <key>1</key>" + + " <name>One</name>" + + " <description>Desc</description>" + + " <remediationFunction>UNKNOWN</remediationFunction>" + + " </rule>" + + "</rules>")) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Fail to load the rule with key [squid:1]") + .hasCauseInstanceOf(IllegalArgumentException.class) + .hasRootCauseMessage("No enum constant org.sonar.api.server.debt.DebtRemediationFunction.Type.UNKNOWN"); + } + + @Test + @SuppressWarnings({"removal"}) + public void markdown_description() { + String xml = "" + + "<rules>" + + " <rule>" + + " <key>1</key>" + + " <name>One</name>" + + " <description>Desc</description>" + + " <descriptionFormat>MARKDOWN</descriptionFormat>" + + " </rule>" + + "</rules>"; + RulesDefinition.Rule rule = load(xml).rule("1"); + assertThat(rule.markdownDescription()).isEqualTo("Desc"); + assertThat(rule.htmlDescription()).isNull(); + } + + @Test + public void fail_if_unsupported_description_format() { + String xml = "" + + "<rules>" + + " <rule>" + + " <key>1</key>" + + " <name>One</name>" + + " <description>Desc</description>" + + " <descriptionFormat>UNKNOWN</descriptionFormat>" + + " </rule>" + + "</rules>"; + + assertThatThrownBy(() -> load(xml).rule("1")) + .isInstanceOf(IllegalStateException.class) + .hasMessage("Fail to load the rule with key [squid:1]") + .hasCauseInstanceOf(IllegalArgumentException.class) + .hasRootCauseMessage("No enum constant org.sonar.plugins.pmd.rule.RulesDefinitionXmlLoader.DescriptionFormat.UNKNOWN"); + } + + @Test + public void test_deprecated_remediation_function() { + String xml = "" + + "<rules>" + + " <rule>" + + " <key>1</key>" + + " <name>One</name>" + + " <description>Desc</description>" + + " <effortToFixDescription>lines</effortToFixDescription>" + + " <debtRemediationFunction>LINEAR_OFFSET</debtRemediationFunction>" + + " <debtRemediationFunctionCoefficient>2d 3h</debtRemediationFunctionCoefficient>" + + " <debtRemediationFunctionOffset>5min</debtRemediationFunctionOffset>" + + " </rule>" + + "</rules>"; + RulesDefinition.Rule rule = load(xml).rule("1"); + assertThat(rule.gapDescription()).isEqualTo("lines"); + DebtRemediationFunction function = rule.debtRemediationFunction(); + assertThat(function).isNotNull(); + assertThat(function.type()).isEqualTo(DebtRemediationFunction.Type.LINEAR_OFFSET); + assertThat(function.gapMultiplier()).isEqualTo("2d3h"); + assertThat(function.baseEffort()).isEqualTo("5min"); + } + + @Test + public void test_filter_non_sonar_tags() { + String xml = "" + + "<rules>" + + "<rule>" + + "<key>rule-non-sonar-tags-test</key>" + + "<name>Rule non Sonar Tags</name>" + + "<description>Rule to check filtering of non Sonar tags</description>" + + "<type>BUG</type>" + + "<tag>tests</tag>" + + "<tag>main-sources</tag>" + + "</rule>" + + "</rules>"; + + RulesDefinition.Repository rulesRepo = load(xml); + RulesDefinition.Rule nonSonarTags = rulesRepo.rule("rule-non-sonar-tags-test"); + + assertThat(nonSonarTags.tags()) + .withFailMessage("Should not contain main-sources") + .containsOnly("tests"); + + } + + @Test + public void test_add_remove_tests_tag_on_name_match() { + String xml = "" + + "<rules>" + + "<rule>" + + "<key>rule-tests_tag_on_name_match_1</key>" + + "<name>Rule add tests tag Test</name>" + + "<description>Rule to check adding tests tag on name match</description>" + + "<type>BUG</type>" + + "</rule>" + + + "<rule>" + + "<key>rule-tests_tag_on_name_match_2</key>" + + "<name>Rule NO add tests tag Test</name>" + + "<description>Rule to check NO adding tests tag on name match</description>" + + "<type>BUG</type>" + + "<tag>main-sources</tag>" + + "</rule>" + + + "<rule>" + + "<key>rule-tests_tag_on_name_match_3</key>" + + "<name>Rule remove tests tag Test</name>" + + "<description>Rule to check remove tests tag on name match override</description>" + + "<type>BUG</type>" + + "<tag>tests</tag>" + + "<tag>main-sources</tag>" + + "</rule>" + + "</rules>"; + + RulesDefinition.Repository rulesRepo = load(xml); + RulesDefinition.Rule addTests1 = rulesRepo.rule("rule-tests_tag_on_name_match_1"); + + assertThat(addTests1.tags()) + .withFailMessage("Should add tests tag") + .containsOnly("tests"); + + RulesDefinition.Rule addTests2 = rulesRepo.rule("rule-tests_tag_on_name_match_2"); + + assertThat(addTests2.tags()) + .withFailMessage("Should NOT add tests tag") + .doesNotContain("tests"); + + RulesDefinition.Rule addTests3 = rulesRepo.rule("rule-tests_tag_on_name_match_3"); + + assertThat(addTests3.tags()) + .withFailMessage("Should remove tests tag") + .doesNotContain("tests"); + } + + @Test + public void test_analysis_scope() { + String xml = "" + + "<rules>" + + "<rule>" + + "<key>Rule00</key>" + + "<name>Rule 00</name>" + + "<description>Description of rule 00</description>" + + "<type>BUG</type>" + + "</rule>" + + + "<rule>" + + "<key>Rule01</key>" + + "<name>Test rule 01</name>" + + "<description>Description</description>" + + "<type>BUG</type>" + + "</rule>" + + + "<rule>" + + "<key>Rule02</key>" + + "<name>Rule 02</name>" + + "<description>Description</description>" + + "<type>CODE_SMELL</type>" + + "<tag>tests</tag>" + + "</rule>" + + + "<rule>" + + "<key>Rule03</key>" + + "<name>Main rule 03</name>" + + "<description>Description</description>" + + "<type>CODE_SMELL</type>" + + "<tag>main-sources</tag>" + + "</rule>" + + + "<rule>" + + "<key>Rule04</key>" + + "<name>Rule 04</name>" + + "<description>Description</description>" + + "<type>CODE_SMELL</type>" + + "<tag>main-sources</tag>" + + "<tag>tests</tag>" + + "</rule>" + + + "<rule>" + + "<key>Rule05</key>" + + "<name>Rule 05</name>" + + "<description>Description</description>" + + "<severity>MAJOR</severity>" + + "<type>CODE_SMELL</type>" + + "<tag>test</tag>" + // wrong tag so ALL + "</rule>" + + + "<rule>" + + "<key>Rule06</key>" + + "<name>Rule Not Test But Main 06</name>" + + "<description>Description</description>" + + "<severity>MAJOR</severity>" + + "<type>CODE_SMELL</type>" + + "<tag>main-sources</tag>" + // override the name containing Test, make it Main + "</rule>" + + + "<rule>" + + "<key>Rule07</key>" + + "<name>Rule Not Test But All 07</name>" + + "<description>Description</description>" + + "<severity>MAJOR</severity>" + + "<type>CODE_SMELL</type>" + + "<tag>main-sources</tag>" + // override the name containing Test + "<tag>tests</tag>" + // make it both, main-sources and test -> All + "</rule>" + + + "<rule>" + + "<key>Rule08</key>" + + "<name>Rule for junit</name>" + + "<description>Description</description>" + + "<severity>MAJOR</severity>" + + "<type>CODE_SMELL</type>" + + "</rule>" + + "</rules>"; + RulesDefinition.Repository rulesRepo = load(xml); + RulesDefinition.Rule rule0 = rulesRepo.rule("Rule00"); + assertThat(rule0.scope()).isEqualTo(RuleScope.ALL); + RulesDefinition.Rule rule1 = rulesRepo.rule("Rule01"); + assertThat(rule1.scope()).isEqualTo(RuleScope.TEST); + RulesDefinition.Rule rule2 = rulesRepo.rule("Rule02"); + assertThat(rule2.scope()).isEqualTo(RuleScope.TEST); + RulesDefinition.Rule rule3 = rulesRepo.rule("Rule03"); + assertThat(rule3.scope()).isEqualTo(RuleScope.MAIN); + RulesDefinition.Rule rule4 = rulesRepo.rule("Rule04"); + assertThat(rule4.scope()).isEqualTo(RuleScope.ALL); + RulesDefinition.Rule rule5 = rulesRepo.rule("Rule05"); + assertThat(rule5.scope()).isEqualTo(RuleScope.ALL); + RulesDefinition.Rule rule6 = rulesRepo.rule("Rule06"); + assertThat(rule6.scope()).isEqualTo(RuleScope.MAIN); + RulesDefinition.Rule rule7 = rulesRepo.rule("Rule07"); + assertThat(rule7.scope()).isEqualTo(RuleScope.ALL); + RulesDefinition.Rule rule8 = rulesRepo.rule("Rule08"); + assertThat(rule8.scope()).isEqualTo(RuleScope.TEST); + } + + private RulesDefinition.Repository load(InputStream input, String encoding) { + RulesDefinition.Context context = new RulesDefinitionContext(); + RulesDefinition.NewRepository newRepository = context.createRepository("squid", "java"); + underTest.load(newRepository, input, encoding); + newRepository.done(); + return context.repository("squid"); + } + + private RulesDefinition.Repository load(String xml) { + RulesDefinition.Context context = new RulesDefinitionContext(); + RulesDefinition.NewRepository newRepository = context.createRepository("squid", "java"); + underTest.load(newRepository, new StringReader(xml)); + newRepository.done(); + return context.repository("squid"); + } +} diff --git a/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/util/RuleParamFormatterTest.java b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/util/RuleParamFormatterTest.java new file mode 100644 index 00000000..388b30d8 --- /dev/null +++ b/sonar-pmd-lib/src/test/java/org/sonar/plugins/pmd/rule/util/RuleParamFormatterTest.java @@ -0,0 +1,61 @@ +/* + * SonarQube PMD7 Plugin + */ +package org.sonar.plugins.pmd.rule.util; + +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class RuleParamFormatterTest { + + @Test + void buildDescription_removesExistingAllowedValues_andAppendsStandardized_single() { + String existing = "Some description. Allowed values: [x, y]. Extra."; + String fromPropInfo = null; + List<String> accepted = Arrays.asList("A","B","C"); + + String result = RuleParamFormatter.buildDescription(existing, fromPropInfo, accepted, false); + + assertThat(result) + .isEqualTo("Some description. Extra. Allowed values: [a,b,c]. Select one of the values."); + } + + @Test + void buildDescription_addsPunctuation_ifMissing_multiple() { + String existing = "Pick values"; // no punctuation + String fromPropInfo = "ignored"; + List<String> accepted = Arrays.asList("x","y"); + + String result = RuleParamFormatter.buildDescription(existing, fromPropInfo, accepted, true); + + assertThat(result) + .isEqualTo("Pick values. Allowed values: [x,y]. Select one or more values."); + } + + @Test + void buildDescription_usesPropInfo_whenExistingBlank_and_noSelect() { + String existing = " "; + String fromPropInfo = "Base description"; + + String result = RuleParamFormatter.buildDescription(existing, fromPropInfo, null, false); + + assertThat(result).isEqualTo("Base description"); + } + + @Test + void buildSelectTypeToken_singleAndMultiple() { + List<String> accepted = Arrays.asList("a","b,c","d\"e"); + + String single = RuleParamFormatter.buildSelectTypeToken(accepted, false); + String multi = RuleParamFormatter.buildSelectTypeToken(accepted, true); + + assertThat(single) + .isEqualTo("SINGLE_SELECT_LIST,values=\"a,b,c,d\"\"e\""); + assertThat(multi) + .isEqualTo("SINGLE_SELECT_LIST,multiple=true,values=\"a,b,c,d\"\"e\""); + } +} diff --git a/sonar-pmd-plugin/src/test/resources/org/sonar/l10n/languageKey/rules/repoKey/ruleWithExternalInfo.html b/sonar-pmd-lib/src/test/resources/org/sonar/l10n/languageKey/rules/repoKey/ruleWithExternalInfo.html similarity index 100% rename from sonar-pmd-plugin/src/test/resources/org/sonar/l10n/languageKey/rules/repoKey/ruleWithExternalInfo.html rename to sonar-pmd-lib/src/test/resources/org/sonar/l10n/languageKey/rules/repoKey/ruleWithExternalInfo.html diff --git a/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/deprecated.xml b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/deprecated.xml new file mode 100644 index 00000000..5734abd4 --- /dev/null +++ b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/deprecated.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rules> + <rule key="org.sonar.it.checkstyle.MethodsCountCheck" priority="CRITICAL"> + <configKey>Checker/TreeWalker/org.sonar.it.checkstyle.MethodsCountCheck</configKey> + <name>Count methods</name> + <description>Count methods</description> + <param key="minMethodsCount" description="Minimum number of methods"> + <defaultValue>2</defaultValue> + </param> + </rule> +</rules> diff --git a/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/invalid.xml b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/invalid.xml new file mode 100644 index 00000000..0484ea0c --- /dev/null +++ b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/invalid.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rules> + <rule> + <key>invalid</key> + <name>Invalid</name> + <description>Invalid XML file</description> + <unclosed-tag> + </rule> +</rules> diff --git a/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/rules.xml b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/rules.xml new file mode 100644 index 00000000..0f720f57 --- /dev/null +++ b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/rules.xml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rules> + <rule> + <key>complete</key> + <name>Complete</name> + <description>Description of Complete</description> + <internalKey>Checker/TreeWalker/LocalVariableName</internalKey> + <severity>BLOCKER</severity> + <type>BUG</type> + <status>BETA</status> + <tag>misra</tag> + <tag>spring</tag> + <cardinality>MULTIPLE</cardinality> + <param> + <key>ignore</key> + <description>Ignore ?</description> + <defaultValue>false</defaultValue> + </param> + <param> + <key>format</key> + <description>Format</description> + <defaultValue>^[a-z][a-zA-Z0-9]*$</defaultValue> + </param> + </rule> + <rule> + <key>minimal</key> + <name>Minimal</name> + <description>Description of Minimal</description> + <type>CODE_SMELL</type> + </rule> +</rules> diff --git a/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/utf8-with-bom.xml b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/utf8-with-bom.xml new file mode 100644 index 00000000..020c9757 --- /dev/null +++ b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/utf8-with-bom.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rules> + <rule> + <key>com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck</key> + <name>M & M</name> + <description>éà& Description</description> + </rule> +</rules> diff --git a/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/utf8.xml b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/utf8.xml new file mode 100644 index 00000000..020c9757 --- /dev/null +++ b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/RulesDefinitionXmlLoaderTest/utf8.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rules> + <rule> + <key>com.puppycrawl.tools.checkstyle.checks.naming.LocalVariableNameCheck</key> + <name>M & M</name> + <description>éà& Description</description> + </rule> +</rules> diff --git a/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-jpinpoint-sample.xml b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-jpinpoint-sample.xml new file mode 100644 index 00000000..f4afa366 --- /dev/null +++ b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-jpinpoint-sample.xml @@ -0,0 +1,67 @@ +<rules xmlns:pmd="http://pmd.sourceforge.net/ruleset/2.0.0"> + <rule> + <key>AvoidCDIReferenceLeak</key> + <name>Explicit CDI references need to be destroyed otherwise they leak.</name> + <internalKey>com/jpinpoint/pmd/rules/jpinpoint-rules.xml/AvoidCDIReferenceLeak</internalKey> + <severity>BLOCKER</severity> + <description><![CDATA[<b>Problem:</b> A proxy object is created by Contexts and Dependency Injection (CDI) for explicit references, they are not de-referenced implicitly and become a memory leak. + <p/> + <b>Solution:</b> Destroy the reference explicitly. + (jpinpoint-rules)<p/> + <b>Example:</b> + <pre>public class CDIStuff { + private void bad() { + MyClass o = CDI.current().select(MyClass.class).get(); + o.doStuff(); + // bad - missing destroy in finally + } + private void good() { + MyClass o = CDI.current().select(MyClass.class).get(); + try { + o.doStuff(); + } finally { + CDI.current().destroy(o); // good - destroy properly + } + } +} +</pre> + <b>More information: </b> + <a href="https://github.com/jborgers/PMD-jPinpoint-rules/tree/pmd7/docs/JavaCodePerformance.md#pml05">JavaCodePerformance.md#pml05</a> + <br/>]]></description> + <tag>jpinpoint-rule</tag> + <tag>memory</tag> + <tag>performance</tag> + <tag>sustainability-low</tag> + </rule> + <rule> + <key>AvoidCalendar</key> + <name>A Calendar is inefficient in memory usage.</name> + <internalKey>com/jpinpoint/pmd/rules/jpinpoint-rules.xml/AvoidCalendar</internalKey> + <severity>MAJOR</severity> + <description><![CDATA[<b>Problem:</b> A Calendar is a heavyweight object and expensive to create. + <p/> + <b>Solution:</b> Use Date, Java 8+ java.time.[Local/Zoned]DateTime. + (jpinpoint-rules)<p/> + <b>Example:</b> + <pre>public class CalendarStuff { + Calendar field1; // bad + private Calendar bad1() { + return Calendar.getInstance(); + } + private Date good1a() { + return new Date(); // now + } + private LocalDateTime good1b() { + return LocalDateTime.now(); + } +} +</pre> + <b>More information: </b> + <a href="https://github.com/jborgers/PMD-jPinpoint-rules/tree/pmd7/docs/JavaCodePerformance.md#imu01">JavaCodePerformance.md#imu01</a> + <br/>]]></description> + <tag>jpinpoint-rule</tag> + <tag>memory</tag> + <tag>performance</tag> + <tag>sustainability-medium</tag> + </rule> +</rules> diff --git a/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-jpinpoint.xml b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-jpinpoint.xml new file mode 100644 index 00000000..87620f67 --- /dev/null +++ b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-jpinpoint.xml @@ -0,0 +1,13 @@ +<?xml version="1.0" encoding="UTF-8"?> +<rules> + <rule key="JP0001"> + <title>Avoid Foo Test + Avoid Foo Test + tests + + + Avoid Foo + main-sources + performance + + diff --git a/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-rules-default-ns-no-header.xml b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-rules-default-ns-no-header.xml new file mode 100644 index 00000000..8e37fc6f --- /dev/null +++ b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-rules-default-ns-no-header.xml @@ -0,0 +1,13 @@ + + + NS001 + Rule With Default NS + tests + + + NS002 + Main Rule + main-sources + performance + + diff --git a/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-rules-prefixed-ns-with-header.xml b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-rules-prefixed-ns-with-header.xml new file mode 100644 index 00000000..1e68dce9 --- /dev/null +++ b/sonar-pmd-lib/src/test/resources/org/sonar/plugins/pmd/rule/test-rules-prefixed-ns-with-header.xml @@ -0,0 +1,14 @@ + + + + NSP001 + Prefixed Namespace Test Rule + tests + + + NSP002 + Another Rule + main-sources + security + + diff --git a/sonar-pmd-lib/src/test/resources/test-highly-compressed.jar b/sonar-pmd-lib/src/test/resources/test-highly-compressed.jar new file mode 100644 index 00000000..44dae0b6 Binary files /dev/null and b/sonar-pmd-lib/src/test/resources/test-highly-compressed.jar differ diff --git a/sonar-pmd-lib/src/test/resources/test-java-rule-extractor.jar b/sonar-pmd-lib/src/test/resources/test-java-rule-extractor.jar new file mode 100644 index 00000000..e48fc23a Binary files /dev/null and b/sonar-pmd-lib/src/test/resources/test-java-rule-extractor.jar differ diff --git a/sonar-pmd-plugin/pom.xml b/sonar-pmd-plugin/pom.xml index f6da5f51..22e38367 100644 --- a/sonar-pmd-plugin/pom.xml +++ b/sonar-pmd-plugin/pom.xml @@ -1,12 +1,11 @@ - + 4.0.0 org.sonarsource.pmd sonar-pmd - 3.3.0-SNAPSHOT + ${revision} sonar-pmd-plugin @@ -15,13 +14,23 @@ SonarQube PMD Plugin Sonar-PMD is a plugin that provides coding rules from PMD. 2012 - https://github.com/jensgerdes/sonar-pmd + https://github.com/jborgers/sonar-pmd true + + Jeroen Borgers + jborgers@jpinpoint.com + +1 + + + Peter Paul Bakker + peter.paul.bakker@stokpop.nl + +1 + Jens Gerdes jens@gerdes.digital @@ -40,40 +49,45 @@ - org.sonarsource.sonarqube + org.sonarsource.api.plugin sonar-plugin-api + provided - org.codehaus.staxmate - staxmate - 2.0.1 - provided + org.sonarsource.sonarqube + sonar-plugin-api-impl + test org.sonarsource.java java-frontend - 6.0.1.20589 + ${sonar-java.version} + + + org.sonarsource.pmd + sonar-pmd-lib + ${revision} + + + org.codehaus.staxmate + staxmate + ${staxmate.version} provided - - - com.google.code.gson - gson - - - com.google.code.findbugs - jsr305 - - + + + com.google.code.findbugs + jsr305 + 3.0.2 com.google.guava guava - 19.0 + ${guava.version} org.sonarsource.sslr-squid-bridge sslr-squid-bridge - 2.7.0.377 + ${sslr.squid.bridge.version} org.picocontainer @@ -100,18 +114,73 @@ net.sourceforge.pmd pmd-java + ${pmd.version} - jdom - jdom - 1.0 + net.sourceforge.pmd + pmd-kotlin + ${pmd.version} + + + org.jdom + jdom2 + ${jdom2.version} + + + org.slf4j + slf4j-api + ${slf4j-api.version} + + + + org.slf4j + slf4j-simple + ${slf4j-api.version} + test - - + + + + org.jacoco + jacoco-maven-plugin + ${jacoco.maven.plugin.version} + + + + + + org.jacoco + jacoco-maven-plugin + + + + prepare-agent + + + surefireArgLine + + + + report + test + + report + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + -Xmx512m + + org.sonarsource.sonar-packaging-maven-plugin sonar-packaging-maven-plugin @@ -119,7 +188,9 @@ pmd PMD org.sonar.plugins.pmd.PmdPlugin - Analyze Java code with PMD. + Analyze Java and Kotlin code with PMD. + java,kotlin + java:8.0.0.0,kotlin:2.0.0.0 @@ -135,8 +206,8 @@ - 7000000 - 4200000 + 30000000 + 12000000 ${project.build.directory}/${project.build.finalName}.jar @@ -146,16 +217,61 @@ - - de.jutzig - github-release-plugin - 1.4.0 - - Sonar PMD Plugin v${project.version} - ${project.version} - ${project.version} - - + + + + + generate-pmd-rules + + + + + org.codehaus.gmaven + groovy-maven-plugin + 2.1.1 + + + org.sonarsource.pmd + sonar-pmd-lib + ${revision} + + + org.codehaus.groovy + groovy-all + 3.0.25 + pom + + + org.apache.ivy + ivy + 2.5.2 + + + + + generate-pmd-rules-xml + generate-resources + + execute + + + ${project.basedir}/../scripts/pmd7_rules_xml_generator.groovy + + ${project.basedir}/src/main/resources/org/sonar/plugins/pmd + + + + + + + + + diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/AbstractPmdExecutor.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/AbstractPmdExecutor.java new file mode 100644 index 00000000..3136ebc4 --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/AbstractPmdExecutor.java @@ -0,0 +1,299 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import net.sourceforge.pmd.PMDConfiguration; +import net.sourceforge.pmd.PMDVersion; +import net.sourceforge.pmd.lang.rule.RuleSet; +import net.sourceforge.pmd.lang.rule.RuleSetLoadException; +import net.sourceforge.pmd.lang.rule.RuleSetLoader; +import net.sourceforge.pmd.reporting.FileAnalysisListener; +import net.sourceforge.pmd.reporting.Report; +import net.sourceforge.pmd.util.log.PmdReporter; +import org.checkerframework.checker.nullness.qual.Nullable; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.event.Level; +import org.sonar.api.batch.fs.FilePredicates; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputFile.Type; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.config.Configuration; +import org.sonar.api.rule.RuleScope; +import org.sonar.plugins.pmd.xml.PmdRuleSet; +import org.sonar.plugins.pmd.xml.PmdRuleSets; +import org.sonar.plugins.pmd.xml.factory.RuleSetFactory; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.URLClassLoader; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Abstract base class for PMD executors that contains common functionality. + */ +public abstract class AbstractPmdExecutor { + + protected static final Logger LOGGER = LoggerFactory.getLogger(AbstractPmdExecutor.class); + + protected final FileSystem fs; + protected final ActiveRules rulesProfile; + protected final PmdConfiguration pmdConfiguration; + protected final Configuration settings; + + protected AbstractPmdExecutor(FileSystem fileSystem, ActiveRules rulesProfile, + PmdConfiguration pmdConfiguration, Configuration settings) { + this.fs = fileSystem; + this.rulesProfile = rulesProfile; + this.pmdConfiguration = pmdConfiguration; + this.settings = settings; + } + + protected static void accept(FileAnalysisListener fal) { + LOGGER.debug("Got FileAnalysisListener: {}", fal); + } + + /** + * Execute PMD analysis + * @return The PMD report containing the results of the analysis + */ + public Report execute() { + final long startTimeMs = System.currentTimeMillis(); + LOGGER.info(getStartMessage(), PMDVersion.VERSION); + final ClassLoader initialClassLoader = Thread.currentThread().getContextClassLoader(); + + try (URLClassLoader classLoader = createClassloader()) { + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); + + return executePmd(classLoader); + } catch (IOException e) { + LOGGER.error("Failed to close URLClassLoader.", e); + } finally { + Thread.currentThread().setContextClassLoader(initialClassLoader); + LOGGER.info(getEndMessage(), PMDVersion.VERSION, System.currentTimeMillis() - startTimeMs); + } + + return null; + } + + /** + * Get the start message for logging + * @return The start message + */ + protected abstract String getStartMessage(); + + /** + * Get the end message for logging + * @return The end message + */ + protected abstract String getEndMessage(); + + /** + * Create a classloader for PMD analysis + * @return The classloader + */ + protected abstract URLClassLoader createClassloader(); + + /** + * Execute PMD analysis with the given classloader + * @param classLoader The classloader to use + * @return The PMD report + */ + protected abstract Report executePmd(URLClassLoader classLoader); + + /** + * Write debug information about the report + * @param r The report + */ + protected void writeDebugLine(Report r) { + LOGGER.debug("Report (violations, suppressedViolations, processingErrors, configurationErrors): {}, {}, {}, {}", r.getViolations().size(), r.getSuppressedViolations().size(), r.getProcessingErrors().size(), r.getConfigurationErrors().size()); + if (!r.getViolations().isEmpty()) { + LOGGER.debug("Violations: {}", r.getViolations()); + } + if (!r.getSuppressedViolations().isEmpty()) { + LOGGER.debug("SuppressedViolations: {}", r.getSuppressedViolations()); + } + if (!r.getProcessingErrors().isEmpty()) { + LOGGER.debug("ProcessingErrors: {}", r.getProcessingErrors()); + } + if (!r.getConfigurationErrors().isEmpty()) { + LOGGER.debug("ConfigurationErrors: {}", r.getConfigurationErrors()); + } + } + + /** + * Get files of the given type and language + * @param fileType The file type (MAIN or TEST) + * @param languageKey The language key + * @return The files + */ + protected Iterable hasFiles(Type fileType, String languageKey) { + final FilePredicates predicates = fs.predicates(); + return fs.inputFiles( + predicates.and( + predicates.hasLanguage(languageKey), + predicates.hasType(fileType) + ) + ); + } + + /** + * Execute PMD rules on the given files + * @param pmdFactory The PMD template + * @param files The files to analyze + * @param repositoryKey The repository key + * @return The report + */ + protected Optional executeRules(PmdTemplate pmdFactory, Iterable files, String repositoryKey, RuleScope scope) { + if (!files.iterator().hasNext()) { + // Nothing to analyze + LOGGER.debug("No files to analyze for {}", repositoryKey); + return Optional.empty(); + } + + final RuleSet ruleSet = createRuleSet(repositoryKey, scope); + + if (ruleSet.size() < 1) { + // No rule + LOGGER.debug("No rules to apply for {}", repositoryKey); + return Optional.empty(); + } + + LOGGER.debug("Found {} rules for {}", ruleSet.size(), repositoryKey); + return Optional.ofNullable(pmdFactory.process(files, ruleSet)); + } + + /** + * Create a ruleset for the given repository + * @param repositoryKey The repository key + * @return The ruleset + */ + protected RuleSet createRuleSet(String repositoryKey, RuleScope scope) { + final String rulesXml = dumpXml(rulesProfile, repositoryKey, scope); + final File ruleSetFile = pmdConfiguration.dumpXmlRuleSet(repositoryKey, rulesXml, scope); + final String ruleSetFilePath = ruleSetFile.getAbsolutePath(); + + try { + PmdReporter reporter = createSonarPmdPluginLogger(); + return parseRuleSetWithReporter(reporter, ruleSetFilePath); + } catch (RuleSetLoadException e) { + throw new IllegalStateException(e); + } + } + + private static RuleSet parseRuleSetWithReporter(PmdReporter reporter, String ruleSetFilePath) { + // no need to use reflection to enable withReporter method, see: https://github.com/pmd/pmd/issues/6126 + PMDConfiguration pmdConfiguration = new PMDConfiguration(); + pmdConfiguration.setReporter(reporter); + RuleSetLoader loader = RuleSetLoader.fromPmdConfig(pmdConfiguration); + return loader.loadFromResource(ruleSetFilePath); + } + + private static @NotNull PmdReporter createSonarPmdPluginLogger() { + PmdReporter reporter = new PmdReporter() { + AtomicInteger numErrors = new AtomicInteger(0); + @Override + public boolean isLoggable(Level level) { + return Level.ERROR.equals(level); + } + + @Override + public void logEx(Level level, @Nullable String message, Object[] formatArgs, @Nullable Throwable error) { + numErrors.incrementAndGet(); + if (message == null) { + message = ""; + } + switch (level) { + case ERROR: + LOGGER.error(String.format(message, formatArgs)); + break; + case WARN: + LOGGER.debug(String.format(message, formatArgs)); + break; + case INFO: + LOGGER.debug(String.format(message, formatArgs)); + break; + case DEBUG: + LOGGER.debug(String.format(message, formatArgs)); + break; + case TRACE: + LOGGER.trace(String.format(message, formatArgs)); + break; + default: + LOGGER.warn("Unknown PMD log level: {} message: {}", level, String.format(message, formatArgs)); + } + } + + @Override + public int numErrors() { + return numErrors.get(); + } + }; + return reporter; + } + + /** + * Dump the rules to XML + * @param rulesProfile The active rules + * @param repositoryKey The repository key + * @return The XML + */ + protected String dumpXml(ActiveRules rulesProfile, String repositoryKey, RuleScope scope) { + final StringWriter writer = new StringWriter(2048); + final PmdRuleSet ruleSet = PmdRuleSets.from(rulesProfile, repositoryKey, scope); + ruleSet.writeTo(writer); + + return writer.toString(); + } + + /** + * Create a PMD template + * @param classLoader The classloader + * @return The PMD template + */ + protected PmdTemplate createPmdTemplate(URLClassLoader classLoader) { + return PmdTemplate.create(getSourceVersion(), classLoader, fs.encoding()); + } + + /** + * Get the Java source version + * @return The Java source version + */ + protected String getSourceVersion() { + String reqJavaVersion = settings.get(PmdConstants.JAVA_SOURCE_VERSION).orElse(PmdConstants.JAVA_SOURCE_VERSION_DEFAULT_VALUE); + String bareReqJavaVersion = reqJavaVersion; + if (reqJavaVersion.endsWith("-preview")) { + bareReqJavaVersion = reqJavaVersion.substring(0, reqJavaVersion.indexOf("-preview")); + } + String effectiveJavaVersion = bareReqJavaVersion; + if (Float.parseFloat(bareReqJavaVersion) >= Float.parseFloat(PmdConstants.JAVA_SOURCE_MINIMUM_UNSUPPORTED_VALUE)) { + effectiveJavaVersion = PmdConstants.JAVA_SOURCE_MAXIMUM_SUPPORTED_VALUE; + LOGGER.warn("Requested Java version {} ('{}') is not supported by PMD. Using maximum supported version: {}.", + reqJavaVersion, PmdConstants.JAVA_SOURCE_VERSION, PmdConstants.JAVA_SOURCE_MAXIMUM_SUPPORTED_VALUE); + } + return effectiveJavaVersion; + } +} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/ClasspathProvider.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/ClasspathProvider.java new file mode 100644 index 00000000..4190a25d --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/ClasspathProvider.java @@ -0,0 +1,19 @@ +package org.sonar.plugins.pmd; + +import java.io.File; +import java.util.Collection; + +/** + * Interface for providing classpath elements for PMD analysis. + * This replaces the dependency on JavaResourceLocator. + */ +public interface ClasspathProvider { + + Collection binaryDirs(); + + Collection classpath(); + + Collection testBinaryDirs(); + + Collection testClasspath(); +} \ No newline at end of file diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/DefaultClasspathProvider.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/DefaultClasspathProvider.java new file mode 100644 index 00000000..83dc1462 --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/DefaultClasspathProvider.java @@ -0,0 +1,49 @@ +package org.sonar.plugins.pmd; + +import org.sonar.api.batch.ScannerSide; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.config.Configuration; +import org.sonar.java.classpath.ClasspathForMain; +import org.sonar.java.classpath.ClasspathForTest; + +import java.io.File; +import java.util.Collection; + +/** + * Default implementation of ClasspathProvider that uses java-frontend's ClasspathForMain and ClasspathForTest + * to provide classpath information for PMD analysis. + * + * Based on findbugs sonar plugin approach. + */ +@ScannerSide +public class DefaultClasspathProvider implements ClasspathProvider { + + private final ClasspathForMain classpathForMain; + private final ClasspathForTest classpathForTest; + + public DefaultClasspathProvider(Configuration configuration, FileSystem fileSystem) { + classpathForMain = new ClasspathForMain(configuration, fileSystem); + classpathForTest = new ClasspathForTest(configuration, fileSystem); + } + + @Override + public Collection binaryDirs() { + return classpathForMain.getBinaryDirs(); + } + + @Override + public Collection classpath() { + return classpathForMain.getElements(); + } + + @Override + public Collection testBinaryDirs() { + return classpathForTest.getBinaryDirs(); + } + + @Override + public Collection testClasspath() { + return classpathForTest.getElements(); + } + +} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConfiguration.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConfiguration.java index 3e501526..82b2f060 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConfiguration.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConfiguration.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,27 @@ */ package org.sonar.plugins.pmd; -import java.io.File; -import java.io.IOException; -import java.io.StringWriter; -import java.nio.file.Files; -import java.nio.file.Path; - -import net.sourceforge.pmd.Report; import net.sourceforge.pmd.renderers.Renderer; import net.sourceforge.pmd.renderers.XMLRenderer; +import net.sourceforge.pmd.reporting.Report; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.batch.ScannerSide; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.config.Configuration; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; +import org.sonar.api.rule.RuleScope; + +import java.io.File; +import java.io.IOException; +import java.io.StringWriter; +import java.nio.file.Files; +import java.nio.file.Path; @ScannerSide public class PmdConfiguration { static final String PROPERTY_GENERATE_XML = "sonar.pmd.generateXml"; private static final String PMD_RESULT_XML = "pmd-result.xml"; - private static final Logger LOG = Loggers.get(PmdConfiguration.class); + private static final Logger LOG = LoggerFactory.getLogger(PmdConfiguration.class); private final FileSystem fileSystem; private final Configuration settings; @@ -59,9 +60,23 @@ private static String reportToString(Report report) throws IOException { return output.toString(); } - File dumpXmlRuleSet(String repositoryKey, String rulesXml) { + File dumpXmlRuleSet(String repositoryKey, String rulesXml, RuleScope scope) { try { - File configurationFile = writeToWorkingDirectory(rulesXml, repositoryKey + ".xml").toFile(); + String suffix; + switch (scope) { + case MAIN: + suffix = "-main"; + break; + case TEST: + suffix = "-test"; + break; + case ALL: + default: + suffix = ""; + break; + } + String fileName = repositoryKey + suffix + ".xml"; + File configurationFile = writeToWorkingDirectory(rulesXml, fileName).toFile(); LOG.info("PMD configuration: " + configurationFile.getAbsolutePath()); @@ -87,7 +102,7 @@ Path dumpXmlReport(Report report) { final String reportAsString = reportToString(report); final Path reportFile = writeToWorkingDirectory(reportAsString, PMD_RESULT_XML); - LOG.info("PMD output report: " + reportFile.toString()); + LOG.info("PMD output report: {}", reportFile); return reportFile; } catch (IOException e) { diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java index caec9338..200707bc 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdConstants.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,11 +25,12 @@ public final class PmdConstants { public static final String PLUGIN_NAME = "PMD"; public static final String PLUGIN_KEY = "pmd"; - public static final String REPOSITORY_KEY = PLUGIN_KEY; + public static final String MAIN_JAVA_REPOSITORY_KEY = PLUGIN_KEY; + public static final String MAIN_KOTLIN_REPOSITORY_KEY = "pmd-kotlin"; public static final String REPOSITORY_NAME = "PMD"; - public static final String TEST_REPOSITORY_KEY = "pmd-unit-tests"; - public static final String TEST_REPOSITORY_NAME = "PMD Unit Tests"; - public static final String XPATH_CLASS = "net.sourceforge.pmd.lang.rule.XPathRule"; + public static final String REPOSITORY_KOTLIN_NAME = "PMD Kotlin"; + + public static final String XPATH_CLASS = "net.sourceforge.pmd.lang.rule.xpath.XPathRule"; public static final String XPATH_EXPRESSION_PARAM = "xpath"; public static final String XPATH_MESSAGE_PARAM = "message"; @@ -41,12 +42,22 @@ public final class PmdConstants { /** * Default value for property {@link #JAVA_SOURCE_VERSION}. */ - public static final String JAVA_SOURCE_VERSION_DEFAULT_VALUE = "1.6"; + public static final String JAVA_SOURCE_VERSION_DEFAULT_VALUE = "25"; + + /** + * Maximum supported value for property {@link #JAVA_SOURCE_VERSION}. For PMD 7 this is 25-preview. + */ + public static final String JAVA_SOURCE_MAXIMUM_SUPPORTED_VALUE = "25-preview"; + /** + * Minimum UNsupported value for property {@link #JAVA_SOURCE_VERSION}. For PMD 7 this is 26. + */ + public static final String JAVA_SOURCE_MINIMUM_UNSUPPORTED_VALUE = "26"; /** * The Java Language key. */ - public static final String LANGUAGE_KEY = "java"; + public static final String LANGUAGE_JAVA_KEY = "java"; + public static final String LANGUAGE_KOTLIN_KEY = "kotlin"; private PmdConstants() { } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java deleted file mode 100644 index 3b1c2277..00000000 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.pmd; - -import java.io.File; -import java.io.IOException; -import java.io.StringWriter; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import net.sourceforge.pmd.PMDVersion; -import net.sourceforge.pmd.Report; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleSet; -import net.sourceforge.pmd.RuleSetFactory; -import net.sourceforge.pmd.RuleSetNotFoundException; -import net.sourceforge.pmd.RuleSets; -import org.sonar.api.batch.ScannerSide; -import org.sonar.api.batch.fs.FilePredicates; -import org.sonar.api.batch.fs.FileSystem; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.InputFile.Type; -import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.config.Configuration; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; -import org.sonar.api.utils.log.Profiler; -import org.sonar.plugins.java.api.JavaResourceLocator; -import org.sonar.plugins.pmd.xml.PmdRuleSet; -import org.sonar.plugins.pmd.xml.PmdRuleSets; - -@ScannerSide -public class PmdExecutor { - - private static final Logger LOGGER = Loggers.get(PmdExecutor.class); - - private final FileSystem fs; - private final ActiveRules rulesProfile; - private final PmdConfiguration pmdConfiguration; - private final JavaResourceLocator javaResourceLocator; - private final Configuration settings; - - public PmdExecutor(FileSystem fileSystem, ActiveRules rulesProfile, - PmdConfiguration pmdConfiguration, JavaResourceLocator javaResourceLocator, Configuration settings) { - this.fs = fileSystem; - this.rulesProfile = rulesProfile; - this.pmdConfiguration = pmdConfiguration; - this.javaResourceLocator = javaResourceLocator; - this.settings = settings; - } - - public Report execute() { - final Profiler profiler = Profiler.create(LOGGER).startInfo("Execute PMD " + PMDVersion.VERSION); - final ClassLoader initialClassLoader = Thread.currentThread().getContextClassLoader(); - - try (URLClassLoader classLoader = createClassloader()) { - Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); - - return executePmd(classLoader); - } catch (IOException e) { - LOGGER.error("Failed to close URLClassLoader.", e); - } finally { - Thread.currentThread().setContextClassLoader(initialClassLoader); - profiler.stopInfo(); - } - - return null; - } - - private Report executePmd(URLClassLoader classLoader) { - Report report = new Report(); - - RuleContext context = new RuleContext(); - context.setReport(report); - - PmdTemplate pmdFactory = createPmdTemplate(classLoader); - executeRules(pmdFactory, context, javaFiles(Type.MAIN), PmdConstants.REPOSITORY_KEY); - executeRules(pmdFactory, context, javaFiles(Type.TEST), PmdConstants.TEST_REPOSITORY_KEY); - - pmdConfiguration.dumpXmlReport(report); - - return report; - } - - private Iterable javaFiles(Type fileType) { - final FilePredicates predicates = fs.predicates(); - return fs.inputFiles( - predicates.and( - predicates.hasLanguage(PmdConstants.LANGUAGE_KEY), - predicates.hasType(fileType) - ) - ); - } - - private void executeRules(PmdTemplate pmdFactory, RuleContext ruleContext, Iterable files, String repositoryKey) { - if (!files.iterator().hasNext()) { - // Nothing to analyze - return; - } - - RuleSets rulesets = createRuleSets(repositoryKey); - if (rulesets.getAllRules().isEmpty()) { - // No rule - return; - } - - rulesets.start(ruleContext); - - for (InputFile file : files) { - pmdFactory.process(file, rulesets, ruleContext); - } - - rulesets.end(ruleContext); - } - - private RuleSets createRuleSets(String repositoryKey) { - String rulesXml = dumpXml(rulesProfile, repositoryKey); - File ruleSetFile = pmdConfiguration.dumpXmlRuleSet(repositoryKey, rulesXml); - String ruleSetFilePath = ruleSetFile.getAbsolutePath(); - RuleSetFactory ruleSetFactory = new RuleSetFactory(); - try { - RuleSet ruleSet = ruleSetFactory.createRuleSet(ruleSetFilePath); - return new RuleSets(ruleSet); - } catch (RuleSetNotFoundException e) { - throw new IllegalStateException(e); - } - } - - private String dumpXml(ActiveRules rulesProfile, String repositoryKey) { - final StringWriter writer = new StringWriter(); - final PmdRuleSet ruleSet = PmdRuleSets.from(rulesProfile, repositoryKey); - ruleSet.writeTo(writer); - - return writer.toString(); - } - - PmdTemplate createPmdTemplate(URLClassLoader classLoader) { - return PmdTemplate.create(getSourceVersion(), classLoader, fs.encoding()); - } - - /** - * @return A classloader for PMD that contains all dependencies of the project that shall be analyzed. - */ - private URLClassLoader createClassloader() { - Collection classpathElements = javaResourceLocator.classpath(); - List urls = new ArrayList<>(); - for (File file : classpathElements) { - try { - urls.add(file.toURI().toURL()); - } catch (MalformedURLException e) { - throw new IllegalStateException("Failed to create the project classloader. Classpath element is invalid: " + file, e); - } - } - return new URLClassLoader(urls.toArray(new URL[0]), null); - } - - private String getSourceVersion() { - return settings.get(PmdConstants.JAVA_SOURCE_VERSION) - .orElse(PmdConstants.JAVA_SOURCE_VERSION_DEFAULT_VALUE); - } - -} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdJavaExecutor.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdJavaExecutor.java new file mode 100644 index 00000000..54418dff --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdJavaExecutor.java @@ -0,0 +1,103 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import net.sourceforge.pmd.reporting.FileAnalysisListener; +import net.sourceforge.pmd.reporting.Report; +import org.sonar.api.batch.ScannerSide; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile.Type; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.config.Configuration; +import org.sonar.api.rule.RuleScope; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; + +/** + * PMD executor for Java files. + */ +@ScannerSide +public class PmdJavaExecutor extends AbstractPmdExecutor { + + private final ClasspathProvider classpathProvider; + + public PmdJavaExecutor(FileSystem fileSystem, ActiveRules rulesProfile, + PmdConfiguration pmdConfiguration, ClasspathProvider classpathProvider, Configuration settings) { + super(fileSystem, rulesProfile, pmdConfiguration, settings); + this.classpathProvider = classpathProvider; + } + + @Override + protected String getStartMessage() { + return "Execute PMD {}"; + } + + @Override + protected String getEndMessage() { + return "Execute PMD {} (done) | time={}ms"; + } + + @Override + protected Report executePmd(URLClassLoader classLoader) { + final PmdTemplate pmdFactory = createPmdTemplate(classLoader); + final Optional javaMainReport = executeRules(pmdFactory, hasFiles(Type.MAIN, PmdConstants.LANGUAGE_JAVA_KEY), PmdConstants.MAIN_JAVA_REPOSITORY_KEY, RuleScope.MAIN); + final Optional javaTestReport = executeRules(pmdFactory, hasFiles(Type.TEST, PmdConstants.LANGUAGE_JAVA_KEY), PmdConstants.MAIN_JAVA_REPOSITORY_KEY, RuleScope.TEST); + + if (LOGGER.isDebugEnabled()) { + javaMainReport.ifPresent(this::writeDebugLine); + javaTestReport.ifPresent(this::writeDebugLine); + } + + Consumer fileAnalysisListenerConsumer = AbstractPmdExecutor::accept; + + Report unionReport = Report.buildReport(fileAnalysisListenerConsumer); + unionReport = javaMainReport.map(unionReport::union).orElse(unionReport); + unionReport = javaTestReport.map(unionReport::union).orElse(unionReport); + + pmdConfiguration.dumpXmlReport(unionReport); + + return unionReport; + } + + /** + * @return A classloader for PMD that contains all dependencies of the project that shall be analyzed. + */ + @Override + protected URLClassLoader createClassloader() { + Collection classpathElements = classpathProvider.classpath(); + List urls = new ArrayList<>(); + for (File file : classpathElements) { + try { + urls.add(file.toURI().toURL()); + } catch (MalformedURLException e) { + throw new IllegalStateException("Failed to create the project classloader. Classpath element is invalid: " + file, e); + } + } + return new URLClassLoader(urls.toArray(new URL[0])); + } +} \ No newline at end of file diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdKotlinExecutor.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdKotlinExecutor.java new file mode 100644 index 00000000..143e3224 --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdKotlinExecutor.java @@ -0,0 +1,89 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import net.sourceforge.pmd.reporting.FileAnalysisListener; +import net.sourceforge.pmd.reporting.Report; +import org.sonar.api.batch.ScannerSide; +import org.sonar.api.batch.fs.FileSystem; +import org.sonar.api.batch.fs.InputFile.Type; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.config.Configuration; +import org.sonar.api.rule.RuleScope; + +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Optional; +import java.util.function.Consumer; + +/** + * PMD executor for Kotlin files. + * It's used for Kotlin projects where JavaResourceLocator might not be available. + */ +@ScannerSide +public class PmdKotlinExecutor extends AbstractPmdExecutor { + + public PmdKotlinExecutor(FileSystem fileSystem, ActiveRules rulesProfile, + PmdConfiguration pmdConfiguration, Configuration settings) { + super(fileSystem, rulesProfile, pmdConfiguration, settings); + } + + @Override + protected String getStartMessage() { + return "Execute PMD {} for Kotlin"; + } + + @Override + protected String getEndMessage() { + return "Execute PMD {} for Kotlin (done) | time={}ms"; + } + + @Override + protected Report executePmd(URLClassLoader classLoader) { + final PmdTemplate pmdFactory = createPmdTemplate(classLoader); + final Optional kotlinMainReport = executeRules(pmdFactory, hasFiles(Type.MAIN, PmdConstants.LANGUAGE_KOTLIN_KEY), PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY, RuleScope.MAIN); + final Optional kotlinTestReport = executeRules(pmdFactory, hasFiles(Type.TEST, PmdConstants.LANGUAGE_KOTLIN_KEY), PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY, RuleScope.TEST); + + if (LOGGER.isDebugEnabled()) { + kotlinMainReport.ifPresent(this::writeDebugLine); + kotlinTestReport.ifPresent(this::writeDebugLine); + } + + Consumer fileAnalysisListenerConsumer = AbstractPmdExecutor::accept; + + Report unionReport = Report.buildReport(fileAnalysisListenerConsumer); + unionReport = kotlinMainReport.map(unionReport::union).orElse(unionReport); + unionReport = kotlinTestReport.map(unionReport::union).orElse(unionReport); + + pmdConfiguration.dumpXmlReport(unionReport); + + return unionReport; + } + + /** + * @return A classloader for PMD that contains no additional dependencies. + * For Kotlin projects, we don't need the project's classpath. + */ + @Override + protected URLClassLoader createClassloader() { + // Create an empty URLClassLoader + return new URLClassLoader(new URL[0]); + } +} \ No newline at end of file diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdLevelUtils.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdLevelUtils.java index 3cecb87f..828ad55e 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdLevelUtils.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdLevelUtils.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPlugin.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPlugin.java index 8cd18ead..9c516dfb 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPlugin.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPlugin.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,10 +21,8 @@ import org.sonar.api.Plugin; import org.sonar.api.config.PropertyDefinition; -import org.sonar.plugins.pmd.profile.PmdProfileExporter; -import org.sonar.plugins.pmd.profile.PmdProfileImporter; +import org.sonar.plugins.pmd.rule.PmdKotlinRulesDefinition; import org.sonar.plugins.pmd.rule.PmdRulesDefinition; -import org.sonar.plugins.pmd.rule.PmdUnitTestsRulesDefinition; /** * The {@link PmdPlugin} is the main entry-point of Sonar-PMD. @@ -39,15 +37,14 @@ public void define(Context context) { .name("Generate XML Report") .hidden() .build(), - PmdSensor.class, PmdConfiguration.class, - PmdExecutor.class, + PmdJavaExecutor.class, + PmdKotlinExecutor.class, PmdRulesDefinition.class, - PmdUnitTestsRulesDefinition.class, - PmdProfileExporter.class, - PmdProfileImporter.class, - PmdViolationRecorder.class + PmdKotlinRulesDefinition.class, + PmdViolationRecorder.class, + DefaultClasspathProvider.class ); } } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPriorities.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPriorities.java new file mode 100644 index 00000000..3005cdb3 --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdPriorities.java @@ -0,0 +1,67 @@ +/* + * SonarQube PMD Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import java.util.Locale; +import java.util.Objects; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.sonar.api.batch.rule.ActiveRule; +import org.sonar.api.rule.Severity; +import org.sonar.api.rules.RulePriority; +import org.sonar.plugins.pmd.xml.PmdRule; + +public final class PmdPriorities { + + private static final int NUM_SEVERITIES = Severity.ALL.size(); + private PmdPriorities() { + // only static methods + } + + public static org.sonar.api.rules.RulePriority sonarPrioOf(@Nonnull PmdRule pmdRule) { + return toSonarPrio(pmdRule.getPriority()); + } + + public static org.sonar.api.rules.RulePriority toSonarPrio(@Nullable Integer pmdPrioLevel) { + String severity = toSonarSeverity(pmdPrioLevel); + return (severity != null) ? RulePriority.valueOf(severity) : null; + } + + public static String toSonarSeverity(@Nullable Integer pmdPrioLevel) { + if (Objects.isNull(pmdPrioLevel)) { + return null; + } + final int index = Math.abs(NUM_SEVERITIES - pmdPrioLevel); + return (index < NUM_SEVERITIES) ? Severity.ALL.get(index) : null; + } + + public static Integer fromSonarPrio(org.sonar.api.rules.RulePriority priority) { + return Math.abs(priority.ordinal() - NUM_SEVERITIES); + } + + public static Integer fromSonarSeverity(@Nonnull String severity) { + return Math.abs(NUM_SEVERITIES - Severity.ALL.indexOf(severity)); + } + + public static Integer ofSonarRule(@Nonnull ActiveRule sonarRule) { + return fromSonarSeverity(sonarRule.severity().toUpperCase(Locale.ENGLISH)); + } +} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java index b4979db0..7a2b45e6 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,7 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.reporting.RuleViolation; import org.sonar.api.batch.fs.FilePredicates; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile.Type; @@ -30,26 +30,32 @@ public class PmdSensor implements Sensor { private final ActiveRules profile; - private final PmdExecutor executor; + private final PmdJavaExecutor javaExecutor; + private final PmdKotlinExecutor kotlinExecutor; private final PmdViolationRecorder pmdViolationRecorder; private final FileSystem fs; - public PmdSensor(ActiveRules profile, PmdExecutor executor, PmdViolationRecorder pmdViolationRecorder, FileSystem fs) { + public PmdSensor(ActiveRules profile, PmdJavaExecutor javaExecutor, PmdKotlinExecutor kotlinExecutor, + PmdViolationRecorder pmdViolationRecorder, FileSystem fs) { this.profile = profile; - this.executor = executor; + this.javaExecutor = javaExecutor; + this.kotlinExecutor = kotlinExecutor; this.pmdViolationRecorder = pmdViolationRecorder; this.fs = fs; } private boolean shouldExecuteOnProject() { - return (hasFilesToCheck(Type.MAIN, PmdConstants.REPOSITORY_KEY)) - || (hasFilesToCheck(Type.TEST, PmdConstants.TEST_REPOSITORY_KEY)); + return (hasFilesToCheck(Type.MAIN, PmdConstants.MAIN_JAVA_REPOSITORY_KEY, PmdConstants.LANGUAGE_JAVA_KEY)) + || (hasFilesToCheck(Type.TEST, PmdConstants.MAIN_JAVA_REPOSITORY_KEY, PmdConstants.LANGUAGE_JAVA_KEY)) + || (hasFilesToCheck(Type.MAIN, PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY, PmdConstants.LANGUAGE_KOTLIN_KEY) + || (hasFilesToCheck(Type.TEST, PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY, PmdConstants.LANGUAGE_KOTLIN_KEY)) + ); } - private boolean hasFilesToCheck(Type type, String repositoryKey) { + private boolean hasFilesToCheck(Type type, String repositoryKey, String languageKey) { FilePredicates predicates = fs.predicates(); final boolean hasMatchingFiles = fs.hasFiles(predicates.and( - predicates.hasLanguage(PmdConstants.LANGUAGE_KEY), + predicates.hasLanguage(languageKey), predicates.hasType(type))); return hasMatchingFiles && !profile.findByRepository(repositoryKey).isEmpty(); } @@ -61,15 +67,39 @@ public String toString() { @Override public void describe(SensorDescriptor descriptor) { - descriptor.onlyOnLanguage(PmdConstants.LANGUAGE_KEY) + descriptor.onlyOnLanguages(PmdConstants.LANGUAGE_JAVA_KEY, PmdConstants.LANGUAGE_KOTLIN_KEY) .name("PmdSensor"); } @Override public void execute(SensorContext context) { if (shouldExecuteOnProject()) { - for (RuleViolation violation : executor.execute()) { - pmdViolationRecorder.saveViolation(violation, context); + // Check if there are Kotlin files to analyze + boolean hasKotlinFiles = hasFilesToCheck(Type.MAIN, PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY, PmdConstants.LANGUAGE_KOTLIN_KEY) || + hasFilesToCheck(Type.TEST, PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY, PmdConstants.LANGUAGE_KOTLIN_KEY); + + // Check if there are Java files to analyze + boolean hasJavaFiles = hasFilesToCheck(Type.MAIN, PmdConstants.MAIN_JAVA_REPOSITORY_KEY, PmdConstants.LANGUAGE_JAVA_KEY) || + hasFilesToCheck(Type.TEST, PmdConstants.MAIN_JAVA_REPOSITORY_KEY, PmdConstants.LANGUAGE_JAVA_KEY); + + // Process Kotlin files if present + if (hasKotlinFiles) { + net.sourceforge.pmd.reporting.Report kotlinReport = kotlinExecutor.execute(); + if (kotlinReport != null) { + for (RuleViolation violation : kotlinReport.getViolations()) { + pmdViolationRecorder.saveViolation(violation, context); + } + } + } + + // Process Java files if present + if (hasJavaFiles) { + net.sourceforge.pmd.reporting.Report javaReport = javaExecutor.execute(); + if (javaReport != null) { + for (RuleViolation violation : javaReport.getViolations()) { + pmdViolationRecorder.saveViolation(violation, context); + } + } } } } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdTemplate.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdTemplate.java index ef18be21..fcab56ea 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdTemplate.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdTemplate.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,61 +19,65 @@ */ package org.sonar.plugins.pmd; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.Charset; -import java.util.HashMap; -import java.util.Map; - -import net.sourceforge.pmd.PMDConfiguration; -import net.sourceforge.pmd.PMDException; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleSets; -import net.sourceforge.pmd.SourceCodeProcessor; +import net.sourceforge.pmd.*; import net.sourceforge.pmd.lang.LanguageVersion; import net.sourceforge.pmd.lang.java.JavaLanguageModule; +import net.sourceforge.pmd.lang.rule.RuleSet; +import net.sourceforge.pmd.renderers.EmptyRenderer; +import net.sourceforge.pmd.reporting.Report; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; + +import java.nio.charset.Charset; +import java.nio.file.Paths; +import java.util.*; public class PmdTemplate { - private static final Logger LOG = Loggers.get(PmdTemplate.class); + private static final Logger LOG = LoggerFactory.getLogger(PmdTemplate.class); private static final Map JAVA_VERSIONS = prepareVersions(); private static Map prepareVersions() { final Map versions = new HashMap<>(); - versions.put("1.1", "1.3"); - versions.put("1.2", "1.3"); - versions.put("5", "1.5"); - versions.put("6", "1.6"); - versions.put("7", "1.7"); versions.put("8", "1.8"); - versions.put("9", "9"); versions.put("1.9", "9"); - versions.put("10", "10"); versions.put("1.10", "10"); - versions.put("11", "11"); versions.put("1.11", "11"); - + versions.put("1.12", "12"); + versions.put("1.13", "13"); + versions.put("1.14", "14"); + versions.put("1.15", "15"); + versions.put("1.16", "16"); + versions.put("1.17", "17"); + versions.put("1.18", "18"); + versions.put("1.19", "19"); + versions.put("1.20", "20"); + versions.put("1.21", "21"); + versions.put("1.22", "22"); + versions.put("1.23", "23"); + versions.put("1.24", "24"); + versions.put("1.25", "25"); + versions.put("1.25-preview", "25-preview"); return versions; } - private SourceCodeProcessor processor; - private PMDConfiguration configuration; + private final PMDConfiguration configuration; - PmdTemplate(PMDConfiguration configuration, SourceCodeProcessor processor) { + PmdTemplate(PMDConfiguration configuration) { this.configuration = configuration; - this.processor = processor; } public static PmdTemplate create(String javaVersion, ClassLoader classloader, Charset charset) { PMDConfiguration configuration = new PMDConfiguration(); configuration.setDefaultLanguageVersion(languageVersion(javaVersion)); configuration.setClassLoader(classloader); - configuration.setSourceEncoding(charset.name()); - SourceCodeProcessor processor = new SourceCodeProcessor(configuration); - return new PmdTemplate(configuration, processor); + configuration.setSourceEncoding(charset); + configuration.setFailOnViolation(false); + configuration.setIgnoreIncrementalAnalysis(true); + configuration.setReportFormat(EmptyRenderer.NAME); + + return new PmdTemplate(configuration); } static LanguageVersion languageVersion(String javaVersion) { @@ -82,7 +86,7 @@ static LanguageVersion languageVersion(String javaVersion) { if (languageVersion == null) { throw new IllegalArgumentException("Unsupported Java version for PMD: " + version); } - LOG.info("Java version: " + version); + LOG.info("Java version: {}", version); return languageVersion; } @@ -94,13 +98,13 @@ PMDConfiguration configuration() { return configuration; } - public void process(InputFile file, RuleSets rulesets, RuleContext ruleContext) { - ruleContext.setSourceCodeFilename(file.uri().toString()); - - try (InputStream inputStream = file.inputStream()) { - processor.processSourceCode(inputStream, rulesets, ruleContext); - } catch (RuntimeException | IOException | PMDException e) { - LOG.error("Fail to execute PMD. Following file is ignored: " + file, e); + public Report process(Iterable files, RuleSet ruleset) { + try (PmdAnalysis pmd = PmdAnalysis.create(configuration)) { + pmd.addRuleSet(ruleset); + for (InputFile file: files) { + pmd.files().addFile(Paths.get(file.uri())); + } + return pmd.performAnalysisAndCollectReport(); } } } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdViolationRecorder.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdViolationRecorder.java index 7be52370..d802cf71 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdViolationRecorder.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdViolationRecorder.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,9 +19,9 @@ */ package org.sonar.plugins.pmd; -import java.net.URI; - -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.reporting.RuleViolation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.batch.ScannerSide; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; @@ -31,10 +31,15 @@ import org.sonar.api.batch.sensor.issue.NewIssue; import org.sonar.api.batch.sensor.issue.NewIssueLocation; import org.sonar.api.rule.RuleKey; +import org.sonar.plugins.pmd.rule.PmdKotlinRulesDefinition; + +import java.util.Optional; @ScannerSide public class PmdViolationRecorder { + private static final Logger LOGGER = LoggerFactory.getLogger(PmdKotlinRulesDefinition.class); + private final FileSystem fs; private final ActiveRules activeRules; @@ -44,7 +49,13 @@ public PmdViolationRecorder(FileSystem fs, ActiveRules activeRules) { } public void saveViolation(RuleViolation pmdViolation, SensorContext context) { + + LOGGER.debug("About to save RuleViolation: {}", pmdViolation); + final InputFile inputFile = findResourceFor(pmdViolation); + + LOGGER.trace("Found violation input file: {}", inputFile); + if (inputFile == null) { // Save violations only for existing resources return; @@ -52,6 +63,8 @@ public void saveViolation(RuleViolation pmdViolation, SensorContext context) { final RuleKey ruleKey = findActiveRuleKeyFor(pmdViolation); + LOGGER.trace("Found violation rule key: {}", ruleKey); + if (ruleKey == null) { // Save violations only for enabled rules return; @@ -62,33 +75,42 @@ public void saveViolation(RuleViolation pmdViolation, SensorContext context) { final TextRange issueTextRange = TextRangeCalculator.calculate(pmdViolation, inputFile); + LOGGER.trace("New issue: {} Text range: {}", issue, issueTextRange); + final NewIssueLocation issueLocation = issue.newLocation() .on(inputFile) .message(pmdViolation.getDescription()) .at(issueTextRange); + LOGGER.trace("Issue location to save: {}", issueLocation); + issue.at(issueLocation) .save(); + + LOGGER.debug("RuleViolation saved: {}", pmdViolation); } private InputFile findResourceFor(RuleViolation violation) { - final URI uri = URI.create(violation.getFilename()); return fs.inputFile( - fs.predicates().hasURI(uri) + fs.predicates().hasAbsolutePath( + violation.getFileId().getAbsolutePath() + ) ); } private RuleKey findActiveRuleKeyFor(RuleViolation violation) { final String internalRuleKey = violation.getRule().getName(); - RuleKey ruleKey = RuleKey.of(PmdConstants.REPOSITORY_KEY, internalRuleKey); + return findRuleKey(internalRuleKey, PmdConstants.MAIN_JAVA_REPOSITORY_KEY) + .orElse(findRuleKey(internalRuleKey, PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY) + .orElse(null)); + } + + private Optional findRuleKey(String internalRuleKey, String repositoryKey) { + RuleKey ruleKey = RuleKey.of(repositoryKey, internalRuleKey); if (activeRules.find(ruleKey) != null) { - return ruleKey; + return Optional.of(ruleKey); } - - // Let's try the test repo. - ruleKey = RuleKey.of(PmdConstants.TEST_REPOSITORY_KEY, internalRuleKey); - - return activeRules.find(ruleKey) != null ? ruleKey : null; + return Optional.empty(); } } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/TextRangeCalculator.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/TextRangeCalculator.java index c5344e1a..570c1910 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/TextRangeCalculator.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/TextRangeCalculator.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,16 +19,19 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.reporting.RuleViolation; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.TextPointer; import org.sonar.api.batch.fs.TextRange; /** - * Calculates a {@link org.sonar.api.batch.fs.TextRange} for a given {@link net.sourceforge.pmd.RuleViolation}. + * Calculates a {@link org.sonar.api.batch.fs.TextRange} for a given {@link net.sourceforge.pmd.reporting.RuleViolation}. */ class TextRangeCalculator { + private TextRangeCalculator() { + } + static TextRange calculate(RuleViolation pmdViolation, InputFile inputFile) { final int startLine = calculateBeginLine(pmdViolation); final int endLine = calculateEndLine(pmdViolation); diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileExporter.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileExporter.java deleted file mode 100644 index 5433899b..00000000 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileExporter.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.pmd.profile; - -import java.io.Writer; - -import org.sonar.api.profiles.ProfileExporter; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.plugins.pmd.PmdConstants; -import org.sonar.plugins.pmd.xml.PmdRuleSet; -import org.sonar.plugins.pmd.xml.PmdRuleSets; - -/** - * ServerSide component that is able to export all currently active PMD rules as XML. - */ -public class PmdProfileExporter extends ProfileExporter { - - private static final String CONTENT_TYPE_APPLICATION_XML = "application/xml"; - - public PmdProfileExporter() { - super(PmdConstants.REPOSITORY_KEY, PmdConstants.PLUGIN_NAME); - setSupportedLanguages(PmdConstants.LANGUAGE_KEY); - setMimeType(CONTENT_TYPE_APPLICATION_XML); - } - - @Override - public void exportProfile(RulesProfile profile, Writer writer) { - - final PmdRuleSet tree = PmdRuleSets.from(profile, PmdConstants.REPOSITORY_KEY); - - try { - tree.writeTo(writer); - } catch (IllegalStateException e) { - throw new IllegalStateException("An exception occurred while generating the PMD configuration file from profile: " + profile.getName(), e); - } - } -} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileImporter.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileImporter.java deleted file mode 100644 index ebe26fa2..00000000 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileImporter.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.pmd.profile; - -import java.io.Reader; - -import org.sonar.api.profiles.ProfileImporter; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RuleFinder; -import org.sonar.api.rules.RuleQuery; -import org.sonar.api.utils.ValidationMessages; -import org.sonar.plugins.pmd.PmdConstants; -import org.sonar.plugins.pmd.PmdLevelUtils; -import org.sonar.plugins.pmd.xml.PmdProperty; -import org.sonar.plugins.pmd.xml.PmdRule; -import org.sonar.plugins.pmd.xml.PmdRuleSet; -import org.sonar.plugins.pmd.xml.PmdRuleSets; - -public class PmdProfileImporter extends ProfileImporter { - - private final RuleFinder ruleFinder; - - public PmdProfileImporter(RuleFinder ruleFinder) { - super(PmdConstants.REPOSITORY_KEY, PmdConstants.PLUGIN_NAME); - setSupportedLanguages(PmdConstants.LANGUAGE_KEY); - this.ruleFinder = ruleFinder; - } - - private void setParameters(ActiveRule activeRule, PmdRule pmdRule, Rule rule, ValidationMessages messages) { - for (PmdProperty prop : pmdRule.getProperties()) { - String paramName = prop.getName(); - if (rule.getParam(paramName) == null) { - messages.addWarningText("The property '" + paramName + "' is not supported in the pmd rule: " + pmdRule.getRef()); - } else { - activeRule.setParameter(paramName, prop.getValue()); - } - } - } - - @Override - public RulesProfile importProfile(Reader pmdConfigurationFile, ValidationMessages messages) { - PmdRuleSet pmdRuleset = PmdRuleSets.from(pmdConfigurationFile, messages); - RulesProfile profile = RulesProfile.create(); - for (PmdRule pmdRule : pmdRuleset.getPmdRules()) { - String ruleClassName = pmdRule.getClazz(); - if (PmdConstants.XPATH_CLASS.equals(ruleClassName)) { - messages.addWarningText("PMD XPath rule '" + pmdRule.getName() - + "' can't be imported automatically. The rule must be created manually through the SonarQube web interface."); - } else { - String ruleRef = pmdRule.getRef(); - if (ruleRef == null) { - messages.addWarningText("A PMD rule without 'ref' attribute can't be imported. see '" + ruleClassName + "'"); - } else { - Rule rule = ruleFinder.find(RuleQuery.create().withRepositoryKey(PmdConstants.REPOSITORY_KEY).withConfigKey(ruleRef)); - if (rule != null) { - ActiveRule activeRule = profile.activateRule(rule, PmdLevelUtils.fromLevel(pmdRule.getPriority())); - setParameters(activeRule, pmdRule, rule, messages); - } else { - messages.addWarningText("Unable to import unknown PMD rule '" + ruleRef + "'"); - } - } - } - } - return profile; - } -} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/PmdKotlinRulesDefinition.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/PmdKotlinRulesDefinition.java new file mode 100644 index 00000000..176f3c7a --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/PmdKotlinRulesDefinition.java @@ -0,0 +1,72 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd.rule; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.sonar.api.server.rule.RulesDefinition; +import org.sonar.plugins.pmd.PmdConstants; +import org.sonar.squidbridge.rules.SqaleXmlLoader; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + +public final class PmdKotlinRulesDefinition implements RulesDefinition { + + private static final Logger LOGGER = LoggerFactory.getLogger(PmdKotlinRulesDefinition.class); + + public PmdKotlinRulesDefinition() { + // do nothing + } + + static void extractRulesData(NewRepository repository, String xmlRulesFilePath, String htmlDescriptionFolder) { + try (InputStream inputStream = PmdKotlinRulesDefinition.class.getResourceAsStream(xmlRulesFilePath)) { + if (inputStream == null) { + LOGGER.error("Cannot read {}", xmlRulesFilePath); + } + else { + new RulesDefinitionXmlLoader() + .load( + repository, + inputStream, + StandardCharsets.UTF_8 + ); + } + } catch (IOException e) { + LOGGER.error("Failed to load PMD RuleSet.", e); + } + + ExternalDescriptionLoader.loadHtmlDescriptions(repository, htmlDescriptionFolder); + SqaleXmlLoader.load(repository, "/com/sonar/sqale/pmd-model-kotlin.xml"); + } + + @Override + public void define(Context context) { + NewRepository repository = context + .createRepository(PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY, PmdConstants.LANGUAGE_KOTLIN_KEY) + .setName(PmdConstants.REPOSITORY_KOTLIN_NAME); + + extractRulesData(repository, "/org/sonar/plugins/pmd/rules-kotlin.xml", "/org/sonar/l10n/pmd/rules/pmd-kotlin"); + + repository.done(); + } + +} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/PmdRulesDefinition.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/PmdRulesDefinition.java index f4b3d482..dce5e640 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/PmdRulesDefinition.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/PmdRulesDefinition.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,27 +19,25 @@ */ package org.sonar.plugins.pmd.rule; -import java.io.IOException; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.Properties; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.api.server.rule.RulesDefinitionXmlLoader; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; import org.sonar.plugins.pmd.PmdConstants; import org.sonar.squidbridge.rules.SqaleXmlLoader; +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; + public final class PmdRulesDefinition implements RulesDefinition { - private static final Logger LOGGER = Loggers.get(PmdRulesDefinition.class); + private static final Logger LOGGER = LoggerFactory.getLogger(PmdRulesDefinition.class); public PmdRulesDefinition() { // do nothing } - static void extractRulesData(NewRepository repository, String xmlRulesFilePath, String htmlDescriptionFolder) { + static void extractRulesData(NewRepository repository, String xmlRulesFilePath) { try (InputStream inputStream = PmdRulesDefinition.class.getResourceAsStream(xmlRulesFilePath)) { new RulesDefinitionXmlLoader() .load( @@ -51,46 +49,18 @@ static void extractRulesData(NewRepository repository, String xmlRulesFilePath, LOGGER.error("Failed to load PMD RuleSet.", e); } - ExternalDescriptionLoader.loadHtmlDescriptions(repository, htmlDescriptionFolder); - loadNames(repository); SqaleXmlLoader.load(repository, "/com/sonar/sqale/pmd-model.xml"); } @Override public void define(Context context) { NewRepository repository = context - .createRepository(PmdConstants.REPOSITORY_KEY, PmdConstants.LANGUAGE_KEY) + .createRepository(PmdConstants.MAIN_JAVA_REPOSITORY_KEY, PmdConstants.LANGUAGE_JAVA_KEY) .setName(PmdConstants.REPOSITORY_NAME); - extractRulesData(repository, "/org/sonar/plugins/pmd/rules.xml", "/org/sonar/l10n/pmd/rules/pmd"); + extractRulesData(repository, "/org/sonar/plugins/pmd/rules-java.xml"); repository.done(); } - private static void loadNames(NewRepository repository) { - - Properties properties = new Properties(); - - try (InputStream stream = PmdRulesDefinition.class.getResourceAsStream("/org/sonar/l10n/pmd.properties")) { - properties.load(stream); - } catch (IOException e) { - throw new IllegalArgumentException("Could not read names from properties", e); - } - - for (NewRule rule : repository.rules()) { - String baseKey = "rule." + repository.key() + "." + rule.key(); - String nameKey = baseKey + ".name"; - String ruleName = properties.getProperty(nameKey); - if (ruleName != null) { - rule.setName(ruleName); - } - for (NewParam param : rule.params()) { - String paramDescriptionKey = baseKey + ".param." + param.key(); - String paramDescription = properties.getProperty(paramDescriptionKey); - if (paramDescription != null) { - param.setDescription(paramDescription); - } - } - } - } } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/PmdUnitTestsRulesDefinition.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/PmdUnitTestsRulesDefinition.java deleted file mode 100644 index d0afcabf..00000000 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/rule/PmdUnitTestsRulesDefinition.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.pmd.rule; - -import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.plugins.pmd.PmdConstants; - -public final class PmdUnitTestsRulesDefinition implements RulesDefinition { - - public PmdUnitTestsRulesDefinition() { - // Do nothing - } - - @Override - public void define(Context context) { - NewRepository repository = context - .createRepository(PmdConstants.TEST_REPOSITORY_KEY, PmdConstants.LANGUAGE_KEY) - .setName(PmdConstants.TEST_REPOSITORY_NAME); - - PmdRulesDefinition.extractRulesData(repository, "/org/sonar/plugins/pmd/rules-unit-tests.xml", "/org/sonar/l10n/pmd/rules/pmd-unit-tests"); - - repository.done(); - } -} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdProperty.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdProperty.java index a3f2d7ea..42cdae75 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdProperty.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdProperty.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRule.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRule.java index 79276a9f..b7158c42 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRule.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRule.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,11 +19,11 @@ */ package org.sonar.plugins.pmd.xml; +import org.sonar.plugins.pmd.PmdConstants; + +import javax.annotation.Nullable; import java.util.ArrayList; import java.util.List; -import javax.annotation.Nullable; - -import org.sonar.plugins.pmd.PmdConstants; public class PmdRule { @@ -143,7 +143,7 @@ public void processXpath(String sonarRuleKey) { xpathExp.setCdataValue(xpathExp.getValue()); clazz = PmdConstants.XPATH_CLASS; - language = PmdConstants.LANGUAGE_KEY; + language = PmdConstants.LANGUAGE_JAVA_KEY; name = sonarRuleKey; } } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java index 8e323264..094a1c89 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -27,11 +27,11 @@ import javax.annotation.Nullable; import org.apache.commons.lang3.StringUtils; -import org.jdom.CDATA; -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.output.Format; -import org.jdom.output.XMLOutputter; +import org.jdom2.CDATA; +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.output.Format; +import org.jdom2.output.XMLOutputter; public class PmdRuleSet { @@ -74,19 +74,31 @@ public void setDescription(String description) { * @param destination The writer to which the XML document shall be written. */ public void writeTo(Writer destination) { - Element eltRuleset = new Element("ruleset"); + // PMD 2.0.0 ruleset namespace (compatible with PMD 6/7) + org.jdom2.Namespace ns = org.jdom2.Namespace.getNamespace("http://pmd.sourceforge.net/ruleset/2.0.0"); + org.jdom2.Namespace xsi = org.jdom2.Namespace.getNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance"); + + Element eltRuleset = new Element("ruleset", ns); + // declare xsi namespace and schema location + eltRuleset.addNamespaceDeclaration(xsi); + eltRuleset.setAttribute("schemaLocation", + "http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd", + xsi); + addAttribute(eltRuleset, "name", name); - addChild(eltRuleset, "description", description); + addChild(eltRuleset, "description", description, ns); for (PmdRule pmdRule : rules) { - Element eltRule = new Element("rule"); + Element eltRule = new Element("rule", ns); addAttribute(eltRule, "ref", pmdRule.getRef()); addAttribute(eltRule, "class", pmdRule.getClazz()); addAttribute(eltRule, "message", pmdRule.getMessage()); addAttribute(eltRule, "name", pmdRule.getName()); addAttribute(eltRule, "language", pmdRule.getLanguage()); - addChild(eltRule, "priority", String.valueOf(pmdRule.getPriority())); + if (pmdRule.getPriority() != null) { + addChild(eltRule, "priority", String.valueOf(pmdRule.getPriority()), ns); + } if (pmdRule.hasProperties()) { - Element ruleProperties = processRuleProperties(pmdRule); + Element ruleProperties = processRuleProperties(pmdRule, ns); if (ruleProperties.getContentSize() > 0) { eltRule.addContent(ruleProperties); } @@ -107,6 +119,13 @@ private void addChild(Element elt, String name, @Nullable String text) { } } + // Overload that ensures the child is created within the given namespace + private void addChild(Element elt, String name, @Nullable String text, org.jdom2.Namespace ns) { + if (text != null) { + elt.addContent(new Element(name, ns).setText(text)); + } + } + private void addAttribute(Element elt, String name, @Nullable String value) { if (value != null) { elt.setAttribute(name, value); @@ -132,6 +151,26 @@ private Element processRuleProperties(PmdRule pmdRule) { return eltProperties; } + // Namespaced variant + private Element processRuleProperties(PmdRule pmdRule, org.jdom2.Namespace ns) { + Element eltProperties = new Element("properties", ns); + for (PmdProperty prop : pmdRule.getProperties()) { + if (isPropertyValueNotEmpty(prop)) { + Element eltProperty = new Element("property", ns); + eltProperty.setAttribute("name", prop.getName()); + if (prop.isCdataValue()) { + Element eltValue = new Element("value", ns); + eltValue.addContent(new CDATA(prop.getCdataValue())); + eltProperty.addContent(eltValue); + } else { + eltProperty.setAttribute("value", prop.getValue()); + } + eltProperties.addContent(eltProperty); + } + } + return eltProperties; + } + private boolean isPropertyValueNotEmpty(PmdProperty prop) { if (prop.isCdataValue()) { return StringUtils.isNotEmpty(prop.getCdataValue()); diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java index 3948be3e..87651cc8 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,28 +17,126 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - package org.sonar.plugins.pmd.xml; -import java.io.IOException; -import java.io.Reader; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.rule.RuleScope; import org.sonar.api.utils.ValidationMessages; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; +import org.sonar.plugins.pmd.rule.PmdRuleScopeRegistry; import org.sonar.plugins.pmd.xml.factory.ActiveRulesRuleSetFactory; import org.sonar.plugins.pmd.xml.factory.RuleSetFactory; -import org.sonar.plugins.pmd.xml.factory.RulesProfileRuleSetFactory; import org.sonar.plugins.pmd.xml.factory.XmlRuleSetFactory; +import java.io.IOException; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + /** * Convenience class that creates {@link PmdRuleSet} instances out of the given input. */ public class PmdRuleSets { - private static final Logger LOG = Loggers.get(PmdRuleSets.class); + private static final Logger LOG = LoggerFactory.getLogger(PmdRuleSets.class); + + private static final PmdRuleScopeRegistry SCOPE_REGISTRY = createRegistry(); + + private static PmdRuleScopeRegistry createRegistry() { + try { + PmdRuleScopeRegistry registry = PmdRuleScopeRegistry.getInstance(); + registry.addXmlResources( + "/org/sonar/plugins/pmd/rules-java.xml", + "/org/sonar/plugins/pmd/rules-kotlin.xml" + ); + + ClassLoader cl = PmdRuleSets.class.getClassLoader(); + + loadPluginProvidedSonarRules(cl, registry); + + loadJPinpointPluginRules(cl, registry); + + return registry; + } catch (Exception e) { + LOG.error("Failed to initialize PMD scope registry, using empty registry", e); + return PmdRuleScopeRegistry.getInstance(); // Empty or minimal fallback + } + } + + private static void loadJPinpointPluginRules(ClassLoader cl, PmdRuleScopeRegistry registry) { + // Load jPinpoint Sonar plugin sonar rules if present on classpath (new canonical path only) + try { + String jpinpointPath = "com/jpinpoint/sonar/rules/sonar-pmd-jpinpoint.xml"; + List found = new ArrayList<>(); + Enumeration jpUrls = cl.getResources(jpinpointPath); + while (jpUrls.hasMoreElements()) { + found.add(jpUrls.nextElement()); + } + if (!found.isEmpty()) { + LOG.info("Loading PMD scope definitions from jPinpoint ruleset found at {} location(s)", found.size()); + registry.addXmlUrls(found.toArray(new URL[0])); + } + } catch (IOException e) { + LOG.debug("Could not enumerate jPinpoint ruleset on classpath", e); + } + } + + private static void loadPluginProvidedSonarRules(ClassLoader cl, PmdRuleScopeRegistry registry) { + // Support a generic index file that child plugins can ship to declare arbitrary rule XML paths + String indexResource = "META-INF/sonar-pmd/sonar-pmd-rules-paths.txt"; // each line: a classpath resource path to an XML + try { + Enumeration indexUrls = cl.getResources(indexResource); + int processedIndexes = 0; + List declaredRuleXmls = new ArrayList<>(); + while (indexUrls.hasMoreElements()) { + processedIndexes++; + URL idxUrl = indexUrls.nextElement(); + try (BufferedReader br = new BufferedReader(new InputStreamReader(idxUrl.openStream(), StandardCharsets.UTF_8))) { + String line; + while ((line = br.readLine()) != null) { + processSonarPluginRulesPathLine(cl, line, declaredRuleXmls, idxUrl); + } + } catch (IOException e) { + LOG.warn("Failed to read PMD scope index {}", idxUrl, e); + } + } + if (!declaredRuleXmls.isEmpty()) { + LOG.info("Loading PMD scope definitions from {} resource(s) declared in {} index file(s)", declaredRuleXmls.size(), processedIndexes); + registry.addXmlUrls(declaredRuleXmls.toArray(new URL[0])); + } else if (processedIndexes > 0) { + LOG.debug("No PMD scope resources declared in {} index file(s)", processedIndexes); + } + } catch (IOException e) { + LOG.warn("Failed to enumerate PMD scope index files on classpath", e); + } + } + + private static void processSonarPluginRulesPathLine(ClassLoader cl, String line, List declaredRuleXmls, URL idxUrl) { + String path = line.trim(); + if (path.isEmpty() || path.startsWith("#")) { + return; + } + // Normalize leading slash for ClassLoader lookups + if (path.startsWith("/")) { + path = path.substring(1); + } + try { + Enumeration xmls = cl.getResources(path); + while (xmls.hasMoreElements()) { + declaredRuleXmls.add(xmls.nextElement()); + } + } catch (IOException e) { + LOG.warn("Failed to resolve declared PMD scope resource '{}' from index {}", path, idxUrl); + } + } + + private PmdRuleSets() {} /** * @param configReader A character stream containing the data of the {@link PmdRuleSet}. @@ -55,16 +153,11 @@ public static PmdRuleSet from(Reader configReader, ValidationMessages messages) * @return An instance of PmdRuleSet. The output may be empty but never null. */ public static PmdRuleSet from(ActiveRules activeRules, String repositoryKey) { - return create(new ActiveRulesRuleSetFactory(activeRules, repositoryKey)); + return from(activeRules, repositoryKey, RuleScope.ALL); } - /** - * @param rulesProfile The current rulesprofile. - * @param repositoryKey The key identifier of the rule repository. - * @return An instance of PmdRuleSet. The output may be empty but never null. - */ - public static PmdRuleSet from(RulesProfile rulesProfile, String repositoryKey) { - return create(new RulesProfileRuleSetFactory(rulesProfile, repositoryKey)); + public static PmdRuleSet from(ActiveRules activeRules, String repositoryKey, RuleScope scope) { + return create(new ActiveRulesRuleSetFactory(activeRules, repositoryKey, scope, SCOPE_REGISTRY)); } private static PmdRuleSet create(RuleSetFactory factory) { diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java index a9a0b072..ff9f6810 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,15 +19,13 @@ */ package org.sonar.plugins.pmd.xml.factory; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; +import java.util.*; import org.sonar.api.batch.rule.ActiveRule; import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.rules.RulePriority; -import org.sonar.plugins.pmd.PmdLevelUtils; +import org.sonar.api.rule.RuleScope; +import org.sonar.plugins.pmd.PmdPriorities; +import org.sonar.plugins.pmd.rule.PmdRuleScopeRegistry; import org.sonar.plugins.pmd.xml.PmdProperty; import org.sonar.plugins.pmd.xml.PmdRule; import org.sonar.plugins.pmd.xml.PmdRuleSet; @@ -39,10 +37,14 @@ public class ActiveRulesRuleSetFactory implements RuleSetFactory { private final ActiveRules activeRules; private final String repositoryKey; + private final RuleScope targetScope; + private final PmdRuleScopeRegistry scopeRegistry; - public ActiveRulesRuleSetFactory(ActiveRules activeRules, String repositoryKey) { + public ActiveRulesRuleSetFactory(ActiveRules activeRules, String repositoryKey, RuleScope targetScope, PmdRuleScopeRegistry scopeRegistry) { this.activeRules = activeRules; this.repositoryKey = repositoryKey; + this.targetScope = targetScope; + this.scopeRegistry = scopeRegistry; } @Override @@ -51,19 +53,36 @@ public PmdRuleSet create() { final Collection rules = this.activeRules.findByRepository(repositoryKey); PmdRuleSet ruleset = new PmdRuleSet(); ruleset.setName(repositoryKey); - ruleset.setDescription(String.format("Sonar Profile: %s", repositoryKey)); + ruleset.setDescription("Sonar Profile: " + repositoryKey + " (" + targetScope + ")"); for (ActiveRule rule : rules) { + if (!isRuleInScope(rule, targetScope)) { + continue; + } String configKey = rule.internalKey(); - PmdRule pmdRule = new PmdRule(configKey, PmdLevelUtils.toLevel(RulePriority.valueOfString(rule.severity()))); + PmdRule pmdRule = new PmdRule(configKey, PmdPriorities.ofSonarRule(rule)); addRuleProperties(rule, pmdRule); ruleset.addRule(pmdRule); - pmdRule.processXpath(rule.internalKey()); + pmdRule.processXpath(rule.ruleKey().rule()); } return ruleset; } - private void addRuleProperties(org.sonar.api.batch.rule.ActiveRule activeRule, PmdRule pmdRule) { + private boolean isRuleInScope(ActiveRule activeRule, RuleScope targetScope) { + if (targetScope == RuleScope.ALL) { + return true; + } + + // Get the actual scope from the registry (based on XML rule definition) + RuleScope ruleScope = scopeRegistry.getScope(activeRule.ruleKey().rule()); + + // Rule matches if: + // - Rule scope is ALL (applies to both MAIN and TEST) + // - Rule scope matches the target scope exactly + return ruleScope == RuleScope.ALL || ruleScope == targetScope; + } + + private void addRuleProperties(ActiveRule activeRule, PmdRule pmdRule) { if ((activeRule.params() != null) && !activeRule.params().isEmpty()) { List properties = new ArrayList<>(); for (Map.Entry activeRuleParam : activeRule.params().entrySet()) { diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RuleSetFactory.java index 05a75c6d..7fb5c1bf 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RuleSetFactory.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RuleSetFactory.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RulesProfileRuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RulesProfileRuleSetFactory.java deleted file mode 100644 index d4266590..00000000 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RulesProfileRuleSetFactory.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.pmd.xml.factory; - -import java.util.ArrayList; -import java.util.List; - -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.ActiveRuleParam; -import org.sonar.plugins.pmd.PmdLevelUtils; -import org.sonar.plugins.pmd.xml.PmdProperty; -import org.sonar.plugins.pmd.xml.PmdRule; -import org.sonar.plugins.pmd.xml.PmdRuleSet; - -/** - * Factory class to create {@link org.sonar.plugins.pmd.xml.PmdRuleSet} out of {@link org.sonar.api.profiles.RulesProfile}. - */ -public class RulesProfileRuleSetFactory implements RuleSetFactory { - - private final RulesProfile rulesProfile; - private final String repositoryKey; - - public RulesProfileRuleSetFactory(RulesProfile rulesProfile, String repositoryKey) { - this.rulesProfile = rulesProfile; - this.repositoryKey = repositoryKey; - } - - @Override - public PmdRuleSet create() { - - final PmdRuleSet ruleset = new PmdRuleSet(); - ruleset.setName(repositoryKey); - ruleset.setDescription(String.format("Sonar Profile: %s", repositoryKey)); - - final List activeRules = rulesProfile.getActiveRulesByRepository(repositoryKey); - - for (ActiveRule activeRule : activeRules) { - if (activeRule.getRule().getRepositoryKey().equals(repositoryKey)) { - String configKey = activeRule.getRule().getConfigKey(); - PmdRule rule = new PmdRule(configKey, PmdLevelUtils.toLevel(activeRule.getSeverity())); - addRuleProperties(activeRule, rule); - ruleset.addRule(rule); - rule.processXpath(activeRule.getRuleKey()); - } - } - - return ruleset; - } - - private void addRuleProperties(ActiveRule activeRule, PmdRule pmdRule) { - if ((activeRule.getActiveRuleParams() != null) && !activeRule.getActiveRuleParams().isEmpty()) { - List properties = new ArrayList<>(); - for (ActiveRuleParam activeRuleParam : activeRule.getActiveRuleParams()) { - properties.add(new PmdProperty(activeRuleParam.getRuleParam().getKey(), activeRuleParam.getValue())); - } - pmdRule.setProperties(properties); - } - } - - @Override - public void close() { - // Unnecessary in this class. - } -} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java index e18c402b..d08a07ad 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,30 +19,30 @@ */ package org.sonar.plugins.pmd.xml.factory; -import java.io.IOException; -import java.io.Reader; -import java.util.List; -import javax.annotation.Nullable; - -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.JDOMException; -import org.jdom.Namespace; -import org.jdom.input.SAXBuilder; +import org.jdom2.Document; +import org.jdom2.Element; +import org.jdom2.JDOMException; +import org.jdom2.Namespace; +import org.jdom2.input.SAXBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.utils.ValidationMessages; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; import org.sonar.plugins.pmd.xml.PmdProperty; import org.sonar.plugins.pmd.xml.PmdRule; import org.sonar.plugins.pmd.xml.PmdRuleSet; -import org.sonar.plugins.pmd.xml.PmdRuleSets; + +import javax.annotation.Nullable; +import javax.xml.XMLConstants; +import java.io.IOException; +import java.io.Reader; +import java.util.List; /** * Factory class to create {@link org.sonar.plugins.pmd.xml.PmdRuleSet} out of XML. */ public class XmlRuleSetFactory implements RuleSetFactory { - private static final Logger LOG = Loggers.get(PmdRuleSets.class); + private static final Logger LOG = LoggerFactory.getLogger(XmlRuleSetFactory.class); private static final String INVALID_INPUT = "The PMD configuration file is not valid"; private final Reader source; @@ -53,7 +53,7 @@ public XmlRuleSetFactory(Reader source, ValidationMessages messages) { this.messages = messages; } - @SuppressWarnings("unchecked") + private List getChildren(Element parent, String childName, @Nullable Namespace namespace) { if (namespace == null) { return parent.getChildren(childName); @@ -99,10 +99,13 @@ public void close() throws IOException { */ @Override public PmdRuleSet create() { - final SAXBuilder parser = new SAXBuilder(); + final SAXBuilder builder = new SAXBuilder(); + // prevent XXE attacks + builder.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, ""); + builder.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); final Document dom; try { - dom = parser.build(source); + dom = builder.build(source); } catch (JDOMException | IOException e) { if (messages != null) { messages.addErrorText(INVALID_INPUT + " : " + e.getMessage()); @@ -124,7 +127,7 @@ public PmdRuleSet create() { result.setDescription(descriptionElement.getValue()); } - for (Element eltRule : getChildren(eltResultset, "rule", namespace)) { + for (Element eltRule : getChildren(eltResultset, "org/sonar/plugins/pmd/rule", namespace)) { PmdRule pmdRule = new PmdRule(eltRule.getAttributeValue("ref")); pmdRule.setClazz(eltRule.getAttributeValue("class")); pmdRule.setName(eltRule.getAttributeValue("name")); diff --git a/sonar-pmd-plugin/src/main/resources/com/sonar/sqale/pmd-model-kotlin.xml b/sonar-pmd-plugin/src/main/resources/com/sonar/sqale/pmd-model-kotlin.xml new file mode 100644 index 00000000..bbe398f1 --- /dev/null +++ b/sonar-pmd-plugin/src/main/resources/com/sonar/sqale/pmd-model-kotlin.xml @@ -0,0 +1,27 @@ + + + REUSABILITY + Reusability + + MODULARITY + Modularity + + pmd-kotlin + FunctionNameTooShort + + remediationFunction + CONSTANT_ISSUE + + + offset + 1 + min + + + + + TRANSPORTABILITY + Transportability + + + diff --git a/sonar-pmd-plugin/src/main/resources/com/sonar/sqale/pmd-model.xml b/sonar-pmd-plugin/src/main/resources/com/sonar/sqale/pmd-model.xml index 45954e7e..552451cc 100644 --- a/sonar-pmd-plugin/src/main/resources/com/sonar/sqale/pmd-model.xml +++ b/sonar-pmd-plugin/src/main/resources/com/sonar/sqale/pmd-model.xml @@ -1219,19 +1219,19 @@ min - - pmd - EmptyInitializer - - remediationFunction - CONSTANT_ISSUE - - - offset - 20 - min - - + + + + + + + + + + + + + pmd AvoidUsingVolatile @@ -2480,19 +2480,20 @@ LOGIC_CHANGEABILITY Logic - - common-java - DuplicatedBlocks - - remediationFunction - LINEAR - - - remediationFactor - 1 - h - - + + + + + + + + + + + + + + pmd AvoidDuplicateLiterals @@ -3600,7 +3601,7 @@ - pmd-unit-tests + pmd JUnit4TestShouldUseBeforeAnnotation remediationFunction @@ -3613,7 +3614,7 @@ - pmd-unit-tests + pmd JUnit4TestShouldUseAfterAnnotation remediationFunction @@ -3626,7 +3627,7 @@ - pmd-unit-tests + pmd JUnitUseExpected remediationFunction @@ -3639,7 +3640,7 @@ - pmd-unit-tests + pmd JUnitTestContainsTooManyAsserts remediationFunction @@ -3652,7 +3653,7 @@ - pmd-unit-tests + pmd JUnit4TestShouldUseTestAnnotation remediationFunction @@ -3665,7 +3666,7 @@ - pmd-unit-tests + pmd JUnitTestsShouldIncludeAssert remediationFunction @@ -3678,7 +3679,7 @@ - pmd-unit-tests + pmd TestClassWithoutTestCases remediationFunction @@ -3690,8 +3691,8 @@ min - - pmd-unit-tests + - pmd-unit-tests + pmd JUnit4SuitesShouldUseSuiteAnnotation remediationFunction @@ -3820,7 +3821,7 @@ - pmd-unit-tests + pmd JUnitStaticSuite remediationFunction @@ -3832,8 +3833,8 @@ min - - pmd-unit-tests + - pmd-unit-tests + pmd JUnitSpelling remediationFunction @@ -3885,7 +3886,7 @@ - pmd-unit-tests + pmd JUnitAssertionsShouldIncludeMessage remediationFunction @@ -3898,7 +3899,7 @@ - pmd-unit-tests + pmd UnnecessaryBooleanAssertion remediationFunction @@ -3910,8 +3911,8 @@ min - - pmd-unit-tests + diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd.properties b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd.properties deleted file mode 100644 index 07530a56..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd.properties +++ /dev/null @@ -1,359 +0,0 @@ -rule.pmd.StringInstantiation.name=String Instantiation -rule.pmd.RemoteInterfaceNamingConvention.name=Remote Interface Naming Convention -rule.pmd.InefficientEmptyStringCheck.name=Inefficient Empty String Check -rule.pmd.DoubleCheckedLocking.name=Double checked locking -rule.pmd.EmptyStaticInitializer.name=Empty Static Initializer -rule.pmd.DoNotThrowExceptionInFinally.name=Strict Exception - Do not throw exception in finally -rule.pmd.SignatureDeclareThrowsException.name=Signature Declare Throws Exception -rule.pmd.UseEqualsToCompareStrings.name=Use Equals To Compare Strings -rule.pmd.VariableNamingConventions.name=Naming - Variable naming conventions -rule.pmd.VariableNamingConventions.param.memberSuffix=A suffix for member variables -rule.pmd.VariableNamingConventions.param.memberPrefix=A prefix for member variables -rule.pmd.VariableNamingConventions.param.staticSuffix=A suffix for static variables -rule.pmd.VariableNamingConventions.param.staticPrefix=A prefix for static variables -rule.pmd.PositionLiteralsFirstInComparisons.name=Position Literals First In Comparisons -rule.pmd.ConfusingTernary.name=Confusing Ternary -rule.pmd.ShortMethodName.name=Naming - Short method name -rule.pmd.ShortMethodName.param.minimum=Number of characters that are required as a minimum for a variable name -rule.pmd.UncommentedEmptyConstructor.name=Uncommented Empty Constructor -rule.pmd.UncommentedEmptyConstructor.param.ignoreExplicitConstructorInvocation=Ignore explicit constructor invocation when deciding whether constructor is empty or not. Default is false. -rule.pmd.UnusedFormalParameter.name=Unused formal parameter -rule.pmd.ExcessiveParameterList.name=Excessive Parameter List -rule.pmd.ExcessiveParameterList.param.minimum=The parameter count reporting threshold. Default is 10. -rule.pmd.OnlyOneReturn.name=Only One Return -rule.pmd.UseStringBufferForStringAppends.name=Use String Buffer For String Appends -rule.pmd.AvoidDollarSigns.name=Naming - Avoid dollar signs -rule.pmd.AvoidUsingShortType.name=Avoid Using Short Type -rule.pmd.NonCaseLabelInSwitchStatement.name=Non Case Label In Switch Statement -rule.pmd.CyclomaticComplexity.name=Code size - cyclomatic complexity -rule.pmd.CyclomaticComplexity.param.methodReportLevel=Cyclomatic complexity reporting threshold. Range: 1 - 50. -rule.pmd.CyclomaticComplexity.param.classReportLevel=Total class complexity reporting threshold. Range: 1 - 600. -rule.pmd.AvoidEnumAsIdentifier.name=Avoid Enum As Identifier -rule.pmd.AvoidFieldNameMatchingMethodName.name=Naming - Avoid field name matching method name -rule.pmd.InstantiationToGetClass.name=Instantiation To Get Class -rule.pmd.SuspiciousHashcodeMethodName.name=Naming - Suspicious Hashcode method name -rule.pmd.MDBAndSessionBeanNamingConvention.name=Message Driven Bean And Session Bean Naming Convention -rule.pmd.UselessOperationOnImmutable.name=Useless Operation On Immutable -rule.pmd.ReturnEmptyArrayRatherThanNull.name=Return empty array rather than null -rule.pmd.LongInstantiation.name=Java5 migration - Long instantiation -rule.pmd.ExcessiveImports.name=Coupling - excessive imports -rule.pmd.ExcessiveImports.param.minimum=The import count reporting threshold. Default is 30. -rule.pmd.StringBufferInstantiationWithChar.name=String Buffer Instantiation With Char -rule.pmd.StringToString.name=String To String -rule.pmd.MissingSerialVersionUID.name=Missing Serial Version UID -rule.pmd.UnconditionalIfStatement.name=Unconditional If Statement -rule.pmd.AvoidArrayLoops.name=Avoid Array Loops -rule.pmd.ShortVariable.name=Short Variable -rule.pmd.ShortVariable.param.minimum=Number of characters that are required as a minimum for a variable name -rule.pmd.UnusedLocalVariable.name=Unused local variable -rule.pmd.SuspiciousConstantFieldName.name=Naming - Suspicious constant field name -rule.pmd.UseArrayListInsteadOfVector.name=Use Array List Instead Of Vector -rule.pmd.CallSuperLast.name=Android - call super last -rule.pmd.SimplifyBooleanExpressions.name=Avoid unnecessary comparisons in boolean expressions -rule.pmd.FinalizeOnlyCallsSuperFinalize.name=Finalize Only Calls Super Finalize -rule.pmd.ImmutableField.name=Immutable Field -rule.pmd.BooleanInstantiation.name=Boolean Instantiation -rule.pmd.StaticEJBFieldShouldBeFinal.name=Static EJB Field Should Be Final -rule.pmd.AvoidFieldNameMatchingTypeName.name=Naming - Avoid field name matching type name -rule.pmd.OverrideBothEqualsAndHashcode.name=Override both equals and hashcode -rule.pmd.BrokenNullCheck.name=Broken Null Check -rule.pmd.NPathComplexity.name=NPath complexity -rule.pmd.NPathComplexity.param.minimum=The npath reporting threshold. Default is 200. -rule.pmd.CouplingBetweenObjects.name=Coupling between objects -rule.pmd.CouplingBetweenObjects.param.threshold=The unique type reporting threshold. Default is 20. -rule.pmd.IntegerInstantiation.name=Integer Instantiation -rule.pmd.DoNotCallGarbageCollectionExplicitly.name=Do not call garbage collection explicitly -rule.pmd.BeanMembersShouldSerialize.name=Bean Members Should Serialize -rule.pmd.BeanMembersShouldSerialize.param.prefix=A variable prefix to skip, i.e., m_ -rule.pmd.IdempotentOperations.name=Idempotent Operations -rule.pmd.NcssTypeCount.name=Ncss Type Count -rule.pmd.NcssTypeCount.param.minimum=The type NCSS count reporting threshold. Default is 1500. -rule.pmd.AvoidThrowingRawExceptionTypes.name=Avoid Throwing Raw Exception Types -rule.pmd.ImportFromSamePackage.name=Import From Same Package -rule.pmd.UnnecessaryLocalBeforeReturn.name=Unnecessary Local Before Return -rule.pmd.IfElseStmtsMustUseBraces.name=If Else Stmts Must Use Braces -rule.pmd.ForLoopsMustUseBraces.name=For Loops Must Use Braces -rule.pmd.UseIndexOfChar.name=Use Index Of Char -rule.pmd.EmptyMethodInAbstractClassShouldBeAbstract.name=Empty Method In Abstract Class Should Be Abstract -rule.pmd.LongVariable.name=Long Variable -rule.pmd.LongVariable.param.minimum=The variable length reporting threshold. Default is 17. -rule.pmd.MissingBreakInSwitch.name=Missing Break In Switch -rule.pmd.UnnecessaryParentheses.name=Unnecessary parentheses -rule.pmd.MisleadingVariableName.name=Naming - Misleading variable name -rule.pmd.AbstractClassWithoutAnyMethod.name=Abstract class without any methods -rule.pmd.DoNotCallSystemExit.name=Do Not Call System Exit -rule.pmd.AvoidThrowingNullPointerException.name=Avoid Throwing Null Pointer Exception -rule.pmd.EmptySynchronizedBlock.name=Empty Synchronized Block -rule.pmd.SwitchStmtsShouldHaveDefault.name=Switch statements should have default -rule.pmd.UseNotifyAllInsteadOfNotify.name=Use Notify All Instead Of Notify -rule.pmd.UnusedPrivateMethod.name=Unused private method -rule.pmd.MoreThanOneLogger.name=More Than One Logger -rule.pmd.EmptyTryBlock.name=Empty Try Block -rule.pmd.AvoidDeeplyNestedIfStmts.name=Avoid Deeply Nested If Stmts -rule.pmd.AvoidDeeplyNestedIfStmts.param.problemDepth=The if statement depth reporting threshold. Default is 3. -rule.pmd.LocalHomeNamingConvention.name=Local Home Naming Convention -rule.pmd.AvoidUsingNativeCode.name=Avoid Using Native Code -rule.pmd.LooseCoupling.name=Loose coupling -rule.pmd.FinalizeOverloaded.name=Finalize Overloaded -rule.pmd.AvoidThreadGroup.name=Avoid Thread Group -rule.pmd.UnnecessaryConstructor.name=Unnecessary constructor -rule.pmd.LocalVariableCouldBeFinal.name=Local variable could be final -rule.pmd.MethodArgumentCouldBeFinal.name=Method Argument Could Be Final -rule.pmd.AvoidAssertAsIdentifier.name=Avoid Assert As Identifier -rule.pmd.SuspiciousOctalEscape.name=Suspicious Octal Escape -rule.pmd.ByteInstantiation.name=Java5 migration - Byte instantiation -rule.pmd.AvoidConstantsInterface.name=Avoid Constants Interface -rule.pmd.LocalInterfaceSessionNamingConvention.name=Local Interface Session Naming Convention -rule.pmd.CloneMethodMustImplementCloneable.name=Clone method must implement Cloneable -rule.pmd.MethodWithSameNameAsEnclosingClass.name=Naming - Method with same name as enclosing class -rule.pmd.ConsecutiveLiteralAppends.name=Consecutive Literal Appends -rule.pmd.ConsecutiveLiteralAppends.param.threshold=The report threshold. Default is 1. -rule.pmd.CallSuperInConstructor.name=Call Super In Constructor -rule.pmd.SimplifyConditional.name=Simplify Conditional -rule.pmd.InefficientStringBuffering.name=Inefficient String Buffering -rule.pmd.EmptyStatementNotInLoop.name=Empty Statement Not In Loop -rule.pmd.AvoidSynchronizedAtMethodLevel.name=Avoid Synchronized At Method Level -rule.pmd.NcssMethodCount.name=Ncss Method Count -rule.pmd.NcssMethodCount.param.minimum=The method NCSS count reporting threshold. Default is 100. -rule.pmd.AbstractClassWithoutAbstractMethod.name=Abstract Class Without Abstract Method -rule.pmd.AbstractNaming.name=Abstract naming -rule.pmd.AbstractNaming.param.strict=Also flag classes, that are named Abstract, but are not abstract -rule.pmd.DoNotExtendJavaLangError.name=Do Not Extend Java Lang Error -rule.pmd.NoPackage.name=No package -rule.pmd.ExcessiveMethodLength.name=Excessive Method Length -rule.pmd.ExcessiveMethodLength.param.minimum=The method size reporting threshold. Default is 100. -rule.pmd.SwitchDensity.name=Switch Density -rule.pmd.SwitchDensity.param.minimum=The switch statement ratio reporting threshold. Default is 10. -rule.pmd.UseLocaleWithCaseConversions.name=Use Locale With Case Conversions -rule.pmd.DuplicateImports.name=Duplicate Imports -rule.pmd.ProperLogger.name=Proper Logger -rule.pmd.ProperLogger.param.staticLoggerName=Default is LOG -rule.pmd.PreserveStackTrace.name=Preserve Stack Trace -rule.pmd.FinalizeDoesNotCallSuperFinalize.name=Finalize Does Not Call Super Finalize -rule.pmd.DontImportSun.name=Dont Import Sun -rule.pmd.ReplaceVectorWithList.name=Replace Vector With List -rule.pmd.ClassNamingConventions.name=Naming - Class naming conventions -rule.pmd.UncommentedEmptyMethodBody.name=Uncommented Empty Method -rule.pmd.AvoidAccessibilityAlteration.name=Avoid Accessibility Alteration -rule.pmd.IfStmtsMustUseBraces.name=If Stmts Must Use Braces -rule.pmd.AvoidReassigningParameters.name=Avoid Reassigning Parameters -rule.pmd.OptimizableToArrayCall.name=Optimizable To Array Call -rule.pmd.FinalizeShouldBeProtected.name=Finalize Should Be Protected -rule.pmd.AddEmptyString.name=Add Empty String -rule.pmd.EmptyFinallyBlock.name=Empty Finally Block -rule.pmd.EqualsNull.name=Equals Null -rule.pmd.SuspiciousEqualsMethodName.name=Naming - Suspicious equals method name -rule.pmd.UnnecessaryWrapperObjectCreation.name=Unnecessary Wrapper Object Creation -rule.pmd.AvoidStringBufferField.name=Avoid StringBuffer field -rule.pmd.SimplifyBooleanReturns.name=Simplify boolean returns -rule.pmd.DefaultLabelNotLastInSwitchStmt.name=Default label not last in switch statement -rule.pmd.AvoidUsingOctalValues.name=Avoid Using Octal Values -rule.pmd.AvoidCallingFinalize.name=Avoid Calling Finalize -rule.pmd.ExcessiveClassLength.name=Excessive Class Length -rule.pmd.ExcessiveClassLength.param.minimum=The class size reporting threshold. Default is 1000. -rule.pmd.FinalFieldCouldBeStatic.name=Final Field Could Be Static -rule.pmd.AvoidRethrowingException.name=Avoid Rethrowing Exception -rule.pmd.AvoidUsingHardCodedIP.name=Avoid Using Hard Coded IP -rule.pmd.AvoidUsingHardCodedIP.param.checkAddressTypes=Defines which IP types should be considered (IPv4, IPv6, IPv4 mapped as IPv6). -rule.pmd.ProtectLogD.name=Android - Protect LOGD -rule.pmd.ProtectLogV.name=Android - Protect LOGV -rule.pmd.MethodNamingConventions.name=Naming - Method naming conventions -rule.pmd.NonStaticInitializer.name=Non Static Initializer -rule.pmd.AvoidProtectedFieldInFinalClass.name=Avoid Protected Field In Final Class -rule.pmd.CompareObjectsWithEquals.name=Compare Objects With Equals -rule.pmd.SystemPrintln.name=System Println -rule.pmd.XPathRule.name=XPath rule template -rule.pmd.XPathRule.param.message=Message to display when a violation occurs. -rule.pmd.XPathRule.param.xpath=XPath expressions. -rule.pmd.DontImportJavaLang.name=Dont Import Java Lang -rule.pmd.TooManyMethods.name=Too many methods -rule.pmd.TooManyMethods.param.maxmethods=The method count reporting threshold. Default is 10. -rule.pmd.CloneThrowsCloneNotSupportedException.name=Clone Throws Clone Not Supported Exception -rule.pmd.EmptyCatchBlock.name=Empty Catch Block -rule.pmd.EmptyCatchBlock.param.allowCommentedBlocks=Empty blocks containing comments will be skipped. Default is false. -rule.pmd.CollapsibleIfStatements.name=Collapsible If Statements -rule.pmd.ForLoopShouldBeWhileLoop.name=For Loop Should Be While Loop -rule.pmd.UseCorrectExceptionLogging.name=Use Correct Exception Logging -rule.pmd.ReplaceEnumerationWithIterator.name=Replace Enumeration With Iterator -rule.pmd.EmptyWhileStmt.name=Empty While Stmt -rule.pmd.ReplaceHashtableWithMap.name=Replace Hashtable With Map -rule.pmd.AvoidMultipleUnaryOperators.name=Avoid Multiple Unary Operators -rule.pmd.UselessOverridingMethod.name=Useless Overriding Method -rule.pmd.UselessOverridingMethod.param.ignoreAnnotations=Ignore annotations. Default is false. -rule.pmd.SimpleDateFormatNeedsLocale.name=Simple Date Format Needs Locale -rule.pmd.UnnecessaryFinalModifier.name=Unnecessary Final Modifier -rule.pmd.CallSuperFirst.name=Android - call super first -rule.pmd.UseArraysAsList.name=Use Arrays As List -rule.pmd.CloseResource.name=Close Resource -rule.pmd.CloseResource.param.closeTargets=Methods which may close this resource. Default is 'close'. -rule.pmd.CloseResource.param.types=Resources to check. Default value is 'Connection,Statement,ResultSet', -rule.pmd.EmptySwitchStatements.name=Empty Switch Statements -rule.pmd.AccessorClassGeneration.name=Accessor Class Generation -rule.pmd.PackageCase.name=Package case -rule.pmd.TooFewBranchesForASwitchStatement.name=Too few branches for a switch statement -rule.pmd.TooFewBranchesForASwitchStatement.param.minimumNumberCaseForASwitch=Minimum number of branches for a switch. Default is 3. -rule.pmd.TooManyStaticImports.name=Too Many Static Imports -rule.pmd.TooManyStaticImports.param.maximumStaticImports=All static imports can be disallowed by setting this to 0. Default is 4. -rule.pmd.EmptyIfStmt.name=Empty If Stmt -rule.pmd.DataflowAnomalyAnalysis.name=Dataflow Anomaly Analysis -rule.pmd.DataflowAnomalyAnalysis.param.maxViolations=The maximum number of violations per class. Default is 100. -rule.pmd.DataflowAnomalyAnalysis.param.maxPaths=The maximum number of checked paths per method. A lower value will increase the performance of the rule but may decrease the number of found anomalies. Default is 1000. -rule.pmd.NonThreadSafeSingleton.name=Non Thread Safe Singleton -rule.pmd.NonThreadSafeSingleton.param.checkNonStaticFields=Do not set this to true and checkNonStaticMethods to false. Default is false. -rule.pmd.NonThreadSafeSingleton.param.checkNonStaticMethods=Do not set this to false and checkNonStaticFields to true. Default is true. -rule.pmd.WhileLoopsMustUseBraces.name=While Loops Must Use Braces -rule.pmd.UnusedModifier.name=Unused Modifier -rule.pmd.ClassCastExceptionWithToArray.name=Class Cast Exception With To Array -rule.pmd.EmptyInitializer.name=Basic - Empty Initializer -rule.pmd.DoNotUseThreads.name=Do Not Use Threads -rule.pmd.InsufficientStringBufferDeclaration.name=Insufficient String Buffer Declaration -rule.pmd.AvoidUsingVolatile.name=Avoid Using Volatile -rule.pmd.UseStringBufferLength.name=Use String Buffer Length -rule.pmd.AvoidInstantiatingObjectsInLoops.name=Avoid instantiating objects in loops -rule.pmd.UnsynchronizedStaticDateFormatter.name=Unsynchronized Static Date Formatter -rule.pmd.MissingStaticMethodInNonInstantiatableClass.name=Missing Static Method In Non Instantiatable Class -rule.pmd.EmptyFinalizer.name=Empty Finalizer -rule.pmd.ShortInstantiation.name=Java5 migration - Short instantiation -rule.pmd.ConstructorCallsOverridableMethod.name=Constructor Calls Overridable Method -rule.pmd.DefaultPackage.name=Default Package -rule.pmd.NcssConstructorCount.name=Ncss Constructor Count -rule.pmd.NcssConstructorCount.param.minimum=The constructor NCSS count reporting threshold. Default is 100. -rule.pmd.AvoidCatchingThrowable.name=Avoid Catching Throwable -rule.pmd.AvoidDecimalLiteralsInBigDecimalConstructor.name=Avoid Decimal Literals In Big Decimal Constructor -rule.pmd.AvoidDuplicateLiterals.name=Avoid Duplicate Literals -rule.pmd.AvoidDuplicateLiterals.param.separator=Separator used in the exceptionlist. Default is , -rule.pmd.AvoidDuplicateLiterals.param.skipAnnotations=Skip literals within Annotations. Default is false. -rule.pmd.AvoidDuplicateLiterals.param.exceptionfile=File containing strings to skip (one string per line), only used if exceptionlist is not set. -rule.pmd.AvoidDuplicateLiterals.param.threshold=The number of duplicate literals reporting threshold. Default is 4. -rule.pmd.AvoidDuplicateLiterals.param.exceptionList=Strings in that list are skipped. -rule.pmd.AvoidDuplicateLiterals.param.minimumLength=Minimum string length to check -rule.pmd.AvoidDuplicateLiterals.param.maxDuplicateLiterals=Max duplicate literals -rule.pmd.ExcessivePublicCount.name=Excessive Public Count -rule.pmd.ExcessivePublicCount.param.minimum=The public item reporting threshold. Default is 45. -rule.pmd.ClassWithOnlyPrivateConstructorsShouldBeFinal.name=Class with only private constructors should be final -rule.pmd.NullAssignment.name=Null Assignment -rule.pmd.MisplacedNullCheck.name=Misplaced Null Check -rule.pmd.SingularField.name=Singular Field -rule.pmd.UnusedImports.name=Unused imports -rule.pmd.UselessStringValueOf.name=Useless String Value Of -rule.pmd.UnusedNullCheckInEquals.name=Unused Null Check In Equals -rule.pmd.AvoidCatchingNPE.name=Avoid Catching NPE -rule.pmd.CheckResultSet.name=Check ResultSet -rule.pmd.ReturnFromFinallyBlock.name=Return From Finally Block -rule.pmd.UseProperClassLoader.name=Use Proper Class Loader -rule.pmd.UseUtilityClass.name=Use Utility Class -rule.pmd.ProperCloneImplementation.name=Proper clone implementation -rule.pmd.UseCollectionIsEmpty.name=Use Collection Is Empty -rule.pmd.AvoidThrowingNewInstanceOfSameException.name=Strict Exception - Avoid throwing new instance of same exception -rule.pmd.SimplifyStartsWith.name=Simplify Starts With -rule.pmd.AvoidFinalLocalVariable.name=Avoid Final Local Variable -rule.pmd.TooManyFields.name=Too Many Fields -rule.pmd.TooManyFields.param.maxfields=The field count reporting threshold. Default is 15. -rule.pmd.MethodReturnsInternalArray.name=Security - Method returns internal array -rule.pmd.AvoidInstanceofChecksInCatchClause.name=Avoid Instanceof Checks In Catch Clause -rule.pmd.LoggerIsNotStaticFinal.name=Logger Is Not Static Final -rule.pmd.BigIntegerInstantiation.name=Big Integer Instantiation -rule.pmd.AssignmentInOperand.name=Assignment In Operand -rule.pmd.BadComparison.name=Bad Comparison -rule.pmd.UnnecessaryReturn.name=Unnecessary Return -rule.pmd.AssignmentToNonFinalStatic.name=Assignment To Non Final Static -rule.pmd.UnnecessaryConversionTemporary.name=Unnecessary Conversion Temporary -rule.pmd.JumbledIncrementer.name=Jumbled Incrementer -rule.pmd.BooleanGetMethodName.name=Boolean Get Method Name -rule.pmd.BooleanGetMethodName.param.checkParameterizedMethods=Check parameterized methods. Default is false. -rule.pmd.AvoidPrintStackTrace.name=Avoid Print Stack Trace -rule.pmd.RemoteSessionInterfaceNamingConvention.name=Remote Session Interface Naming Convention -rule.pmd.UnnecessaryCaseChange.name=Unnecessary Case Change -rule.pmd.ArrayIsStoredDirectly.name=Security - Array is stored directly -rule.pmd.ExceptionAsFlowControl.name=Exception As Flow Control -rule.pmd.UnusedPrivateField.name=Unused Private Field -rule.pmd.AtLeastOneConstructor.name=At Least One Constructor -rule.pmd.AppendCharacterWithChar.name=Append Character With Char -rule.pmd.GenericsNaming.name=Generics Naming -rule.pmd.AvoidCatchingGenericException.name=Avoid Catching Generic Exception -rule.pmd.AvoidLosingExceptionInformation.name=Avoid Losing Exception Information -rule.pmd.AvoidLiteralsInIfCondition.name=Avoid Literals In If Condition -rule.pmd.UseConcurrentHashMap.name=Use ConcurrentHashMap -rule.pmd.DoNotHardCodeSDCard.name=Android - Do Not Hard Code SD Card -rule.pmd.DontCallThreadRun.name=Dont Call Thread Run -rule.pmd.GuardDebugLogging.name=Guard Debug Logging -rule.pmd.AvoidBranchingStatementAsLastInLoop.name=Avoid Branching Statement As Last In Loop -rule.pmd.CheckSkipResult.name=Check Skip Result -rule.pmd.DontUseFloatTypeForLoopIndices.name=Dont Use Float Type For Loop Indices -rule.pmd.ExtendsObject.name=Extends Object -rule.pmd.CommentContent.name=Comment Content -rule.pmd.CommentRequired.name=Comment Required -rule.pmd.CommentRequired.param.violationSuppressXPath=Suppress violations on nodes which match a given relative XPath expression. -rule.pmd.AvoidPrefixingMethodParameters.name=Avoid Prefixing Method Parameters -rule.pmd.OneDeclarationPerLine.name=One Declaration Per Line -rule.pmd.UseObjectForClearerAPI.name=Use Object For Clearer API -rule.pmd.LawOfDemeter.name=Law Of Demeter -rule.pmd.LoosePackageCoupling.name=Loose Package Coupling -rule.pmd.AvoidProtectedMethodInFinalClassNotExtending.name=Avoid Protected Method In Final Class Not Extending -rule.pmd.FieldDeclarationsShouldBeAtStartOfClass.name=Field Declarations Should Be At Start Of Class -rule.pmd.FieldDeclarationsShouldBeAtStartOfClass.param.ignoreEnumDeclarations=Ignore Enum Declarations that precede fields. -rule.pmd.FieldDeclarationsShouldBeAtStartOfClass.param.ignoreAnonymousClassDeclarations=Ignore Field Declarations, that are initialized with anonymous class declarations -rule.pmd.GodClass.name=God Class -rule.pmd.LogicInversion.name=Logic Inversion -rule.pmd.PositionLiteralsFirstInCaseInsensitiveComparisons.name=Position Literals First In Case Insensitive Comparisons -rule.pmd.UseVarargs.name=Use Varargs -rule.pmd.EmptyStatementBlock.name=Empty Statement Block -rule.pmd.UnnecessaryFullyQualifiedName.name=Unnecessary Fully Qualified Name -rule.pmd.GuardLogStatement.name=Guard Log Statement -rule.pmd.GuardLogStatementJavaUtil.name=Guard Log Statement Java Util -rule.pmd.ShortClassName.name=Short Class Name -rule.pmd.ShortClassName.param.minimum=Number of characters that are required as a minimum for a class name. -rule.pmd.PrematureDeclaration.name=Premature Declaration -rule.pmd.RedundantFieldInitializer.name=Redundant Field Initializer -rule.pmd.ConsecutiveAppendsShouldReuse.name=Consecutive Appends Should Reuse -rule.pmd.CloneMethodMustImplementCloneableWithTypeResolution.name=Clone Method Must Implement Cloneable (With Type Resolution) -rule.pmd.LooseCouplingWithTypeResolution.name=Loose Coupling (With Type Resolution) -rule.pmd.SignatureDeclareThrowsExceptionWithTypeResolution.name=Signature Declare Throws Exception (With Type Resolution) -rule.pmd.SignatureDeclareThrowsExceptionWithTypeResolution.param.IgnoreJUnitCompletely=If true, all methods in a JUnit testcase may throw Exception -rule.pmd.UnusedImportsWithTypeResolution.name=Unused Imports (With Type Resolution) -rule.pmd.UselessParentheses.name=Useless Parentheses -rule.pmd.StdCyclomaticComplexity.name=Std Cyclomatic Complexity -rule.pmd.StdCyclomaticComplexity.param.reportLevel=Cyclomatic Complexity reporting threshold -rule.pmd.StdCyclomaticComplexity.param.showClassesComplexity=Add class average violations to the report -rule.pmd.StdCyclomaticComplexity.param.showMethodsComplexity=Add method average violations to the report -rule.pmd.ModifiedCyclomaticComplexity.name=Modified Cyclomatic Complexity -rule.pmd.ModifiedCyclomaticComplexity.param.reportLevel=Cyclomatic Complexity reporting threshold -rule.pmd.ModifiedCyclomaticComplexity.param.showClassesComplexity=Add class average violations to the report -rule.pmd.ModifiedCyclomaticComplexity.param.showMethodsComplexity=Add method average violations to the report -rule.pmd.CommentSize.name=Comment Size -rule.pmd.CommentSize.param.violationSuppressRegex=Suppress violations with messages matching a regular expression -rule.pmd.CommentSize.param.violationSuppressXPath=Suppress violations on nodes which match a given relative XPath expression -rule.pmd.CommentSize.param.maxLines=Maximum lines -rule.pmd.CommentSize.param.maxLineLength=Maximum line length -rule.pmd.SimplifiedTernary.name=Ternary operator with a boolean literal can be simplified with a boolean expression -rule.pmd.CloneMethodMustBePublic.name=By convention, classes that implement the Cloneable interface should override Object.clone (which is protected) with a public method -rule.pmd.CloneMethodReturnTypeMustMatchClassName.name=If a class implements Cloneable the return type of the method clone() must be the class name -rule.pmd.CommentDefaultAccessModifier.name=Comment the default access modifier -rule.pmd.CommentDefaultAccessModifier.param.regex=Regular expression -rule.pmd.CommentDefaultAccessModifier.param.violationSuppressRegex=Suppress violations with messages matching a regular expression -rule.pmd.CommentDefaultAccessModifier.param.violationSuppressXPath=Suppress violations on nodes which match a given relative XPath expression -rule.pmd.SingletonClassReturningNewInstance.name=getInstance should cache the instance -rule.pmd.SingletonClassReturningNewInstance.param.violationSuppressRegex=Suppress violations with messages matching a regular expression -rule.pmd.SingletonClassReturningNewInstance.param.violationSuppressXPath=Suppress violations on nodes which match a given relative XPath expression -rule.pmd.SingleMethodSingleton.name=Only one getInstance method is allowed -rule.pmd.SingleMethodSingleton.param.violationSuppressRegex=Suppress violations with messages matching a regular expression -rule.pmd.SingleMethodSingleton.param.violationSuppressXPath=Suppress violations on nodes which match a given relative XPath expression -rule.pmd.UselessQualifiedThis.name=Flags unnecessary qualified usages of this -rule.pmd-unit-tests.JUnitStaticSuite.name=JUnit static suite -rule.pmd-unit-tests.JUnitSpelling.name=JUnit spelling -rule.pmd-unit-tests.JUnitAssertionsShouldIncludeMessage.name=JUnit assertions should include a message -rule.pmd-unit-tests.JUnitTestsShouldIncludeAssert.name=JUnit tests should include an assert -rule.pmd-unit-tests.TestClassWithoutTestCases.name=Test class without test cases (JUnit 3.x only) -rule.pmd-unit-tests.UnnecessaryBooleanAssertion.name=Unnecessary boolean assertion -rule.pmd-unit-tests.UseAssertEqualsInsteadOfAssertTrue.name=Use assertEquals instead of assertTrue -rule.pmd-unit-tests.UseAssertSameInsteadOfAssertTrue.name=Use assertSame instead of assertTrue -rule.pmd-unit-tests.UseAssertNullInsteadOfAssertTrue.name=Use assertNull instead of assertTrue -rule.pmd-unit-tests.SimplifyBooleanAssertion.name=Simplify boolean assertion -rule.pmd-unit-tests.UseAssertTrueInsteadOfAssertEquals.name=Use Assert True Instead Of Assert Equals -rule.pmd-unit-tests.JUnitTestContainsTooManyAsserts.name=JUnit Test Contains Too Many Asserts -rule.pmd-unit-tests.JUnitTestContainsTooManyAsserts.param.maximumAsserts=Maximum number of Asserts in a test method -rule.pmd-unit-tests.JUnit4SuitesShouldUseSuiteAnnotation.name=JUnit4 Suites Should Use Suite Annotation -rule.pmd-unit-tests.JUnit4TestShouldUseAfterAnnotation.name=JUnit4 Test Should Use After Annotation -rule.pmd-unit-tests.JUnit4TestShouldUseBeforeAnnotation.name=JUnit4 Test Should Use Before Annotation -rule.pmd-unit-tests.JUnit4TestShouldUseTestAnnotation.name=JUnit4 Test Should Use Test Annotation -rule.pmd-unit-tests.JUnitUseExpected.name=JUnit Use Expected diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4SuitesShouldUseSuiteAnnotation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4SuitesShouldUseSuiteAnnotation.html deleted file mode 100644 index 33de8db6..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4SuitesShouldUseSuiteAnnotation.html +++ /dev/null @@ -1,15 +0,0 @@ -In JUnit 3, test suites are indicated by the suite() method. In JUnit 4, suites are indicated -through the @RunWith(Suite.class) annotation. Example: -

        -public class BadExample extends TestCase{
        -
        -    public static Test suite(){
        -    	return new Suite();
        -    }
        -}
        -
        -@RunWith(Suite.class)
        -@SuiteClasses( { TestOne.class, TestTwo.class })
        -public class GoodTest {
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4TestShouldUseAfterAnnotation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4TestShouldUseAfterAnnotation.html deleted file mode 100644 index b37d6332..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4TestShouldUseAfterAnnotation.html +++ /dev/null @@ -1,14 +0,0 @@ -In JUnit 3, the tearDown method was used to clean up all data entities required in running tests. -JUnit 4 skips the tearDown method and executes all methods annotated with @After after running each test Example: -
        -public class MyTest {
        -    public void tearDown() {
        -        bad();
        -    }
        -}
        -public class MyTest2 {
        -    @After public void tearDown() {
        -        good();
        -    }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4TestShouldUseBeforeAnnotation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4TestShouldUseBeforeAnnotation.html deleted file mode 100644 index 3fcd1d8a..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4TestShouldUseBeforeAnnotation.html +++ /dev/null @@ -1,14 +0,0 @@ -In JUnit 3, the setUp method was used to set up all data entities required in running tests. -JUnit 4 skips the setUp method and executes all methods annotated with @Before before all tests Example: -
        -public class MyTest {
        -    public void setUp() {
        -        bad();
        -    }
        -}
        -public class MyTest2 {
        -    @Before public void setUp() {
        -        good();
        -    }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4TestShouldUseTestAnnotation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4TestShouldUseTestAnnotation.html deleted file mode 100644 index bde1cf6c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnit4TestShouldUseTestAnnotation.html +++ /dev/null @@ -1,14 +0,0 @@ -In JUnit 3, the framework executed all methods which started with the word test as a unit test. -In JUnit 4, only methods annotated with the @Test annotation are executed. Example: -
        -public class MyTest {
        -    public void testBad() {
        -        doSomething();
        -    }
        -
        -	@Test
        -    public void testGood() {
        -        doSomething();
        -    }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitAssertionsShouldIncludeMessage.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitAssertionsShouldIncludeMessage.html deleted file mode 100644 index fd09b3be..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitAssertionsShouldIncludeMessage.html +++ /dev/null @@ -1,12 +0,0 @@ -JUnit assertions should include a message - i.e., use the three argument version of assertEquals(), not the two argument version. -
        -public class Foo extends TestCase {
        -  public void testSomething() {
        -    assertEquals("foo", "bar"); // violation, should be assertEquals("Foo does not equals bar", "foo", "bar");
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S2698} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitSpelling.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitSpelling.html deleted file mode 100644 index efd28cda..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitSpelling.html +++ /dev/null @@ -1,9 +0,0 @@ -Some JUnit framework methods are easy to misspell. -
        -import junit.framework.*;
        -
        -public class Foo extends TestCase {
        -  public void setup() {} // violation, should be setUp()
        -  public void TearDown() {} // violation, should be tearDown()
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitStaticSuite.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitStaticSuite.html deleted file mode 100644 index 6c7e51e1..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitStaticSuite.html +++ /dev/null @@ -1,9 +0,0 @@ -The suite() method in a JUnit test needs to be both public and static. -
        -import junit.framework.*;
        -
        -public class Foo extends TestCase {
        -  public void suite() {} // violation, should be static
        -  private static void suite() {} // violation, should be public
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitTestContainsTooManyAsserts.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitTestContainsTooManyAsserts.html deleted file mode 100644 index 4e37ff90..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitTestContainsTooManyAsserts.html +++ /dev/null @@ -1,19 +0,0 @@ -JUnit tests should not contain too many asserts. Many asserts are indicative of a complex test, for which -it is harder to verify correctness. Consider breaking the test scenario into multiple, shorter test scenarios. -Customize the maximum number of assertions used by this Rule to suit your needs. Example: -
        -public class MyTestCase extends TestCase {
        -	// Ok
        -	public void testMyCaseWithOneAssert() {
        -		boolean myVar = false;		
        -		assertFalse("should be false", myVar);
        -	}
        -
        -	// Bad, too many asserts (assuming max=1)
        -	public void testMyCaseWithMoreAsserts() {
        -		boolean myVar = false;		
        -		assertFalse("myVar should be false", myVar);
        -		assertEquals("should equals false", false, myVar);
        -	}
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitTestsShouldIncludeAssert.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitTestsShouldIncludeAssert.html deleted file mode 100644 index 7015ac14..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitTestsShouldIncludeAssert.html +++ /dev/null @@ -1,10 +0,0 @@ -JUnit tests should include at least one assertion. This makes the tests more robust, and using assert with messages provide the developer a clearer idea of what the test does. -
        -public class Foo extends TestCase {
        -  public void testSomething() {
        -    Bar b = findBar();
        -    b.work();
        -    // violation, we could use assertNotNull("bar not found", b);
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitUseExpected.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitUseExpected.html deleted file mode 100644 index b40c93b7..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/JUnitUseExpected.html +++ /dev/null @@ -1,18 +0,0 @@ -In JUnit4, use the @Test(expected) annotation to denote tests that should throw exceptions. Example: -
        -public class MyTest {
        -	@Test
        -    public void testBad() {
        -        try {
        -            doSomething();
        -            fail("should have thrown an exception");
        -        } catch (Exception e) {
        -        }
        -    }
        -
        -	@Test(expected=Exception.class)
        -    public void testGood() {
        -        doSomething();
        -    }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/SimplifyBooleanAssertion.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/SimplifyBooleanAssertion.html deleted file mode 100644 index 9c511fbb..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/SimplifyBooleanAssertion.html +++ /dev/null @@ -1,9 +0,0 @@ -Avoid negation in an assertTrue or assertFalse test. For example, rephrase: assertTrue(!expr); as: assertFalse(expr); -
        -public class SimpleTest extends TestCase {
        -  public void testX() {
        -    assertTrue("not empty", !r.isEmpty()); // violation, replace with assertFalse("not empty", r.isEmpty())
        -    assertFalse(!r.isEmpty()); // violation, replace with assertTrue("empty", r.isEmpty())
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/TestClassWithoutTestCases.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/TestClassWithoutTestCases.html deleted file mode 100644 index a7ca580b..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/TestClassWithoutTestCases.html +++ /dev/null @@ -1,10 +0,0 @@ -Test classes end with the suffix Test. Having a non-test class with that name is not a good practice, since most people will assume it is a test case. Test classes have test methods named testXXX. -Beware: This rule doesn't support JUnit 4.x's @Test annotation. -
        -public class CarTest { // violation, consider changing the name of the class if it is not a test
        -  // consider adding test methods if it is a test
        -  public static void main(String[] args) {
        -    // do something
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UnnecessaryBooleanAssertion.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UnnecessaryBooleanAssertion.html deleted file mode 100644 index 7ccb2f13..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UnnecessaryBooleanAssertion.html +++ /dev/null @@ -1,7 +0,0 @@ -A JUnit test assertion with a boolean literal is unnecessary since it always will eval to the same thing. Consider using flow control (in case of assertTrue(false) or similar) or simply removing statements like assertTrue(true) and assertFalse(false). If you just want a test to halt, use the fail method. -
        -public class SimpleTest extends TestCase {
        -  public void testX() {
        -    assertTrue(true); // violation
        -  }
        -}
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertEqualsInsteadOfAssertTrue.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertEqualsInsteadOfAssertTrue.html deleted file mode 100644 index b217662e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertEqualsInsteadOfAssertTrue.html +++ /dev/null @@ -1,10 +0,0 @@ -This rule detects JUnit assertions in object equality. These assertions should be made by more specific methods, like assertEquals. -
        -public class FooTest extends TestCase {
        -  void testCode() {
        -    Object a, b;
        -
        -    assertTrue(a.equals(b)); // violation
        -    assertEquals("a should equals b", a, b); // good usage
        -  }
        -}
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertNullInsteadOfAssertTrue.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertNullInsteadOfAssertTrue.html deleted file mode 100644 index e335fcba..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertNullInsteadOfAssertTrue.html +++ /dev/null @@ -1,13 +0,0 @@ -This rule detects JUnit assertions in object references equality. These assertions should be made by more specific methods, like assertNull, assertNotNull. -
        -public class FooTest extends TestCase {
        -  void testCode() {
        -    Object a = doSomething();
        -
        -    assertTrue(a==null); // violation
        -    assertNull(a);  // good usage
        -    assertTrue(a != null); // violation
        -    assertNotNull(a);  // good usage
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertSameInsteadOfAssertTrue.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertSameInsteadOfAssertTrue.html deleted file mode 100644 index 6d5273dd..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertSameInsteadOfAssertTrue.html +++ /dev/null @@ -1,11 +0,0 @@ -This rule detects JUnit assertions in object references equality. These assertions should be made by more specific methods, like assertSame, assertNotSame. -
        -public class FooTest extends TestCase {
        -  void testCode() {
        -    Object a, b;
        -
        -    assertTrue(a==b); // violation
        -    assertSame(a, b); // good usage
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertTrueInsteadOfAssertEquals.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertTrueInsteadOfAssertEquals.html deleted file mode 100644 index 1f9c0572..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd-unit-tests/UseAssertTrueInsteadOfAssertEquals.html +++ /dev/null @@ -1,14 +0,0 @@ -When asserting a value is the same as a boolean literal, use assertTrue/assertFalse, instead of assertEquals. Example: -
        -public class MyTestCase extends TestCase {
        -	public void testMyCase() {
        -		boolean myVar = true;
        -		// Ok
        -		assertTrue("myVar is true", myVar);
        -		// Bad
        -		assertEquals("myVar is true", true, myVar);
        -		// Bad
        -		assertEquals("myVar is false", false, myVar);
        -	}
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AbstractClassWithoutAbstractMethod.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AbstractClassWithoutAbstractMethod.html deleted file mode 100644 index 48b52782..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AbstractClassWithoutAbstractMethod.html +++ /dev/null @@ -1,6 +0,0 @@ - -The abstract class does not contain any abstract methods. An abstract class suggests an incomplete implementation, which is to be completed by subclasses implementing the abstract methods. If the class is intended to be used as a base class only (not to be instantiated directly) a protected constructor can be provided prevent direct instantiation. - -

        - This rule is deprecated, use {rule:squid:S1694} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AbstractClassWithoutAnyMethod.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AbstractClassWithoutAnyMethod.html deleted file mode 100644 index cac0f594..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AbstractClassWithoutAnyMethod.html +++ /dev/null @@ -1,13 +0,0 @@ - -If an abstract class does not provide any method, it may be acting as a simple data container that is not meant to be instantiated. In this case, it is probably better to use a private or protected constructor in order to prevent instantiation than make the class misleadingly abstract. -

        Example:

        -
        -public class abstract Example {
        -  String field;
        -  int otherField;
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1694} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AbstractNaming.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AbstractNaming.html deleted file mode 100644 index 94a3ebf4..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AbstractNaming.html +++ /dev/null @@ -1,11 +0,0 @@ - -Abstract classes should be named 'AbstractXXX'. -

        Example:

        h2> -
        -public abstract class Foo { // should be AbstractFoo
        -}
        -  
        - -

        - This rule is deprecated, use {rule:squid:S00118} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AccessorClassGeneration.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AccessorClassGeneration.html deleted file mode 100644 index ac3f72bf..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AccessorClassGeneration.html +++ /dev/null @@ -1,18 +0,0 @@ - -Instantiation by way of private constructors from outside of the constructor’s class often causes the generation of an accessor. -A factory method, or non-privatization of the constructor can eliminate this situation. -The generated class file is actually an interface. It gives the accessing class the ability to invoke a new hidden package scope constructor that takes the interface as a supplementary parameter. -This turns a private constructor effectively into one with package scope, and is challenging to discern. - -

        Example:

        -
        -public class Outer {
        -  void method() {
        -    Inner ic = new Inner(); // Causes generation of accessor class
        -  }
        -
        -  public class Inner {
        -    private Inner() {}
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AddEmptyString.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AddEmptyString.html deleted file mode 100644 index a29a7ba7..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AddEmptyString.html +++ /dev/null @@ -1,9 +0,0 @@ - -The conversion of literals to strings by concatenating them with empty strings is inefficient. -It is much better to use one of the type-specific toString() methods instead. - -

        Example:

        -
        -String s = "" + 123;                // inefficient
        -String t = Integer.toString(456);   // preferred approach
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AppendCharacterWithChar.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AppendCharacterWithChar.html deleted file mode 100644 index f244f100..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AppendCharacterWithChar.html +++ /dev/null @@ -1,13 +0,0 @@ - -Avoid concatenating characters as strings in StringBuffer/StringBuilder.append methods. - -

        Noncompliant Code Example

        -
        -StringBuffer sb = new StringBuffer();
        -sb.append("a");     // avoid this
        -
        -

        Compliant Solution

        -
        -StringBuffer sb = new StringBuffer();
        -sb.append('a');     // use this instead
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ArrayIsStoredDirectly.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ArrayIsStoredDirectly.html deleted file mode 100644 index 72deffd7..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ArrayIsStoredDirectly.html +++ /dev/null @@ -1,6 +0,0 @@ - -Constructors and methods receiving arrays should clone objects and store the copy. This prevents future changes from the user from affecting the original array. - -

        - This rule is deprecated, use {rule:squid:S2384} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AssignmentInOperand.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AssignmentInOperand.html deleted file mode 100644 index 5f9e777b..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AssignmentInOperand.html +++ /dev/null @@ -1,16 +0,0 @@ - -Avoid assignments in operands; this can make code more complicated and harder to read. - -

        Example:

        -
        -public void bar() {
        -  int x = 2;
        -  if ((x = getX()) == 3) {
        -    System.out.println("3!");
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:AssignmentInSubExpressionCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AssignmentToNonFinalStatic.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AssignmentToNonFinalStatic.html deleted file mode 100644 index 2106638f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AssignmentToNonFinalStatic.html +++ /dev/null @@ -1,12 +0,0 @@ - -Identifies a possible unsafe usage of a static field. - -

        Example:

        -
        -public class StaticField {
        - static int x;
        - public FinalFields(int y) {
        -  x = y; // unsafe
        - }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AtLeastOneConstructor.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AtLeastOneConstructor.html deleted file mode 100644 index e9704d77..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AtLeastOneConstructor.html +++ /dev/null @@ -1,5 +0,0 @@ -Each non-static class should declare at least one constructor. Classes with solely static members ("Utility class") are ignored. - -

        - This rule is deprecated, use {rule:squid:S1118} or {rule:squid:S1258} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidAccessibilityAlteration.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidAccessibilityAlteration.html deleted file mode 100644 index d13ef767..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidAccessibilityAlteration.html +++ /dev/null @@ -1,35 +0,0 @@ - -Methods such as getDeclaredConstructors(), getDeclaredConstructor(Class[]) and setAccessible(), as the interface PrivilegedAction, allow for the runtime alteration of variable, class, or method visibility, even if they are private. This violates the principle of encapsulation. - -

        Example:

        -
        -import java.lang.reflect.AccessibleObject;
        -import java.lang.reflect.Method;
        -import java.security.PrivilegedAction;
        -
        -public class Violation {
        -  public void invalidCallsInMethod() throws SecurityException, NoSuchMethodException {
        -
        -    // Possible call to forbidden getDeclaredConstructors
        -    Class[] arrayOfClass = new Class[1];
        -    this.getClass().getDeclaredConstructors();
        -    this.getClass().getDeclaredConstructor(arrayOfClass);
        -    Class clazz = this.getClass();
        -    clazz.getDeclaredConstructor(arrayOfClass);
        -    clazz.getDeclaredConstructors();
        -
        -    // Possible call to forbidden setAccessible
        -    clazz.getMethod("", arrayOfClass).setAccessible(false);
        -    AccessibleObject.setAccessible(null, false);
        -    Method.setAccessible(null, false);
        -    Method[] methodsArray = clazz.getMethods();
        -    int nbMethod;
        -    for (nbMethod = 0; nbMethod < methodsArray.length; nbMethod++ ) {
        -      methodsArray[nbMethod].setAccessible(false);
        -    }
        -
        -    // Possible call to forbidden PrivilegedAction
        -    PrivilegedAction priv = (PrivilegedAction) new Object(); priv.run();
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidArrayLoops.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidArrayLoops.html deleted file mode 100644 index c2db10b3..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidArrayLoops.html +++ /dev/null @@ -1,24 +0,0 @@ - -Instead of manually copying data between two arrays, use the efficient Arrays.copyOf or System.arraycopy method instead. - -

        Noncompliant Code Example

        -
        -int[] a = new int[10];
        -int[] b = new int[10];
        -
        -for (int i = 0; i < 10; i++) {
        -  b[i] = a[i];
        -}
        -
        - -

        Compliant Solution

        -
        -int[] a = new int[10];
        -int[] b;
        -
        -// Option 1
        -b = Arrays.copyOf(a, a.length);
        -
        -// Option 2
        -System.arraycopy(a, 0, b, 0, a.length);
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidAssertAsIdentifier.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidAssertAsIdentifier.html deleted file mode 100644 index dfeff04f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidAssertAsIdentifier.html +++ /dev/null @@ -1,6 +0,0 @@ - -Use of the term assert will conflict with newer versions of Java since it is a reserved word. - -

        - This rule is deprecated, use {rule:squid:S1190} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidBranchingStatementAsLastInLoop.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidBranchingStatementAsLastInLoop.html deleted file mode 100644 index cc2c010f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidBranchingStatementAsLastInLoop.html +++ /dev/null @@ -1,23 +0,0 @@ - -Using a branching statement as the last part of a loop may be a bug, and/or is confusing. Ensure that the usage is not a bug, or consider using another approach. - -

        Noncompliant Code Example

        -
        -// unusual use of branching statement in a loop
        -for (int i = 0; i < 10; i++) {
        -  if (i*i <= 25) {
        -    continue;
        -  }
        -  break;
        -}
        -
        - -

        Compliant Solution

        -
        -// this makes more sense...
        -for (int i = 0; i < 10; i++) {
        -  if (i*i > 25) {
        -    break;
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCallingFinalize.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCallingFinalize.html deleted file mode 100644 index 596e4236..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCallingFinalize.html +++ /dev/null @@ -1,12 +0,0 @@ - -

        - The method Object.finalize() is called by the garbage collector on an object when garbage collection determines that there are no more references to the object. - It should not be invoked by application logic. -

        -

        - Note that Oracle has declared Object.finalize() as deprecated since JDK 9. -

        - -

        - This rule is deprecated, use {rule:squid:ObjectFinalizeCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCatchingGenericException.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCatchingGenericException.html deleted file mode 100644 index a2cfd566..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCatchingGenericException.html +++ /dev/null @@ -1,6 +0,0 @@ - -Avoid catching generic exceptions such as NullPointerException, RuntimeException, Exception in try-catch block. - -

        - This rule is deprecated, use {rule:squid:S2221} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCatchingNPE.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCatchingNPE.html deleted file mode 100644 index 49e5f53b..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCatchingNPE.html +++ /dev/null @@ -1,7 +0,0 @@ - -Code should never throw NullPointerExceptions under normal circumstances. -A catch block may hide the original error, causing other, more subtle problems later on. - -

        - This rule is deprecated, use {rule:squid:S1696} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCatchingThrowable.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCatchingThrowable.html deleted file mode 100644 index f8d5253e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidCatchingThrowable.html +++ /dev/null @@ -1,7 +0,0 @@ - -Catching Throwable errors is not recommended since its scope is very broad. It includes runtime issues such as -OutOfMemoryError that should be exposed and managed separately. - -

        - This rule is deprecated, use {rule:squid:S1181} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidConstantsInterface.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidConstantsInterface.html deleted file mode 100644 index 4712e4da..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidConstantsInterface.html +++ /dev/null @@ -1,11 +0,0 @@ - -

        - Avoid constants in interfaces. Interfaces should define types, constants are implementation details better placed in - classes or enums. -

        -

        - See Effective Java, item 19. -

        -

        - This rule is deprecated, use {rule:squid:S1214} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDecimalLiteralsInBigDecimalConstructor.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDecimalLiteralsInBigDecimalConstructor.html deleted file mode 100644 index b3d8604c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDecimalLiteralsInBigDecimalConstructor.html +++ /dev/null @@ -1,26 +0,0 @@ - -

        - One might assume that the result of new BigDecimal(0.1) is exactly equal to 0.1, but it is - actually equal to .1000000000000000055511151231257827021181583404541015625. This is because 0.1 - cannot be represented exactly as a double (or as a binary fraction of any finite length). - Thus, the long value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding. -

        -

        - The (String) constructor, on the other hand, is perfectly predictable: new BigDecimal("0.1") is exactly equal - to 0.1, as one would expect. Therefore, it is generally recommended that the (String) constructor be used in preference to this one. -

        -

        Noncompliant Code Example

        -
        -BigDecimal bd = new BigDecimal(1.123);       // loss of precision, this would trigger the rule
        -
        - -

        Compliant Solution

        -
        -BigDecimal bd = new BigDecimal("1.123");     // preferred approach
        -
        -BigDecimal bd = new BigDecimal(12);          // preferred approach, ok for integer values
        -
        - -

        - This rule is deprecated, use {rule:squid:S2111} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDeeplyNestedIfStmts.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDeeplyNestedIfStmts.html deleted file mode 100644 index 8f267279..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDeeplyNestedIfStmts.html +++ /dev/null @@ -1,6 +0,0 @@ - -Avoid creating deeply nested if-then statements since they are harder to read and error-prone to maintain. - -

        - This rule is deprecated, use {rule:squid:S134} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDollarSigns.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDollarSigns.html deleted file mode 100644 index 9a19e9b8..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDollarSigns.html +++ /dev/null @@ -1,8 +0,0 @@ -

        - Avoid using dollar signs in variable/method/class/interface names. -

        - -

        - This rule is deprecated, use {rule:squid:S00114}, {rule:squid:S00115}, {rule:squid:S00116} and {rule:squid:S00117} - instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDuplicateLiterals.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDuplicateLiterals.html deleted file mode 100644 index ab422fe1..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidDuplicateLiterals.html +++ /dev/null @@ -1,16 +0,0 @@ -Code containing duplicate String literals can usually be improved by declaring the String as a constant field. Example : -
        -public class Foo {
        - private void bar() {
        -    buz("Howdy");
        -    buz("Howdy");
        -    buz("Howdy");
        -    buz("Howdy");
        - }
        - private void buz(String x) {}
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1192} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidEnumAsIdentifier.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidEnumAsIdentifier.html deleted file mode 100644 index 8f2b5ac1..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidEnumAsIdentifier.html +++ /dev/null @@ -1,5 +0,0 @@ -Finds all places 'enum' is used as an identifier is used. - -

        - This rule is deprecated, use {rule:squid:S1190} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidFieldNameMatchingMethodName.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidFieldNameMatchingMethodName.html deleted file mode 100644 index 14d6a327..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidFieldNameMatchingMethodName.html +++ /dev/null @@ -1,13 +0,0 @@ -It is somewhat confusing to have a field name with the same name as a method. While this is totally legal, having information (field) and actions (method) is not clear naming. Example : -
        -public class Foo {
        -  Object bar;
        -  // bar is data or an action or both?
        -  void bar() {
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1845} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidFieldNameMatchingTypeName.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidFieldNameMatchingTypeName.html deleted file mode 100644 index b12142cc..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidFieldNameMatchingTypeName.html +++ /dev/null @@ -1,11 +0,0 @@ -It is somewhat confusing to have a field name matching the declaring class name. This probably means that type and or field names could be more precise. Example : -
        -public class Foo extends Bar {
        -  // There's probably a better name for foo
        -  int foo;
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1700} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidFinalLocalVariable.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidFinalLocalVariable.html deleted file mode 100644 index 43a0acc5..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidFinalLocalVariable.html +++ /dev/null @@ -1,8 +0,0 @@ -Avoid using final local variables, turn them into fields. Example : -
        -public class MyClass {
        -    public void foo() {
        -        final String finalLocalVariable;
        -    }
        -}
        -  
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidInstanceofChecksInCatchClause.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidInstanceofChecksInCatchClause.html deleted file mode 100644 index 0b96dd5d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidInstanceofChecksInCatchClause.html +++ /dev/null @@ -1,5 +0,0 @@ -Each caught exception type should be handled in its own catch clause. - -

        - This rule is deprecated, use {rule:squid:S1193} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidInstantiatingObjectsInLoops.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidInstantiatingObjectsInLoops.html deleted file mode 100644 index f0aa0d8d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidInstantiatingObjectsInLoops.html +++ /dev/null @@ -1 +0,0 @@ -Detects when a new object is created inside a loop diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidLiteralsInIfCondition.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidLiteralsInIfCondition.html deleted file mode 100644 index d7c82ea6..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidLiteralsInIfCondition.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid using hard coded literals in conditional statements, declare those as static variables or private members. - -

        - This rule is deprecated, use {rule:squid:S109} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidLosingExceptionInformation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidLosingExceptionInformation.html deleted file mode 100644 index 25bddf05..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidLosingExceptionInformation.html +++ /dev/null @@ -1,5 +0,0 @@ -Statements in a catch block that invoke accessors on the exception without using the information only add to code size. Either remove the invocation, or use the return result. - -

        - This rule is deprecated, use {rule:squid:S1166} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidMultipleUnaryOperators.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidMultipleUnaryOperators.html deleted file mode 100644 index d434ed75..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidMultipleUnaryOperators.html +++ /dev/null @@ -1,24 +0,0 @@ -Using multiple unary operators may be a bug, and/or is confusing. Check the usage is not a bug, or consider simplifying the expression. Example : -
        -// These are typo bugs, or at best needlessly complex and confusing:
        -int i = - -1;
        -int j = + - +1;
        -int z = ~~2;
        -boolean b = !!true;
        -boolean c = !!!true;
        -
        -// These are better:
        -int i = 1;
        -int j = -1;
        -int z = 2;
        -boolean b = true;
        -boolean c = false;
        -
        -// And these just make your brain hurt:
        -int i = ~-2;
        -int j = -~7;
        -
        - -

        - This rule is deprecated, use {rule:squid:S881} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidPrefixingMethodParameters.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidPrefixingMethodParameters.html deleted file mode 100644 index 32c18b92..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidPrefixingMethodParameters.html +++ /dev/null @@ -1,17 +0,0 @@ -Prefixing parameters by 'in' or 'out' pollutes the name of the parameters and reduces code readability. -To indicate whether or not a parameter will be modify in a method, its better to document method -behavior with Javadoc. Example: -
        -// Not really clear
        -public class Foo {
        -  public void bar(
        -      int inLeftOperand,
        -      Result outRightOperand) {
        -      outRightOperand.setValue(inLeftOperand * outRightOperand.getValue());
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S00117} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidPrintStackTrace.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidPrintStackTrace.html deleted file mode 100644 index 74858c3e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidPrintStackTrace.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid printStackTrace(); use a logger call instead. - -

        - This rule is deprecated, use {rule:squid:S1148} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidProtectedFieldInFinalClass.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidProtectedFieldInFinalClass.html deleted file mode 100644 index 6e474e7a..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidProtectedFieldInFinalClass.html +++ /dev/null @@ -1,5 +0,0 @@ -Do not use protected fields in final classes since they cannot be subclassed. Clarify your intent by using private or package access modifiers instead. - -

        - This rule is deprecated, use {rule:squid:S2156} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidProtectedMethodInFinalClassNotExtending.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidProtectedMethodInFinalClassNotExtending.html deleted file mode 100644 index c20fed12..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidProtectedMethodInFinalClassNotExtending.html +++ /dev/null @@ -1,13 +0,0 @@ -Do not use protected methods in most final classes since they cannot be subclassed. This should -only be allowed in final classes that extend other classes with protected methods (whose -visibility cannot be reduced). Clarify your intent by using private or package access modifiers instead. Example: -
        -public final class Foo {
        -  private int bar() {}
        -  protected int baz() {} // Foo cannot be subclassed, and doesn't extend anything, so is baz() really private or package visible? 
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S2156} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidReassigningParameters.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidReassigningParameters.html deleted file mode 100644 index d7bc4bb3..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidReassigningParameters.html +++ /dev/null @@ -1,5 +0,0 @@ -Reassigning values to parameters is a questionable practice. Use a temporary local variable instead. - -

        - This rule is deprecated, use {rule:squid:S1226} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidRethrowingException.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidRethrowingException.html deleted file mode 100644 index f49a4899..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidRethrowingException.html +++ /dev/null @@ -1,5 +0,0 @@ -Catch blocks that merely rethrow a caught exception only add to code size and runtime complexity. - -

        - This rule is deprecated, use {rule:squid:S1166} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidStringBufferField.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidStringBufferField.html deleted file mode 100644 index ef505db4..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidStringBufferField.html +++ /dev/null @@ -1,10 +0,0 @@ -StringBuffers can grow quite a lot, and so may become a source of memory leak (if the owning class has a long life time). Example : -
        -class Foo {
        -  private StringBuffer memoryLeak;
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1149} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidSynchronizedAtMethodLevel.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidSynchronizedAtMethodLevel.html deleted file mode 100644 index 94406263..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidSynchronizedAtMethodLevel.html +++ /dev/null @@ -1 +0,0 @@ -Method level synchronization can backfire when new code is added to the method. Block-level synchronization helps to ensure that only the code that needs synchronization gets it. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThreadGroup.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThreadGroup.html deleted file mode 100644 index 99370ca1..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThreadGroup.html +++ /dev/null @@ -1 +0,0 @@ -Avoid using ThreadGroup; although it is intended to be used in a threaded environment it contains methods that are not thread safe. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThrowingNewInstanceOfSameException.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThrowingNewInstanceOfSameException.html deleted file mode 100644 index fe1b5557..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThrowingNewInstanceOfSameException.html +++ /dev/null @@ -1,17 +0,0 @@ -Catch blocks that merely rethrow a caught exception wrapped inside a new instance of the same type only add to code size and runtime complexity. Example : -
        -public class Foo {
        -  void bar() {
        -    try {
        -      // do something
        -    }  catch (SomeException se) {
        -      // harmless comment
        -      throw new SomeException(se);
        -    }
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1166} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThrowingNullPointerException.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThrowingNullPointerException.html deleted file mode 100644 index b2dd7a01..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThrowingNullPointerException.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid throwing a NullPointerException - it's confusing because most people will assume that the virtual machine threw it. Consider using an IllegalArgumentException instead; this will be clearly seen as a programmer-initiated exception. - -

        - This rule is deprecated, use {rule:squid:S1695} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThrowingRawExceptionTypes.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThrowingRawExceptionTypes.html deleted file mode 100644 index b3b044d1..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidThrowingRawExceptionTypes.html +++ /dev/null @@ -1,8 +0,0 @@ -

        - Avoid throwing certain exception types. Rather than throw a raw RuntimeException, Throwable, Exception, or Error, use - a subclassed exception or error instead. -

        - -

        - This rule is deprecated, use {rule:squid:S00112} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingHardCodedIP.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingHardCodedIP.html deleted file mode 100644 index 84485476..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingHardCodedIP.html +++ /dev/null @@ -1,5 +0,0 @@ -An application with hard-coded IP addresses can become impossible to deploy in some cases. Externalizing IP addresses is preferable. - -

        - This rule is deprecated, use {rule:squid:S1313} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingNativeCode.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingNativeCode.html deleted file mode 100644 index dd948a44..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingNativeCode.html +++ /dev/null @@ -1 +0,0 @@ -As JVM and Java language offer already many help in creating application, it should be very rare to have to rely on non-java code. Even though, it is rare to actually have to use Java Native Interface (JNI). As the use of JNI make application less portable, and harder to maintain, it is not recommended. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingOctalValues.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingOctalValues.html deleted file mode 100644 index 031a446f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingOctalValues.html +++ /dev/null @@ -1,5 +0,0 @@ -Integer literals should not start with zero. Zero means that the rest of literal will be interpreted as an octal value. - -

        - This rule is deprecated, use {rule:squid:S1314} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingShortType.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingShortType.html deleted file mode 100644 index 791d78d5..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingShortType.html +++ /dev/null @@ -1 +0,0 @@ -Java uses the short type to reduce memory usage, not to optimize calculation. On the contrary, the JVM does not have arithmetic capabilities with the type short. So, the P-code must convert the short into int, then do the proper calculation and then again, convert int to short. So, use of the short type may have a great effect on memory usage. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingVolatile.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingVolatile.html deleted file mode 100644 index 54631a18..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/AvoidUsingVolatile.html +++ /dev/null @@ -1 +0,0 @@ -Use of the keyword "volatile" is general used to fine tune a Java application, and therefore, requires a good expertise of the Java Memory Model. Morover, its range of action is somewhat misknown. Therefore, the volatile keyword should not be used for maintenance purpose and portability. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BadComparison.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BadComparison.html deleted file mode 100644 index df55129c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BadComparison.html +++ /dev/null @@ -1 +0,0 @@ -Avoid equality comparisons with Double.NaN - these are likely to be logic errors. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BeanMembersShouldSerialize.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BeanMembersShouldSerialize.html deleted file mode 100644 index f68d411e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BeanMembersShouldSerialize.html +++ /dev/null @@ -1 +0,0 @@ -If a class is a bean, or is referenced by a bean directly or indirectly it needs to be serializable. Member variables need to be marked as transient, static, or have accessor methods in the class. Marking variables as transient is the safest and easiest modification. Accessor methods should follow the Java naming conventions, i.e.if you have a variable foo, you should provide getFoo and setFoo methods. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BigIntegerInstantiation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BigIntegerInstantiation.html deleted file mode 100644 index 16d271b7..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BigIntegerInstantiation.html +++ /dev/null @@ -1 +0,0 @@ -Don't create instances of already existing BigInteger (BigInteger.ZERO, BigInteger.ONE) and for 1.5 on, BigInteger.TEN and BigDecimal (BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN) diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BooleanGetMethodName.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BooleanGetMethodName.html deleted file mode 100644 index bd2167a7..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BooleanGetMethodName.html +++ /dev/null @@ -1 +0,0 @@ -Looks for methods named "getX()" with "boolean" as the return type. The convention is to name these methods "isX()". diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BooleanInstantiation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BooleanInstantiation.html deleted file mode 100644 index 5dd8e884..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BooleanInstantiation.html +++ /dev/null @@ -1 +0,0 @@ -Avoid instantiating Boolean objects; you can reference Boolean.TRUE, Boolean.FALSE, or call Boolean.valueOf() instead. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BrokenNullCheck.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BrokenNullCheck.html deleted file mode 100644 index 9da7ede2..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/BrokenNullCheck.html +++ /dev/null @@ -1,5 +0,0 @@ -The null check is broken since it will throw a Nullpointer itself. The reason is that a method is called on the object when it is null. It is likely that you used || instead of && or vice versa. - -

        - This rule is deprecated, use {rule:squid:S1697} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ByteInstantiation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ByteInstantiation.html deleted file mode 100644 index 7ada656f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ByteInstantiation.html +++ /dev/null @@ -1,7 +0,0 @@ -In JDK 1.5, calling new Byte() causes memory allocation. Byte.valueOf() is more memory friendly. Example : -
        -public class Foo {
        -private Byte i = new Byte(0); // change to Byte i =
        -Byte.valueOf(0);
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CallSuperFirst.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CallSuperFirst.html deleted file mode 100644 index 2cd89645..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CallSuperFirst.html +++ /dev/null @@ -1,9 +0,0 @@ -Super should be called at the start of the method. Example : -
        -public class DummyActivity extends Activity {
        -  public void onCreate(Bundle bundle) {
        -    // missing call to super.onCreate(bundle)
        -    foo();
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CallSuperInConstructor.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CallSuperInConstructor.html deleted file mode 100644 index d76fc758..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CallSuperInConstructor.html +++ /dev/null @@ -1 +0,0 @@ -It is a good practice to call super() in a constructor. If super() is not called but another constructor (such as an overloaded constructor) is called, this rule will not report it. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CallSuperLast.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CallSuperLast.html deleted file mode 100644 index 169337ef..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CallSuperLast.html +++ /dev/null @@ -1,9 +0,0 @@ -Super should be called at the end of the method. Example : -
        -public class DummyActivity extends Activity {
        -  public void onPause() {
        -    foo();
        -    // missing call to super.onPause()
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CheckResultSet.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CheckResultSet.html deleted file mode 100644 index 94631f01..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CheckResultSet.html +++ /dev/null @@ -1 +0,0 @@ -Always check the return of one of the navigation method (next,previous,first,last) of a ResultSet. Indeed, if the value return is "false", the developer should deal with it ! diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CheckSkipResult.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CheckSkipResult.html deleted file mode 100644 index 10016b9d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CheckSkipResult.html +++ /dev/null @@ -1,23 +0,0 @@ -The skip() method may skip a smaller number of bytes than requested. Check the returned value to find out if it was the case or not. Example: -
        -public class Foo {
        -
        -   private FileInputStream _s = new FileInputStream("file");
        -
        -   public void skip(int n) throws IOException {
        -      _s.skip(n); // You are not sure that exactly n bytes are skipped
        -   }
        -
        -   public void skipExactly(int n) throws IOException {
        -      while (n != 0) {
        -         long skipped = _s.skip(n);
        -         if (skipped == 0)
        -            throw new EOFException();
        -         n -= skipped;
        -      }
        -   }
        -
        - -

        - This rule is deprecated, use {rule:squid:S2674} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ClassCastExceptionWithToArray.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ClassCastExceptionWithToArray.html deleted file mode 100644 index e6b765c6..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ClassCastExceptionWithToArray.html +++ /dev/null @@ -1 +0,0 @@ -if you need to get an array of a class from your Collection, you should pass an array of the desidered class as the parameter of the toArray method. Otherwise you will get a ClassCastException. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ClassNamingConventions.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ClassNamingConventions.html deleted file mode 100644 index 8818e721..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ClassNamingConventions.html +++ /dev/null @@ -1,7 +0,0 @@ -

        - Class names should always begin with an upper case character. -

        - -

        - This rule is deprecated, use {rule:squid:S00101} and {rule:squid:S00114} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ClassWithOnlyPrivateConstructorsShouldBeFinal.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ClassWithOnlyPrivateConstructorsShouldBeFinal.html deleted file mode 100644 index e2bc0509..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ClassWithOnlyPrivateConstructorsShouldBeFinal.html +++ /dev/null @@ -1,10 +0,0 @@ -A class with only private constructors should be final, unless the private constructor is called by a inner class. Example : -
        -public class Foo {  //Should be final
        -    private Foo() { }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S2974} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodMustBePublic.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodMustBePublic.html deleted file mode 100644 index ebf1435e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodMustBePublic.html +++ /dev/null @@ -1,24 +0,0 @@ -

        - The java Manual says “By convention, classes that implement this interface should override Object.clone (which is - protected) with a public method.” -

        - -

        Examples:

        -
        -public class Foo implements Cloneable {
        -  @Override
        -  protected Object clone() throws CloneNotSupportedException { // Violation, must be public
        -  }
        -}
        -
        -public class Foo implements Cloneable {
        -  @Override
        -  protected Foo clone() { // Violation, must be public
        -  }
        -}
        -
        -public class Foo implements Cloneable {
        -  @Override
        -  public Object clone() // Ok
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodMustImplementCloneable.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodMustImplementCloneable.html deleted file mode 100644 index 47616c99..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodMustImplementCloneable.html +++ /dev/null @@ -1,5 +0,0 @@ -The method clone() should only be implemented if the class implements the Cloneable interface with the exception of a final method that only throws CloneNotSupportedException. - -

        - This rule is deprecated, use {rule:squid:S1182} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodMustImplementCloneableWithTypeResolution.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodMustImplementCloneableWithTypeResolution.html deleted file mode 100644 index 51a29488..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodMustImplementCloneableWithTypeResolution.html +++ /dev/null @@ -1,14 +0,0 @@ -The method clone() should only be implemented if the class implements the Cloneable interface with the exception -of a final method that only throws CloneNotSupportedException. This version uses PMD's type resolution facilities, -and can detect if the class implements or extends a Cloneable class. Example: -
        -public class MyClass {
        -  public Object clone() throws CloneNotSupportedException {
        -    return foo;
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1182} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodReturnTypeMustMatchClassName.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodReturnTypeMustMatchClassName.html deleted file mode 100644 index 77b4a6d4..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneMethodReturnTypeMustMatchClassName.html +++ /dev/null @@ -1,23 +0,0 @@ -

        Minimum Language Version: java 1.5

        -

        - If a class implements cloneable the return type of the method clone() must be the class name. That way, the caller of - the clone method doesn’t need to cast the returned clone to the correct type. -

        -

        - Note: This is only possible with Java 1.5 or higher. -

        - -

        Examples:

        -
        -public class Foo implements Cloneable {
        -    @Override
        -    protected Object clone() { // Violation, Object must be Foo
        -    }
        -}
        -
        -public class Foo implements Cloneable {
        -    @Override
        -    public Foo clone() { //Ok
        -    }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneThrowsCloneNotSupportedException.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneThrowsCloneNotSupportedException.html deleted file mode 100644 index 2b5b79f0..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloneThrowsCloneNotSupportedException.html +++ /dev/null @@ -1,5 +0,0 @@ -The method clone() should throw a CloneNotSupportedException. - -

        - This rule is deprecated, use {rule:squid:S1182} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloseResource.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloseResource.html deleted file mode 100644 index 52a17986..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CloseResource.html +++ /dev/null @@ -1,13 +0,0 @@ -Ensure that resources (like Connection, Statement, and ResultSet objects) are always closed after use. It does this by looking for code patterned like : -
        -Connection c = openConnection();
        -try {
        -  // do stuff, and maybe catch something
        -} finally {
        -  c.close();
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S2095} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CollapsibleIfStatements.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CollapsibleIfStatements.html deleted file mode 100644 index 043aa51e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CollapsibleIfStatements.html +++ /dev/null @@ -1,5 +0,0 @@ -Sometimes two 'if' statements can be consolidated by separating their conditions with a boolean short-circuit operator. - -

        - This rule is deprecated, use {rule:squid:S1066} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentContent.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentContent.html deleted file mode 100644 index 46085128..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentContent.html +++ /dev/null @@ -1,4 +0,0 @@ -A rule for the politically correct... we don't want to offend anyone. Example: -
        -// OMG, this is horrible, Bob is an idiot !!!
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentDefaultAccessModifier.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentDefaultAccessModifier.html deleted file mode 100644 index 46a5d997..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentDefaultAccessModifier.html +++ /dev/null @@ -1,28 +0,0 @@ -

        - To avoid mistakes if we want that a Method, Field or Nested class have a default access modifier - we must add a comment at the beginning of the Method, Field or Nested class. - By default the comment must be /* default */, if you want another, you have to provide a regex. -

        - -
        -public class Foo {
        -    final String stringValue = "some string";
        -    String getString() {
        -       return stringValue;
        -    }
        -
        -    class NestedFoo {
        -    }
        -}
        -
        -// should be
        -public class Foo {
        -  /* default */ final String stringValue = "some string";
        -  /* default */ String getString() {
        -     return stringValue;
        -  }
        -
        -  /* default */ class NestedFoo {
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentRequired.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentRequired.html deleted file mode 100644 index 8e0cbbf1..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentRequired.html +++ /dev/null @@ -1,8 +0,0 @@ -Denotes whether comments are required (or unwanted) for specific language elements. Example: -
        -/**
        -* 
        -*
        -* @author George Bush
        -*/
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentSize.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentSize.html deleted file mode 100644 index 395dc440..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CommentSize.html +++ /dev/null @@ -1,19 +0,0 @@ -Determines whether the dimensions of non-header comments found are within the specified limits. Example: -
        -/**
        -*
        -* too many lines!
        -*
        -*
        -*
        -*
        -*
        -*
        -*
        -*
        -*
        -*
        -*
        -*
        -*/
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CompareObjectsWithEquals.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CompareObjectsWithEquals.html deleted file mode 100644 index aeb1a01d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CompareObjectsWithEquals.html +++ /dev/null @@ -1,5 +0,0 @@ -Use equals() to compare object references; avoid comparing them with ==. - -

        - This rule is deprecated, use {rule:squid:S1698} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConfusingTernary.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConfusingTernary.html deleted file mode 100644 index a43624d6..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConfusingTernary.html +++ /dev/null @@ -1 +0,0 @@ -In an if expression with an else clause, avoid negation in the test. For example, rephrase: if (x != y) diff(); else same(); as: if (x == y) same(); else diff(); Most if (x != y) cases without an else are often return cases, so consistent use of this rule makes the code easier to read. Also, this resolves trivial ordering problems, such as does the error case go first? or does the common case go first?. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConsecutiveAppendsShouldReuse.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConsecutiveAppendsShouldReuse.html deleted file mode 100644 index 206ec873..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConsecutiveAppendsShouldReuse.html +++ /dev/null @@ -1,12 +0,0 @@ -Consecutively calls to StringBuffer/StringBuilder .append should reuse the target object. This can improve the performance. Example: -
        -String foo = " ";
        -
        -StringBuffer buf = new StringBuffer();
        -buf.append("Hello"); // poor
        -buf.append(foo);
        -buf.append("World");
        -
        -StringBuffer buf = new StringBuffer();
        -buf.append("Hello").append(foo).append("World"); // good
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConsecutiveLiteralAppends.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConsecutiveLiteralAppends.html deleted file mode 100644 index 293d77bf..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConsecutiveLiteralAppends.html +++ /dev/null @@ -1 +0,0 @@ -Consecutively calling StringBuffer.append with String literals diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConstructorCallsOverridableMethod.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConstructorCallsOverridableMethod.html deleted file mode 100644 index cde4d6db..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ConstructorCallsOverridableMethod.html +++ /dev/null @@ -1,31 +0,0 @@ -Calling overridable methods during construction poses a risk of invoking methods on an incompletely constructed object -and can be difficult to discern. It may leave the sub-class unable to construct its superclass or forced to replicate -the construction process completely within itself, losing the ability to call super(). -If the default constructor contains a call to an overridable method, the subclass may be completely uninstantiable. -Note that this includes method calls throughout the control flow graph - i.e., if a constructor Foo() calls -a private method bar() that calls a public method buz(), this denotes a problem. -
        Example : -
        -public class SeniorClass {
        -  public SeniorClass(){
        -      toString(); //may throw NullPointerException if overridden
        -  }
        -  public String toString(){
        -    return "IAmSeniorClass";
        -  }
        -}
        -public class JuniorClass extends SeniorClass {
        -  private String name;
        -  public JuniorClass(){
        -    super(); //Automatic call leads to NullPointerException
        -    name = "JuniorClass";
        -  }
        -  public String toString(){
        -    return name.toUpperCase();
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1699} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CouplingBetweenObjects.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CouplingBetweenObjects.html deleted file mode 100644 index 06281e28..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CouplingBetweenObjects.html +++ /dev/null @@ -1,5 +0,0 @@ -This rule counts unique attributes, local variables and return types within an object. A number higher than specified threshold can indicate a high degree of coupling. - -

        - This rule is deprecated, use {rule:squid:S1200} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CyclomaticComplexity.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CyclomaticComplexity.html deleted file mode 100644 index cea4648e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/CyclomaticComplexity.html +++ /dev/null @@ -1,10 +0,0 @@ -

        - Complexity is determined by the number of decision points in a method plus one for the method entry. The decision - points are 'if', 'while', 'for', and 'case labels'. Generally, 1-4 is low complexity, 5-7 indicates moderate - complexity, 8-10 is high complexity, and 11+ is very high complexity. -

        - -

        - This rule is deprecated, use {rule:squid:MethodCyclomaticComplexity} or {rule:squid:ClassCyclomaticComplexity} - instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DataflowAnomalyAnalysis.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DataflowAnomalyAnalysis.html deleted file mode 100644 index d9d32c1f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DataflowAnomalyAnalysis.html +++ /dev/null @@ -1 +0,0 @@ -The dataflow analysis tracks local definitions, undefinitions and references to variables on different paths on the data flow. From those informations there can be found various problems. 1. UR - Anomaly: There is a reference to a variable that was not defined before. This is a bug and leads to an error. 2. DU - Anomaly: A recently defined variable is undefined. These anomalies may appear in normal source text. 3. DD - Anomaly: A recently defined variable is redefined. This is ominous but don't have to be a bug. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DefaultLabelNotLastInSwitchStmt.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DefaultLabelNotLastInSwitchStmt.html deleted file mode 100644 index 90004280..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DefaultLabelNotLastInSwitchStmt.html +++ /dev/null @@ -1,19 +0,0 @@ -Switch statements should have a default label. Example : -
        -public class Foo {
        - void bar(int a) {
        -  switch (a) {
        -   case 1:  // do something
        -      break;
        -   default:  // the default case should be last, by convention
        -      break;
        -   case 2:
        -      break;
        -  }
        - }
        -}
        -  
        - -

        - This rule is deprecated, use {rule:squid:SwitchLastCaseIsDefaultCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DefaultPackage.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DefaultPackage.html deleted file mode 100644 index 85632d85..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DefaultPackage.html +++ /dev/null @@ -1 +0,0 @@ -Use explicit scoping instead of the default package private level. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotCallGarbageCollectionExplicitly.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotCallGarbageCollectionExplicitly.html deleted file mode 100644 index a7379dda..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotCallGarbageCollectionExplicitly.html +++ /dev/null @@ -1,24 +0,0 @@ -Calls to System.gc(), Runtime.getRuntime().gc(), and System.runFinalization() are not advised. Code should have the same behavior whether the garbage collection is disabled using the option -Xdisableexplicitgc or not. Moreover, "modern" jvms do a very good job handling garbage collections. If memory usage issues unrelated to memory leaks develop within an application, it should be dealt with JVM options rather than within the code itself. Example : -
        - public class GCCall
        -{
        -  public GCCall()
        -  {
        -  // Explicit gc call !
        -    System.gc();
        -  }
        -  public void doSomething()
        -  {
        -    // Explicit gc call !
        -    Runtime.getRuntime().gc();
        -  }
        -
        -  public explicitGCcall() { // Explicit gc call ! System.gc(); }
        -
        -  public void doSomething() { // Explicit gc call ! Runtime.getRuntime().gc(); }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1215} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotCallSystemExit.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotCallSystemExit.html deleted file mode 100644 index 1d8516b6..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotCallSystemExit.html +++ /dev/null @@ -1,5 +0,0 @@ -Web applications should not call System.exit(), since only the web container or the application server should stop the JVM. - -

        - This rule is deprecated, use {rule:squid:S1147} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotExtendJavaLangError.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotExtendJavaLangError.html deleted file mode 100644 index 3a414acd..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotExtendJavaLangError.html +++ /dev/null @@ -1,5 +0,0 @@ -Errors are system exceptions. Do not extend them. - -

        - This rule is deprecated, use {rule:squid:S1194} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotHardCodeSDCard.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotHardCodeSDCard.html deleted file mode 100644 index 003eaefe..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotHardCodeSDCard.html +++ /dev/null @@ -1 +0,0 @@ -Use Environment.getExternalStorageDirectory() instead of "/sdcard". diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotThrowExceptionInFinally.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotThrowExceptionInFinally.html deleted file mode 100644 index 56f2e89c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotThrowExceptionInFinally.html +++ /dev/null @@ -1,24 +0,0 @@ -Throwing exception in a finally block is confusing. It may mask exception or a defect of the code, it also render code cleanup uninstable. Example : -
        -public class Foo
        -{
        -  public void bar()
        -  {
        -    try {
        -    // Here do some stuff
        -    }
        -    catch( Exception e) {
        -    // Handling the issue
        -    }
        -    finally
        -    {
        -      // is this really a good idea ?
        -      throw new Exception();
        -    }
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1163} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotUseThreads.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotUseThreads.html deleted file mode 100644 index 408b98a1..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoNotUseThreads.html +++ /dev/null @@ -1 +0,0 @@ -The J2EE specification explicitly forbid use of threads. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontCallThreadRun.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontCallThreadRun.html deleted file mode 100644 index d175f242..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontCallThreadRun.html +++ /dev/null @@ -1,5 +0,0 @@ -Explicitly calling Thread.run() method will execute in the caller's thread of control. Instead, call Thread.start() for the intended behavior. - -

        - This rule is deprecated, use {rule:squid:S1217} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontImportJavaLang.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontImportJavaLang.html deleted file mode 100644 index 6277e6f4..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontImportJavaLang.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid importing anything from the package 'java.lang'. These classes are automatically imported (JLS 7.5.3). - -

        - This rule is deprecated, use {rule:squid:UselessImportCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontImportSun.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontImportSun.html deleted file mode 100644 index e344f9ed..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontImportSun.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid importing anything from the 'sun.*' packages. These packages are not portable and are likely to change. - -

        - This rule is deprecated, use {rule:squid:S1191} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontUseFloatTypeForLoopIndices.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontUseFloatTypeForLoopIndices.html deleted file mode 100644 index 054f351f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DontUseFloatTypeForLoopIndices.html +++ /dev/null @@ -1,16 +0,0 @@ -Don't use floating point for loop indices. If you must use floating point, use double -unless you're certain that float provides enough precision and you have a compelling -performance need (space or time). Example: -
        -public class Count {
        -  public static void main(String[] args) {
        -    final int START = 2000000000;
        -    int count = 0;
        -    for (float f = START; f < START + 50; f++)
        -      count++;
        -      //Prints 0 because (float) START == (float) (START + 50).
        -      System.out.println(count);
        -      //The termination test misbehaves due to floating point granularity.
        -    }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoubleCheckedLocking.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoubleCheckedLocking.html deleted file mode 100644 index 6874ea4f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DoubleCheckedLocking.html +++ /dev/null @@ -1,17 +0,0 @@ -Partially created objects can be returned by the Double Checked Locking pattern when used in Java. An optimizing JRE may assign a reference to the baz variable before it creates the object the reference is intended to point to. -More details. Example : -
        -public class Foo {
        -  Object baz;
        -  Object bar() {
        -    if(baz == null) { //baz may be non-null yet not fully created
        -      synchronized(this){
        -        if(baz == null){
        -          baz = new Object();
        -        }
        -      }
        -    }
        -    return baz;
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DuplicateImports.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DuplicateImports.html deleted file mode 100644 index 1c9a9608..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/DuplicateImports.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid duplicate import statements. - -

        - This rule is deprecated, use {rule:squid:UselessImportCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyCatchBlock.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyCatchBlock.html deleted file mode 100644 index 60e3b26c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyCatchBlock.html +++ /dev/null @@ -1,8 +0,0 @@ -

        - Empty Catch Block finds instances where an exception is caught, but nothing is done. In most circumstances, this - swallows an exception which should either be acted on or reported. -

        - -

        - This rule is deprecated, use {rule:squid:S00108} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyFinalizer.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyFinalizer.html deleted file mode 100644 index 8c9eb51e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyFinalizer.html +++ /dev/null @@ -1,5 +0,0 @@ -

        If the finalize() method is empty, then it does not need to exist.

        - -

        - This rule is deprecated, use {rule:squid:S1186} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyFinallyBlock.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyFinallyBlock.html deleted file mode 100644 index 269fe90c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyFinallyBlock.html +++ /dev/null @@ -1,7 +0,0 @@ -

        - Avoid empty finally blocks - these can be deleted. -

        - -

        - This rule is deprecated, use {rule:squid:S00108} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyIfStmt.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyIfStmt.html deleted file mode 100644 index 2d83e4c9..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyIfStmt.html +++ /dev/null @@ -1,7 +0,0 @@ -

        - Empty If Statement finds instances where a condition is checked but nothing is done about it. -

        - -

        - This rule is deprecated, use {rule:squid:S00108} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyInitializer.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyInitializer.html deleted file mode 100644 index 80827069..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyInitializer.html +++ /dev/null @@ -1,14 +0,0 @@ -An empty initializer was found. Example : -
        -public class Foo {
        -
        -   static {} // Why ?
        -
        -   {} // Again, why ?
        -
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S00108} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyMethodInAbstractClassShouldBeAbstract.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyMethodInAbstractClassShouldBeAbstract.html deleted file mode 100644 index de702def..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyMethodInAbstractClassShouldBeAbstract.html +++ /dev/null @@ -1,15 +0,0 @@ -An empty method in an abstract class should be abstract instead, as developer may rely on this empty implementation rather than code the appropriate one. -
        -public abstract class ShouldBeAbstract
        -{
        -  public Object couldBeAbstract()
        -  {
        -  // Should be abstract method ?
        -    return null;
        -  }
        -
        -  public void couldBeAbstract()
        -  {
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyStatementBlock.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyStatementBlock.html deleted file mode 100644 index efcfc3d2..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyStatementBlock.html +++ /dev/null @@ -1,17 +0,0 @@ -Empty block statements serve no purpose and should be removed. Example: -
        -public class Foo {
        -
        -   private int _bar;
        -
        -   public void setBar(int bar) {
        -      { _bar = bar; } // Why not?
        -      {} // But remove this.
        -   }
        -
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S00108} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyStatementNotInLoop.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyStatementNotInLoop.html deleted file mode 100644 index fd1ea97d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyStatementNotInLoop.html +++ /dev/null @@ -1,5 +0,0 @@ -An empty statement (aka a semicolon by itself) that is not used as the sole body of a for loop or while loop is probably a bug. It could also be a double semicolon, which is useless and should be removed. - -

        - This rule is deprecated, use {rule:squid:EmptyStatementUsageCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyStaticInitializer.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyStaticInitializer.html deleted file mode 100644 index a7611060..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyStaticInitializer.html +++ /dev/null @@ -1,5 +0,0 @@ -An empty static initializer was found. - -

        - This rule is deprecated, use {rule:squid:S00108} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptySwitchStatements.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptySwitchStatements.html deleted file mode 100644 index 81d3ea20..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptySwitchStatements.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid empty switch statements. - -

        - This rule is deprecated, use {rule:squid:S00108} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptySynchronizedBlock.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptySynchronizedBlock.html deleted file mode 100644 index 16f1a97d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptySynchronizedBlock.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid empty synchronized blocks - they're useless. - -

        - This rule is deprecated, use {rule:squid:S00108} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyTryBlock.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyTryBlock.html deleted file mode 100644 index 1058475d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyTryBlock.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid empty try blocks - what's the point? - -

        - This rule is deprecated, use {rule:squid:S00108} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyWhileStmt.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyWhileStmt.html deleted file mode 100644 index 0edd432b..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EmptyWhileStmt.html +++ /dev/null @@ -1,5 +0,0 @@ -Empty While Statement finds all instances where a while statement does nothing. If it is a timing loop, then you should use Thread.sleep() for it; if it's a while loop that does a lot in the exit expression, rewrite it to make it clearer. - -

        - This rule is deprecated, use {rule:squid:S00108} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EqualsNull.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EqualsNull.html deleted file mode 100644 index 12624bab..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/EqualsNull.html +++ /dev/null @@ -1,5 +0,0 @@ -Inexperienced programmers sometimes confuse comparison concepts and use equals() to compare to null. - -

        - This rule is deprecated, use {rule:squid:S2159} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExceptionAsFlowControl.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExceptionAsFlowControl.html deleted file mode 100644 index 93777132..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExceptionAsFlowControl.html +++ /dev/null @@ -1,5 +0,0 @@ -Using Exceptions as flow control leads to GOTOish code and obscures true exceptions when debugging. - -

        - This rule is deprecated, use {rule:squid:S1141} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveClassLength.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveClassLength.html deleted file mode 100644 index 4e366cd5..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveClassLength.html +++ /dev/null @@ -1,5 +0,0 @@ -Long Class files are indications that the class may be trying to do too much. Try to break it down, and reduce the size to something manageable. - -

        - This rule is deprecated, use {rule:squid:S1448} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveImports.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveImports.html deleted file mode 100644 index 40369fff..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveImports.html +++ /dev/null @@ -1,5 +0,0 @@ -A high number of imports can indicate a high degree of coupling within an object. Rule counts the number of unique imports and reports a violation if the count is above the user defined threshold. - -

        - This rule is deprecated, use {rule:squid:S1200} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveMethodLength.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveMethodLength.html deleted file mode 100644 index f160cd0e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveMethodLength.html +++ /dev/null @@ -1,5 +0,0 @@ -Violations of this rule usually indicate that the method is doing too much. Try to reduce the method size by creating helper methods and removing any copy/pasted code. - -

        - This rule is deprecated, use {rule:squid:S138} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveParameterList.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveParameterList.html deleted file mode 100644 index 2b72623a..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessiveParameterList.html +++ /dev/null @@ -1,8 +0,0 @@ -

        - Long parameter lists can indicate that a new object should be created to wrap the numerous parameters. Basically, try - to group the parameters together. -

        - -

        - This rule is deprecated, use {rule:squid:S00107} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessivePublicCount.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessivePublicCount.html deleted file mode 100644 index db8dc9cb..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExcessivePublicCount.html +++ /dev/null @@ -1,5 +0,0 @@ -A large number of public methods and attributes declared in a class can indicate the class may need to be broken up as increased effort will be required to thoroughly test it. - -

        - This rule is deprecated, use {rule:squid:S1448} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExtendsObject.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExtendsObject.html deleted file mode 100644 index b81cdf9e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ExtendsObject.html +++ /dev/null @@ -1,9 +0,0 @@ -No need to explicitly extend Object. Example: -
        -public class Foo extends Object { // not required
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1939} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FieldDeclarationsShouldBeAtStartOfClass.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FieldDeclarationsShouldBeAtStartOfClass.html deleted file mode 100644 index 91b34827..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FieldDeclarationsShouldBeAtStartOfClass.html +++ /dev/null @@ -1,19 +0,0 @@ -Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes. Example: -
        -public class HelloWorldBean {
        -
        -  // Field declared before methods / inner classes - OK
        -  private String _thing;
        -
        -  public String getMessage() {
        -    return "Hello World!";
        -  }
        -
        -  // Field declared after methods / inner classes - avoid this
        -  private String _fieldInWrongLocation;
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1213} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalFieldCouldBeStatic.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalFieldCouldBeStatic.html deleted file mode 100644 index e0f30b07..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalFieldCouldBeStatic.html +++ /dev/null @@ -1,5 +0,0 @@ -If a final field is assigned to a compile-time constant, it could be made static, thus saving overhead in each object at runtime. - -

        - This rule is deprecated, use {rule:squid:S1170} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeDoesNotCallSuperFinalize.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeDoesNotCallSuperFinalize.html deleted file mode 100644 index 15c4c595..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeDoesNotCallSuperFinalize.html +++ /dev/null @@ -1,5 +0,0 @@ -If the finalize() is implemented, its last action should be to call super.finalize. - -

        - This rule is deprecated, use {rule:squid:ObjectFinalizeOverridenCallsSuperFinalizeCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeOnlyCallsSuperFinalize.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeOnlyCallsSuperFinalize.html deleted file mode 100644 index be9537f4..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeOnlyCallsSuperFinalize.html +++ /dev/null @@ -1,5 +0,0 @@ -If the finalize() is implemented, it should do something besides just calling super.finalize(). - -

        - This rule is deprecated, use {rule:squid:S1185} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeOverloaded.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeOverloaded.html deleted file mode 100644 index 2f7e764e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeOverloaded.html +++ /dev/null @@ -1,5 +0,0 @@ -Methods named finalize() should not have parameters. It is confusing and probably a bug to overload finalize(). It will not be called by the VM. - -

        - This rule is deprecated, use {rule:squid:S1175} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeShouldBeProtected.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeShouldBeProtected.html deleted file mode 100644 index 097cc3ea..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/FinalizeShouldBeProtected.html +++ /dev/null @@ -1,5 +0,0 @@ -If you override finalize(), make it protected. If you make it public, other classes may call it. - -

        - This rule is deprecated, use {rule:squid:S1174} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ForLoopShouldBeWhileLoop.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ForLoopShouldBeWhileLoop.html deleted file mode 100644 index 6c461e5c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ForLoopShouldBeWhileLoop.html +++ /dev/null @@ -1,5 +0,0 @@ -Some for loops can be simplified to while loops - this makes them more concise. - -

        - This rule is deprecated, use {rule:squid:S1264} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ForLoopsMustUseBraces.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ForLoopsMustUseBraces.html deleted file mode 100644 index 898fdb13..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ForLoopsMustUseBraces.html +++ /dev/null @@ -1,7 +0,0 @@ -

        - Avoid using 'for' statements without using curly braces, like for (int i=0; i<42;i++) foo(); -

        - -

        - This rule is deprecated, use {rule:squid:S00121} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GenericsNaming.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GenericsNaming.html deleted file mode 100644 index 99c6544d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GenericsNaming.html +++ /dev/null @@ -1,5 +0,0 @@ -Generics names should be a one letter long and upper case. - -

        - This rule is deprecated, use {rule:squid:S00119} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GodClass.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GodClass.html deleted file mode 100644 index 2a40eda1..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GodClass.html +++ /dev/null @@ -1,7 +0,0 @@ -The God Class rule detects the God Class design flaw using metrics. God classes do too many things, -are very big and overly complex. They should be split apart to be more object-oriented. -The rule uses the detection strategy described in "Object-Oriented Metrics in Practice". -The violations are reported against the entire class. See also the references: -Michele Lanza and Radu Marinescu. Object-Oriented Metrics in Practice: -Using Software Metrics to Characterize, Evaluate, and Improve the Design -of Object-Oriented Systems. Springer, Berlin, 1 edition, October 2006. Page 80. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GuardDebugLogging.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GuardDebugLogging.html deleted file mode 100644 index cc533ca8..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GuardDebugLogging.html +++ /dev/null @@ -1 +0,0 @@ -When log messages are composed by concatenating strings, the whole section should be guarded by a isDebugEnabled() check to avoid performance and memory issues. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GuardLogStatement.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GuardLogStatement.html deleted file mode 100644 index 8e4da158..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GuardLogStatement.html +++ /dev/null @@ -1,7 +0,0 @@ -Whenever using a log level, one should check if the loglevel is actually enabled, or -otherwise skip the associate String creation and manipulation. Example: -
        -// Add this for performance
        -if (log.isDebugEnabled() { ...
        -  log.debug("This happens");
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GuardLogStatementJavaUtil.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GuardLogStatementJavaUtil.html deleted file mode 100644 index a7355ba8..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/GuardLogStatementJavaUtil.html +++ /dev/null @@ -1,7 +0,0 @@ -Whenever using a log level, one should check if the loglevel is actually enabled, or -otherwise skip the associate String creation and manipulation. Example: -
        -// Add this for performance
        -if (log.isLoggable(Level.FINE)) { ...
        -  log.fine("This happens");
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IdempotentOperations.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IdempotentOperations.html deleted file mode 100644 index b5491f34..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IdempotentOperations.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid idempotent operations - they are have no effect. Example :
        int x = 2;
        x = x;
        - -

        - This rule is deprecated, use {rule:squid:S1656} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IfElseStmtsMustUseBraces.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IfElseStmtsMustUseBraces.html deleted file mode 100644 index aa1d687b..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IfElseStmtsMustUseBraces.html +++ /dev/null @@ -1,7 +0,0 @@ -

        - Avoid using if..else statements without using curly braces. -

        - -

        - This rule is deprecated, use {rule:squid:S00121} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IfStmtsMustUseBraces.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IfStmtsMustUseBraces.html deleted file mode 100644 index f5c0e1f2..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IfStmtsMustUseBraces.html +++ /dev/null @@ -1,7 +0,0 @@ -

        - Avoid using if statements without using curly braces. -

        - -

        - This rule is deprecated, use {rule:squid:S00121} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ImmutableField.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ImmutableField.html deleted file mode 100644 index 7732e300..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ImmutableField.html +++ /dev/null @@ -1 +0,0 @@ -Identifies private fields whose values never change once they are initialized either in the declaration of the field or by a constructor. This aids in converting existing classes to immutable classes. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ImportFromSamePackage.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ImportFromSamePackage.html deleted file mode 100644 index 2fc41d34..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ImportFromSamePackage.html +++ /dev/null @@ -1,5 +0,0 @@ -No need to import a type that lives in the same package. - -

        - This rule is deprecated, use {rule:squid:UselessImportCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InefficientEmptyStringCheck.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InefficientEmptyStringCheck.html deleted file mode 100644 index cdf337a7..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InefficientEmptyStringCheck.html +++ /dev/null @@ -1 +0,0 @@ -String.trim().length() is an inefficient way to check if a String is really empty, as it creates a new String object just to check its size. Consider creating a static function that loops through a string, checking Character.isWhitespace() on each character and returning false if a non-whitespace character is found. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InefficientStringBuffering.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InefficientStringBuffering.html deleted file mode 100644 index 538688b6..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InefficientStringBuffering.html +++ /dev/null @@ -1 +0,0 @@ -Avoid concatenating non literals in a StringBuffer constructor or append(). diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InstantiationToGetClass.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InstantiationToGetClass.html deleted file mode 100644 index 2042392a..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InstantiationToGetClass.html +++ /dev/null @@ -1,6 +0,0 @@ -Avoid instantiating an object just to call getClass() on it; use the .class public member instead. Example : replace -Class c = new String().getClass(); with Class c = String.class; - -

        - This rule is deprecated, use {rule:squid:S2133} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InsufficientStringBufferDeclaration.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InsufficientStringBufferDeclaration.html deleted file mode 100644 index c8e7c7ef..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/InsufficientStringBufferDeclaration.html +++ /dev/null @@ -1 +0,0 @@ -Failing to pre-size a StringBuffer properly could cause it to re-size many times during runtime. This rule checks the characters that are actually passed into StringBuffer.append(), but represents a best guess worst case scenario. An empty StringBuffer constructor initializes the object to 16 characters. This default is assumed if the length of the constructor can not be determined. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IntegerInstantiation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IntegerInstantiation.html deleted file mode 100644 index 778be374..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/IntegerInstantiation.html +++ /dev/null @@ -1 +0,0 @@ -In JDK 1.5, calling new Integer() causes memory allocation. Integer.valueOf() is more memory friendly. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/JumbledIncrementer.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/JumbledIncrementer.html deleted file mode 100644 index 35e7ad51..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/JumbledIncrementer.html +++ /dev/null @@ -1,16 +0,0 @@ -Avoid jumbled loop incrementers - it's usually a mistake, and it's confusing even if it's what's intended. -
        Example : -
        -public class JumbledIncrementerRule1 {
        -  public void foo() {
        -   for (int i = 0; i < 10; i++) {
        -    for (int k = 0; k < 20; i++) {
        -     System.out.println("Hello");
        -    }
        -   }
        -  }
        -}
        - -

        - This rule is deprecated, use {rule:squid:ForLoopCounterChangedCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LawOfDemeter.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LawOfDemeter.html deleted file mode 100644 index 237063e0..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LawOfDemeter.html +++ /dev/null @@ -1,30 +0,0 @@ -The Law of Demeter is a simple rule, that says "only talk to friends". It helps to reduce coupling between classes or objects. -See also the references: -Andrew Hunt, David Thomas, and Ward Cunningham. The Pragmatic Programmer. From Journeyman to Master. Addison-Wesley Longman, Amsterdam, October 1999.; -K.J. Lieberherr and I.M. Holland. Assuring good style for object-oriented programs. Software, IEEE, 6(5):38–48, 1989.; -http://www.ccs.neu.edu/home/lieber/LoD.html; -http://en.wikipedia.org/wiki/Law_of_Demeter -

        Example:

        -
        -public class Foo {
        -    /**
        -     * This example will result in two violations.
        -     */
        -    public void example(Bar b) {
        -        // this method call is ok, as b is a parameter of "example"
        -        C c = b.getC();
        -        
        -        // this method call is a violation, as we are using c, which we got from B.
        -        // We should ask b directly instead, e.g. "b.doItOnC();"
        -        c.doIt();
        -        
        -        // this is also a violation, just expressed differently as a method chain without temporary variables.
        -        b.getC().doIt();
        -        
        -        // a constructor call, not a method call.
        -        D d = new D();
        -        // this method call is ok, because we have create the new instance of D locally.
        -        d.doSomethingElse(); 
        -    }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LocalHomeNamingConvention.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LocalHomeNamingConvention.html deleted file mode 100644 index d17bbc37..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LocalHomeNamingConvention.html +++ /dev/null @@ -1 +0,0 @@ -The Local Home interface of a Session EJB should be suffixed by "LocalHome". diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LocalInterfaceSessionNamingConvention.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LocalInterfaceSessionNamingConvention.html deleted file mode 100644 index ae234c8c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LocalInterfaceSessionNamingConvention.html +++ /dev/null @@ -1 +0,0 @@ -The Local Interface of a Session EJB should be suffixed by "Local". diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LocalVariableCouldBeFinal.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LocalVariableCouldBeFinal.html deleted file mode 100644 index 84ae1da7..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LocalVariableCouldBeFinal.html +++ /dev/null @@ -1,9 +0,0 @@ -A local variable assigned only once can be declared final. Example : -
        -public class Bar {
        - public void foo () {
        -  String a = "a"; //if a will not be assigned again it is better to do this:
        -  final String b = "b";
        - }
        -}
        -  
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LoggerIsNotStaticFinal.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LoggerIsNotStaticFinal.html deleted file mode 100644 index d9fd6e52..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LoggerIsNotStaticFinal.html +++ /dev/null @@ -1,5 +0,0 @@ -In most cases, the Logger can be declared static and final. - -

        - This rule is deprecated, use {rule:squid:S1312} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LogicInversion.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LogicInversion.html deleted file mode 100644 index e5415599..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LogicInversion.html +++ /dev/null @@ -1,17 +0,0 @@ -Use opposite operator instead of negating the whole expression with a logic complement operator. Example: -
        -public boolean bar(int a, int b) {
        -
        -  if (!(a == b)) // use !=
        -    return false;
        -
        -  if (!(a < b)) // use >=
        -    return false;
        -
        -  return true;
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1940} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LongInstantiation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LongInstantiation.html deleted file mode 100644 index 66db7658..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LongInstantiation.html +++ /dev/null @@ -1,7 +0,0 @@ -In JDK 1.5, calling new Long() causes memory allocation. Long.valueOf() is more memory friendly. Example : -
        -public class Foo {
        -private Long i = new Long(0); // change to Long i =
        -Long.valueOf(0);
        -}
        -  
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LongVariable.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LongVariable.html deleted file mode 100644 index 05910f86..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LongVariable.html +++ /dev/null @@ -1,5 +0,0 @@ -Detects when a field, formal or local variable is declared with a long name. - -

        - This rule is deprecated, use {rule:squid:S00117} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LooseCoupling.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LooseCoupling.html deleted file mode 100644 index 095bfe5f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LooseCoupling.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid using implementation types (i.e., HashSet); use the interface (i.e, Set) instead - -

        - This rule is deprecated, use {rule:squid:S1319} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LooseCouplingWithTypeResolution.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LooseCouplingWithTypeResolution.html deleted file mode 100644 index 0f8732bf..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LooseCouplingWithTypeResolution.html +++ /dev/null @@ -1,21 +0,0 @@ -Avoid using implementation types (i.e., HashSet); use the interface (i.e, Set) instead Example: -
        -import java.util.ArrayList;
        -import java.util.HashSet;
        -
        -public class Bar {
        -
        -  // Use List instead
        -  private ArrayList list = new ArrayList();
        -
        -  // Use Set instead
        -  public HashSet getFoo() {
        -    return new HashSet();
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1319} instead. -

        - diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LoosePackageCoupling.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LoosePackageCoupling.html deleted file mode 100644 index 0b1a9a8f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/LoosePackageCoupling.html +++ /dev/null @@ -1,15 +0,0 @@ -Avoid using classes from the configured package hierarchy outside of the package hierarchy, -except when using one of the configured allowed classes. Example: -
        -package some.package;
        -
        -import some.other.package.subpackage.subsubpackage.DontUseThisClass;
        -
        -public class Bar {
        -   DontUseThisClass boo = new DontUseThisClass();
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:ArchitecturalConstraint} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MDBAndSessionBeanNamingConvention.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MDBAndSessionBeanNamingConvention.html deleted file mode 100644 index eed52060..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MDBAndSessionBeanNamingConvention.html +++ /dev/null @@ -1 +0,0 @@ -The EJB Specification state that any MessageDrivenBean or SessionBean should be suffixed by Bean. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodArgumentCouldBeFinal.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodArgumentCouldBeFinal.html deleted file mode 100644 index 4c8a4a6e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodArgumentCouldBeFinal.html +++ /dev/null @@ -1,5 +0,0 @@ -A method argument that is never assigned can be declared final. - -

        - This rule is deprecated, use {rule:squid:S1226} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodNamingConventions.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodNamingConventions.html deleted file mode 100644 index 19296096..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodNamingConventions.html +++ /dev/null @@ -1,11 +0,0 @@ -Method names should always begin with a lower case character, and should not contain underscores. Example : -
        -public class Foo {
        -  public void fooStuff() {
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S00100} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodReturnsInternalArray.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodReturnsInternalArray.html deleted file mode 100644 index c3c9e799..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodReturnsInternalArray.html +++ /dev/null @@ -1,5 +0,0 @@ -Exposing internal arrays directly allows the user to modify some code that could be critical. It is safer to return a copy of the array. - -

        - This rule is deprecated, use {rule:squid:S2384} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodWithSameNameAsEnclosingClass.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodWithSameNameAsEnclosingClass.html deleted file mode 100644 index 760768bd..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MethodWithSameNameAsEnclosingClass.html +++ /dev/null @@ -1,13 +0,0 @@ -Non-constructor methods should not have the same name as the enclosing class. Example : -
        -public class MyClass {
        -  // this is bad because it is a method
        -  public void MyClass() {}
        -  // this is OK because it is a constructor
        -  public MyClass() {}
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1223} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MisleadingVariableName.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MisleadingVariableName.html deleted file mode 100644 index bf8ed2e3..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MisleadingVariableName.html +++ /dev/null @@ -1,13 +0,0 @@ -Detects when a non-field has a name starting with 'm_'. This usually indicates a field and thus is confusing. Example : -
        -public class Foo {
        -  private int m_foo; // OK
        -  public void bar(String m_baz) {  // Bad
        -    int m_boz = 42; // Bad
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S00117} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MisplacedNullCheck.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MisplacedNullCheck.html deleted file mode 100644 index 31daf130..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MisplacedNullCheck.html +++ /dev/null @@ -1,12 +0,0 @@ -The null check here is misplaced. if the variable is null you'll get a NullPointerException. -Either the check is useless (the variable will never be null) or it's incorrect. -
        Example : -
        -if (object1!=null && object2.equals(object1)) { 
        -  ...
        -}      
        -
        - -

        - This rule is deprecated, use {rule:squid:S1697} or {rule:squid:S2259} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MissingBreakInSwitch.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MissingBreakInSwitch.html deleted file mode 100644 index d8b9383c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MissingBreakInSwitch.html +++ /dev/null @@ -1,5 +0,0 @@ -A switch statement without an enclosed break statement may be a bug. - -

        - This rule is deprecated, use {rule:squid:S128} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MissingSerialVersionUID.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MissingSerialVersionUID.html deleted file mode 100644 index b27f8ce0..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MissingSerialVersionUID.html +++ /dev/null @@ -1,5 +0,0 @@ -Classes that are serializable should provide a serialVersionUID field. - -

        - This rule is deprecated, use {rule:squid:S2057} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MissingStaticMethodInNonInstantiatableClass.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MissingStaticMethodInNonInstantiatableClass.html deleted file mode 100644 index 4f64c39f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MissingStaticMethodInNonInstantiatableClass.html +++ /dev/null @@ -1 +0,0 @@ -A class that has private constructors and does not have any static methods or fields cannot be used. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ModifiedCyclomaticComplexity.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ModifiedCyclomaticComplexity.html deleted file mode 100644 index b8be7350..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ModifiedCyclomaticComplexity.html +++ /dev/null @@ -1,5 +0,0 @@ -Complexity directly affects maintenance costs is determined by the number of decision points in a method plus one for the method entry. The decision points include 'if', 'while', 'for', and 'case labels' calls. Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote high complexity, and 11+ is very high complexity. Modified complexity treats switch statements as a single decision point. - -

        - This rule is deprecated, use {rule:squid:MethodCyclomaticComplexity} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MoreThanOneLogger.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MoreThanOneLogger.html deleted file mode 100644 index f90c5c34..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/MoreThanOneLogger.html +++ /dev/null @@ -1,5 +0,0 @@ -Normally only one logger is used in each class. - -

        - This rule is deprecated, use {rule:squid:S1312} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NPathComplexity.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NPathComplexity.html deleted file mode 100644 index 58e19868..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NPathComplexity.html +++ /dev/null @@ -1,8 +0,0 @@ -The NPath complexity of a method is the number of acyclic execution paths through that method. A threshold of 200 is generally considered the point where measures should be taken to reduce complexity. Example : -
        -public class Foo {
        -  void bar() {
        -   // lots of complicated code
        -  }
        - }
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NcssConstructorCount.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NcssConstructorCount.html deleted file mode 100644 index c0736c4d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NcssConstructorCount.html +++ /dev/null @@ -1,5 +0,0 @@ -This rule uses the NCSS (Non Commenting Source Statements) algorithm to determine the number of lines of code for a given constructor. NCSS ignores comments, and counts actual statements. Using this algorithm, lines of code that are split are counted as one. - -

        - This rule is deprecated, use {rule:squid:S138} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NcssMethodCount.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NcssMethodCount.html deleted file mode 100644 index b8326e50..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NcssMethodCount.html +++ /dev/null @@ -1,5 +0,0 @@ -This rule uses the NCSS (Non Commenting Source Statements) algorithm to determine the number of lines of code for a given method. NCSS ignores comments, and counts actual statements. Using this algorithm, lines of code that are split are counted as one. - -

        - This rule is deprecated, use {rule:squid:S138} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NcssTypeCount.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NcssTypeCount.html deleted file mode 100644 index b92ab58f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NcssTypeCount.html +++ /dev/null @@ -1,5 +0,0 @@ -This rule uses the NCSS (Non Commenting Source Statements) algorithm to determine the number of lines of code for a given type. NCSS ignores comments, and counts actual statements. Using this algorithm, lines of code that are split are counted as one. - -

        - This rule is deprecated, use {rule:common-java:InsufficientCommentDensity} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NoPackage.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NoPackage.html deleted file mode 100644 index 8641090e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NoPackage.html +++ /dev/null @@ -1,10 +0,0 @@ -Detects when a class or interface does not have a package definition. Example : -
        -// no package declaration
        -public class ClassInDefaultPackage {
        -}
        -  
        - -

        - This rule is deprecated, use {rule:squid:S1220} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NonCaseLabelInSwitchStatement.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NonCaseLabelInSwitchStatement.html deleted file mode 100644 index 40693f1f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NonCaseLabelInSwitchStatement.html +++ /dev/null @@ -1,5 +0,0 @@ -A non-case label (e.g. a named break/continue label) was present in a switch statement. This legal, but confusing. It is easy to mix up the case labels and the non-case labels. - -

        - This rule is deprecated, use {rule:squid:S1219} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NonStaticInitializer.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NonStaticInitializer.html deleted file mode 100644 index 9b8bd31b..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NonStaticInitializer.html +++ /dev/null @@ -1,7 +0,0 @@ -A nonstatic initializer block will be called any time a constructor is invoked (just prior to invoking the constructor). While this is a valid language construct, it is rarely used and is confusing. Example : -
        public class MyClass {
        // this block gets run before any call to a constructor {
        System.out.println("I - am about to construct myself");
        }
        }
        - -

        - This rule is deprecated, use {rule:squid:S1171} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NonThreadSafeSingleton.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NonThreadSafeSingleton.html deleted file mode 100644 index 4a1c3505..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NonThreadSafeSingleton.html +++ /dev/null @@ -1,5 +0,0 @@ -Non-thread safe singletons can result in bad state changes. Eliminate static singletons if possible by instantiating the object directly. Static singletons are usually not needed as only a single instance exists anyway. Other possible fixes are to synchronize the entire method or to use an initialize-on-demand holder class (do not use the double-check idiom). See Effective Java, item 48. - -

        - This rule is deprecated, use {rule:squid:S2444} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NullAssignment.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NullAssignment.html deleted file mode 100644 index aa85a3b4..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/NullAssignment.html +++ /dev/null @@ -1 +0,0 @@ -Assigning a null to a variable (outside of its declaration) is usually bad form. Some times, the assignment is an indication that the programmer doesn't completely understand what is going on in the code. NOTE: This sort of assignment may in rare cases be useful to encourage garbage collection. If that's what you're using it for, by all means, disregard this rule :-) diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OneDeclarationPerLine.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OneDeclarationPerLine.html deleted file mode 100644 index 60f9f6ba..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OneDeclarationPerLine.html +++ /dev/null @@ -1,12 +0,0 @@ -Java allows the use of several variables declaration of the same type on one line. However, it -can lead to quite messy code. This rule looks for several declarations on the same line. Example: -
        -String name; // separate declarations
        -String lastname;
        -
        -String name, lastname; // combined declaration, a violation
        -
        - -

        - This rule is deprecated, use {rule:squid:S00122} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OnlyOneReturn.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OnlyOneReturn.html deleted file mode 100644 index 97a9ab54..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OnlyOneReturn.html +++ /dev/null @@ -1,5 +0,0 @@ -A method should have only one exit point, and that should be the last statement in the method. - -

        - This rule is deprecated, use {rule:squid:S1142} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OptimizableToArrayCall.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OptimizableToArrayCall.html deleted file mode 100644 index 909cca5f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OptimizableToArrayCall.html +++ /dev/null @@ -1,34 +0,0 @@ - -

        - Calls to a collection’s toArray(E[]) method should specify a target array of zero size. This allows the - JVM to - optimize the memory allocation and copying as much as possible. -

        -

        - Previous versions of this rule (pre PMD 6.0.0) suggested the opposite, but current JVM implementations - perform always better, when they have full control over the target array. And allocation an array via - reflection is nowadays as fast as the direct allocation. -

        -

        - See also Arrays of Wisdom of the Ancients -

        -

        - Note: If you don’t need an array of the correct type, then the simple toArray() method without an array - is faster, but - returns only an array of type Object[]. -

        -

        Noncompliant Code Example

        -
        -List<Foo> foos = getFoos();
        -
        -// inefficient, the array needs to be zeroed out by the jvm before it is handed over to the toArray method
        -Foo[] fooArray = foos.toArray(new Foo[foos.size()]);
        -
        -

        Compliant Solution

        -
        -List<Foo> foos = getFoos();
        -
        -// much better; this one allows the jvm to allocate an array of the correct size and effectively skip
        -// the zeroing, since each array element will be overridden anyways
        -Foo[] fooArray = foos.toArray(new Foo[0]);
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OverrideBothEqualsAndHashcode.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OverrideBothEqualsAndHashcode.html deleted file mode 100644 index 851a0377..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/OverrideBothEqualsAndHashcode.html +++ /dev/null @@ -1,30 +0,0 @@ -Override both public boolean Object.equals(Object other), and public int Object.hashCode(), or override neither. Even if you are inheriting a hashCode() from a parent class, consider implementing hashCode and explicitly delegating to your superclass. Example : -
        -// this is bad
        -public class Bar {
        -  public boolean equals(Object o) {
        -      // do some comparison
        -  }
        -}
        -
        -// and so is this
        -public class Baz {
        -  public int hashCode() {
        -      // return some hash value
        -  }
        -}
        -
        -// this is OK
        -public class Foo {
        -  public boolean equals(Object other) {
        -      // do some comparison
        -  }
        -  public int hashCode() {
        -      // return some hash value
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1206} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PackageCase.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PackageCase.html deleted file mode 100644 index f40c6630..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PackageCase.html +++ /dev/null @@ -1,10 +0,0 @@ -Detects when a package definition contains upper case characters. Example : -
        -package com.MyCompany;  // <- should be lower case name
        -public class SomeClass {
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S00120} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PositionLiteralsFirstInCaseInsensitiveComparisons.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PositionLiteralsFirstInCaseInsensitiveComparisons.html deleted file mode 100644 index e19dbb48..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PositionLiteralsFirstInCaseInsensitiveComparisons.html +++ /dev/null @@ -1,13 +0,0 @@ -Position literals first in comparisons, if the second argument is null then NullPointerExceptions -can be avoided, they will just return false. Example: -
        -class Foo {
        -  boolean bar(String x) {
        -    return x.equalsIgnoreCase("2"); // should be "2".equalsIgnoreCase(x)
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1132} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PositionLiteralsFirstInComparisons.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PositionLiteralsFirstInComparisons.html deleted file mode 100644 index aedc1158..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PositionLiteralsFirstInComparisons.html +++ /dev/null @@ -1,5 +0,0 @@ -Position literals first in String comparisons - that way if the String is null you won't get a NullPointerException, it'll just return false. - -

        - This rule is deprecated, use {rule:squid:S1132} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PrematureDeclaration.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PrematureDeclaration.html deleted file mode 100644 index d140e080..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PrematureDeclaration.html +++ /dev/null @@ -1,19 +0,0 @@ -Checks for variables that are defined before they might be used. A reference is deemed to be premature if it is created right before a block of code that doesn't use it that also has the ability to return or throw an exception. Example: -
        -public int getLength(String[] strings) {
        -
        -  int length = 0; // declared prematurely
        -
        -  if (strings == null || strings.length == 0) return 0;
        -
        -  for (String str : strings) {
        -    length += str.length();
        -  }
        -
        -  return length;
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1941} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PreserveStackTrace.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PreserveStackTrace.html deleted file mode 100644 index 104fb2b3..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/PreserveStackTrace.html +++ /dev/null @@ -1,5 +0,0 @@ -Throwing a new exception from a catch block without passing the original exception into the new Exception will cause the true stack trace to be lost, and can make it difficult to debug effectively. - -

        - This rule is deprecated, use {rule:squid:S1166} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ProperCloneImplementation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ProperCloneImplementation.html deleted file mode 100644 index a0447618..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ProperCloneImplementation.html +++ /dev/null @@ -1,12 +0,0 @@ -Object clone() should be implemented with super.clone(). Example : -
        -class Foo{
        -    public Object clone(){
        -        return new Foo(); // This is bad
        -    }
        -}
        -  
        - -

        - This rule is deprecated, use {rule:squid:S1182} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ProperLogger.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ProperLogger.html deleted file mode 100644 index 1c608bec..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ProperLogger.html +++ /dev/null @@ -1,5 +0,0 @@ -Logger should normally be defined private static final and have the correct class. Private final Log log; is also allowed for rare cases when loggers need to be passed around, but the logger needs to be passed into the constructor. - -

        - This rule is deprecated, use {rule:squid:S1312} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/RedundantFieldInitializer.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/RedundantFieldInitializer.html deleted file mode 100644 index f7b25dd4..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/RedundantFieldInitializer.html +++ /dev/null @@ -1,23 +0,0 @@ -Java will initialize fields with known default values so any explicit initialization of those same defaults -is redundant and results in a larger class file (approximately three additional bytecode instructions per field). Example: -
        -public class C {
        -  boolean b = false; // examples of redundant initializers
        -  byte by   = 0;
        -  short s   = 0;
        -  char c    = 0;
        -  int i     = 0;
        -  long l    = 0;
        -
        -  float f   = .0f;   // all possible float literals
        -  doable d  = 0d;    // all possible double literals
        -  Object o  = null;
        -
        -  MyClass mca[] = null;
        -  int i1 = 0, ia1[] = null;
        -
        -  class Nested {
        -    boolean b = false;
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/RemoteInterfaceNamingConvention.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/RemoteInterfaceNamingConvention.html deleted file mode 100644 index a7b6258b..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/RemoteInterfaceNamingConvention.html +++ /dev/null @@ -1 +0,0 @@ -Remote Interface of a Session EJB should NOT be suffixed. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/RemoteSessionInterfaceNamingConvention.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/RemoteSessionInterfaceNamingConvention.html deleted file mode 100644 index dd5ba59a..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/RemoteSessionInterfaceNamingConvention.html +++ /dev/null @@ -1 +0,0 @@ -Remote Home interface of a Session EJB should be suffixed by "Home". diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReplaceEnumerationWithIterator.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReplaceEnumerationWithIterator.html deleted file mode 100644 index b52f1202..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReplaceEnumerationWithIterator.html +++ /dev/null @@ -1,5 +0,0 @@ -Consider replacing this Enumeration with the newer java.util.Iterator - -

        - This rule is deprecated, use {rule:squid:S1150} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReplaceHashtableWithMap.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReplaceHashtableWithMap.html deleted file mode 100644 index 62f47de8..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReplaceHashtableWithMap.html +++ /dev/null @@ -1,5 +0,0 @@ -Consider replacing this Hashtable with the newer java.util.Map - -

        - This rule is deprecated, use {rule:squid:S1149} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReplaceVectorWithList.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReplaceVectorWithList.html deleted file mode 100644 index 7963f674..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReplaceVectorWithList.html +++ /dev/null @@ -1,5 +0,0 @@ -Consider replacing Vector usages with the newer java.util.ArrayList if expensive threadsafe operation is not required. - -

        - This rule is deprecated, use {rule:squid:S1149} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReturnEmptyArrayRatherThanNull.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReturnEmptyArrayRatherThanNull.html deleted file mode 100644 index 1413da86..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReturnEmptyArrayRatherThanNull.html +++ /dev/null @@ -1,23 +0,0 @@ -For any method that returns an array, it's a better behavior to return an empty array rather than a null reference. Example : -
        -public class Example
        -{
        -  // Not a good idea...
        -  public int []badBehavior()
        -  {
        -    // ...
        -    return null;
        -  }
        -
        -  // Good behavior
        -  public String[] bonnePratique()
        -  {
        -    //...
        -    return new String[0];
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1168} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReturnFromFinallyBlock.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReturnFromFinallyBlock.html deleted file mode 100644 index f9886445..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ReturnFromFinallyBlock.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid returning from a finally block - this can discard exceptions. - -

        - This rule is deprecated, use {rule:squid:S1143} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortClassName.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortClassName.html deleted file mode 100644 index 89f69914..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortClassName.html +++ /dev/null @@ -1,9 +0,0 @@ -Classnames with fewer than five characters are not recommended. Example: -
        -public class Foo {
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S00101} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortInstantiation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortInstantiation.html deleted file mode 100644 index 70e086e0..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortInstantiation.html +++ /dev/null @@ -1,7 +0,0 @@ -In JDK 1.5, calling new Short() causes memory allocation. Short.valueOf() is more memory friendly. Example : -
        -public class Foo {
        -private Short i = new Short(0); // change to Short i =
        -Short.valueOf(0);
        -}
        -  
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortMethodName.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortMethodName.html deleted file mode 100644 index ac3c5eaa..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortMethodName.html +++ /dev/null @@ -1,11 +0,0 @@ -Detects when very short method names are used. Example : -
        -public class ShortMethod {
        -  public void a( int i ) { // Violation
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S00100} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortVariable.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortVariable.html deleted file mode 100644 index 665e22cf..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/ShortVariable.html +++ /dev/null @@ -1,5 +0,0 @@ -Detects when a field, local, or parameter has a very short name. - -

        - This rule is deprecated, use {rule:squid:S00117} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SignatureDeclareThrowsException.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SignatureDeclareThrowsException.html deleted file mode 100644 index 85ace23c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SignatureDeclareThrowsException.html +++ /dev/null @@ -1,5 +0,0 @@ -It is unclear which exceptions that can be thrown from the methods. It might be difficult to document and understand the vague interfaces. Use either a class derived from RuntimeException or a checked exception. - -

        - This rule is deprecated, use {rule:squid:S00112} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SignatureDeclareThrowsExceptionWithTypeResolution.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SignatureDeclareThrowsExceptionWithTypeResolution.html deleted file mode 100644 index cee95cb6..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SignatureDeclareThrowsExceptionWithTypeResolution.html +++ /dev/null @@ -1,13 +0,0 @@ -It is unclear which exceptions that can be thrown from the methods. -It might be difficult to document and understand the vague interfaces. -Use either a class derived from RuntimeException or a checked exception. - -JUnit classes are excluded. Example: -
        -public void methodThrowingException() throws Exception {
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S00112} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimpleDateFormatNeedsLocale.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimpleDateFormatNeedsLocale.html deleted file mode 100644 index b24136c8..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimpleDateFormatNeedsLocale.html +++ /dev/null @@ -1 +0,0 @@ -Be sure to specify a Locale when creating a new instance of SimpleDateFormat. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifiedTernary.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifiedTernary.html deleted file mode 100644 index 218f22ec..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifiedTernary.html +++ /dev/null @@ -1,24 +0,0 @@ -

        - Look for ternary operators with the form condition ? literalBoolean : foo or condition ? foo : literalBoolean. -

        - -

        Examples:

        -
        -public class Foo {
        -  public boolean test() {
        -    return condition ? true : something(); // can be as simple as return condition || something();
        -  }
        -
        -  public void test2() {
        -    final boolean value = condition ? false : something(); // can be as simple as value = !condition && something();
        -  }
        -
        -  public boolean test3() {
        -    return condition ? something() : true; // can be as simple as return !condition || something();
        -  }
        -
        -  public void test4() {
        -    final boolean otherValue = condition ? something() : false; // can be as simple as condition && something();
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyBooleanExpressions.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyBooleanExpressions.html deleted file mode 100644 index 68ad2c01..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyBooleanExpressions.html +++ /dev/null @@ -1,14 +0,0 @@ -Avoid unnecessary comparisons in boolean expressions - this complicates simple code. Example : -
        -public class Bar {
        - // can be simplified to
        - // bar = isFoo();
        - private boolean bar = (isFoo() == true);
        -
        - public isFoo() { return false;}
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1125} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyBooleanReturns.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyBooleanReturns.html deleted file mode 100644 index c63eeb3d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyBooleanReturns.html +++ /dev/null @@ -1,20 +0,0 @@ -Avoid unnecessary if..then..else statements when returning a boolean. Example : -
        -public class Foo {
        -  private int bar =2;
        -  public boolean isBarEqualsTo(int x) {
        -    // this bit of code
        -    if (bar == x) {
        -     return true;
        -    } else {
        -     return false;
        -    }
        -    // can be replaced with a simple
        -    // return bar == x;
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1126} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyConditional.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyConditional.html deleted file mode 100644 index a4d2d6fe..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyConditional.html +++ /dev/null @@ -1 +0,0 @@ -No need to check for null before an instanceof; the instanceof keyword returns false when given a null argument. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyStartsWith.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyStartsWith.html deleted file mode 100644 index 3601b6de..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SimplifyStartsWith.html +++ /dev/null @@ -1 +0,0 @@ -Since it passes in a literal of length 1, this call to String.startsWith can be rewritten using String.charAt(0) to save some time. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SingleMethodSingleton.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SingleMethodSingleton.html deleted file mode 100644 index fb07c38a..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SingleMethodSingleton.html +++ /dev/null @@ -1,23 +0,0 @@ -

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

        - -

        Examples:

        -
        -public class Singleton {
        -  private static Singleton singleton = new Singleton( );
        -
        -  private Singleton() { }
        -
        -  public static Singleton getInstance( ) {
        -    return singleton;
        -  }
        -
        -  public static Singleton getInstance(Object obj) {
        -    Singleton singleton = (Singleton) obj;
        -    return singleton; //violation
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SingletonClassReturningNewInstance.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SingletonClassReturningNewInstance.html deleted file mode 100644 index 058f237d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SingletonClassReturningNewInstance.html +++ /dev/null @@ -1,18 +0,0 @@ -

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

        - -

        Examples:

        -
        -class Singleton {
        -  private static Singleton instance = null;
        -
        -  public static Singleton getInstance() {
        -    synchronized(Singleton.class) {
        -      return new Singleton();
        -    }
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SingularField.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SingularField.html deleted file mode 100644 index 800045f4..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SingularField.html +++ /dev/null @@ -1 +0,0 @@ -A field that's only used by one method could perhaps be replaced by a local variable. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StaticEJBFieldShouldBeFinal.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StaticEJBFieldShouldBeFinal.html deleted file mode 100644 index 1cf04b1f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StaticEJBFieldShouldBeFinal.html +++ /dev/null @@ -1 +0,0 @@ -According to the J2EE specification (p.494), an EJB should not have any static fields with write access. However, static read only fields are allowed. This ensures proper behavior especially when instances are distributed by the container on several JREs. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StdCyclomaticComplexity.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StdCyclomaticComplexity.html deleted file mode 100644 index bbb3865b..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StdCyclomaticComplexity.html +++ /dev/null @@ -1,6 +0,0 @@ -Complexity directly affects maintenance costs is determined by the number of decision points in a method plus one for the method entry. The decision points include 'if', 'while', 'for', and 'case labels' calls. Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote high complexity, and 11+ is very high complexity. - -

        - This rule is deprecated, use {rule:squid:MethodCyclomaticComplexity} or {rule:squid:ClassCyclomaticComplexity} - instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StringBufferInstantiationWithChar.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StringBufferInstantiationWithChar.html deleted file mode 100644 index 6d8942b0..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StringBufferInstantiationWithChar.html +++ /dev/null @@ -1,5 +0,0 @@ -StringBuffer sb = new StringBuffer('c'); The char will be converted into int to intialize StringBuffer size. - -

        - This rule is deprecated, use {rule:squid:S1317} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StringInstantiation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StringInstantiation.html deleted file mode 100644 index c6ea3bb6..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StringInstantiation.html +++ /dev/null @@ -1 +0,0 @@ -Avoid instantiating String objects; this is usually unnecessary. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StringToString.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StringToString.html deleted file mode 100644 index 88db0103..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/StringToString.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid calling toString() on String objects; this is unnecessary. - -

        - This rule is deprecated, use {rule:squid:S1858} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousConstantFieldName.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousConstantFieldName.html deleted file mode 100644 index c997c29f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousConstantFieldName.html +++ /dev/null @@ -1,13 +0,0 @@ -A field name is all in uppercase characters, which in Sun's Java naming conventions indicate a constant. However, the field is not final. Example : -
        -public class Foo {
        -  // this is bad, since someone could accidentally
        -  // do PI = 2.71828; which is actualy e
        -  // final double PI = 3.16; is ok
        -  double PI = 3.16;
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S00116} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousEqualsMethodName.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousEqualsMethodName.html deleted file mode 100644 index 1e4144bf..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousEqualsMethodName.html +++ /dev/null @@ -1,15 +0,0 @@ -The method name and parameter number are suspiciously close to equals(Object), which may mean you are intending to override the equals(Object) method. Example : -
        -public class Foo {
        -  public int equals(Object o) {
        -  // oops, this probably was supposed to be boolean equals
        -  }
        -  public boolean equals(String s) {
        -  // oops, this probably was supposed to be equals(Object)
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1201} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousHashcodeMethodName.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousHashcodeMethodName.html deleted file mode 100644 index 44440959..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousHashcodeMethodName.html +++ /dev/null @@ -1,11 +0,0 @@ -The method name and return type are suspiciously close to hashCode(), which may mean you are intending to override the hashCode() method. Example : -
        -public class Foo {
        -  public int hashcode() {
        -  // oops, this probably was supposed to be hashCode
        -  }
        -}
        - -

        - This rule is deprecated, use {rule:squid:S1221} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousOctalEscape.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousOctalEscape.html deleted file mode 100644 index add6e3f1..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SuspiciousOctalEscape.html +++ /dev/null @@ -1 +0,0 @@ -A suspicious octal escape sequence was found inside a String literal. The Java language specification (section 3.10.6) says an octal escape sequence inside a literal String shall consist of a backslash followed by: OctalDigit | OctalDigit OctalDigit | ZeroToThree OctalDigit OctalDigit Any octal escape sequence followed by non-octal digits can be confusing, e.g. "\038" is interpreted as the octal escape sequence "\03" followed by the literal character 8. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SwitchDensity.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SwitchDensity.html deleted file mode 100644 index c15e5dc8..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SwitchDensity.html +++ /dev/null @@ -1,5 +0,0 @@ -A high ratio of statements to labels in a switch statement implies that the switch statement is doing too much work. Consider moving the statements into new methods, or creating subclasses based on the switch variable. - -

        - This rule is deprecated, use {rule:squid:S1151} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SwitchStmtsShouldHaveDefault.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SwitchStmtsShouldHaveDefault.html deleted file mode 100644 index 8f9ef790..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SwitchStmtsShouldHaveDefault.html +++ /dev/null @@ -1,15 +0,0 @@ -Switch statements should have a default label. Example : -
        -public class Foo {
        - public void bar() {
        -  int x = 2;
        -  switch (x) {
        -   case 2: int j = 8;
        -  }
        - }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:SwitchLastCaseIsDefaultCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SystemPrintln.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SystemPrintln.html deleted file mode 100644 index 49a66a44..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/SystemPrintln.html +++ /dev/null @@ -1,5 +0,0 @@ -System.(out|err).print is used, consider using a logger. - -

        - This rule is deprecated, use {rule:squid:S106} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooFewBranchesForASwitchStatement.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooFewBranchesForASwitchStatement.html deleted file mode 100644 index 9ffa953e..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooFewBranchesForASwitchStatement.html +++ /dev/null @@ -1,20 +0,0 @@ -Swith are designed complex branches, and allow branches to share treatement. Using a switch for only a few branches is ill advised, as switches are not as easy to understand as if. In this case, it's most likely is a good idea to use a if statement instead, at least to increase code readability. Example : -
        -// With a minimumNumberCaseForASwitch of 3
        -public class Foo {
        -  public void bar() {
        -    switch (condition) {
        -      case ONE:
        -        instruction;
        -        break;
        -      default:
        -        break; // not enough for a 'switch' stmt,
        -               // a simple 'if' stmt would have been more appropriate
        -    }
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S1301} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooManyFields.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooManyFields.html deleted file mode 100644 index a0c21119..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooManyFields.html +++ /dev/null @@ -1 +0,0 @@ -Classes that have too many fields could be redesigned to have fewer fields, possibly through some nested object grouping of some of the information. For example, a class with city/state/zip fields could instead have one Address field. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooManyMethods.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooManyMethods.html deleted file mode 100644 index 07bc1447..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooManyMethods.html +++ /dev/null @@ -1,5 +0,0 @@ -A class with too many methods is probably a good suspect for refactoring, in order to reduce its complexity and find a way to have more fine grained objects. - -

        - This rule is deprecated, use {rule:squid:S1448} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooManyStaticImports.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooManyStaticImports.html deleted file mode 100644 index d2578446..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/TooManyStaticImports.html +++ /dev/null @@ -1 +0,0 @@ -If you overuse the static import feature, it can make your program unreadable and unmaintainable, polluting its namespace with all the static members you import. Readers of your code (including you, a few months after you wrote it) will not know which class a static member comes from (Sun 1.5 Language Guide). diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UncommentedEmptyConstructor.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UncommentedEmptyConstructor.html deleted file mode 100644 index 077f1044..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UncommentedEmptyConstructor.html +++ /dev/null @@ -1,5 +0,0 @@ -Uncommented Empty Constructor finds instances where a constructor does not contain statements, but there is no comment. By explicitly commenting empty constructors it is easier to distinguish between intentional (commented) and unintentional empty constructors. - -

        - This rule is deprecated, use {rule:squid:S2094} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UncommentedEmptyMethodBody.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UncommentedEmptyMethodBody.html deleted file mode 100644 index 45604da5..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UncommentedEmptyMethodBody.html +++ /dev/null @@ -1,7 +0,0 @@ -

        Uncommented Empty Method finds instances where a method does not contain statements, but there is no comment. By - explicitly commenting empty methods it is easier to distinguish between intentional (commented) and unintentional - empty methods.

        - -

        - This rule is deprecated, use {rule:squid:S1186} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnconditionalIfStatement.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnconditionalIfStatement.html deleted file mode 100644 index 88a5d77f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnconditionalIfStatement.html +++ /dev/null @@ -1,5 +0,0 @@ -Do not use if statements that are always true or always false. - -

        - This rule is deprecated, use {rule:squid:S2583} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryCaseChange.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryCaseChange.html deleted file mode 100644 index 7ee1a0dc..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryCaseChange.html +++ /dev/null @@ -1,5 +0,0 @@ -Using equalsIgnoreCase() is faster than using toUpperCase/toLowerCase().equals() - -

        - This rule is deprecated, use {rule:squid:S1157} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryConstructor.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryConstructor.html deleted file mode 100644 index a1a8e6ff..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryConstructor.html +++ /dev/null @@ -1,5 +0,0 @@ -This rule detects when a constructor is not necessary; i.e., when there's only one constructor, it's public, has an empty body, and takes no arguments. - -

        - This rule is deprecated, use {rule:squid:S1186} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryConversionTemporary.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryConversionTemporary.html deleted file mode 100644 index eabf72a0..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryConversionTemporary.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid unnecessary temporaries when converting primitives to Strings - -

        - This rule is deprecated, use {rule:squid:S1158} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryFinalModifier.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryFinalModifier.html deleted file mode 100644 index 42978dfe..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryFinalModifier.html +++ /dev/null @@ -1 +0,0 @@ -When a class has the final modifier, all the methods are automatically final. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryFullyQualifiedName.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryFullyQualifiedName.html deleted file mode 100644 index 22440406..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryFullyQualifiedName.html +++ /dev/null @@ -1,10 +0,0 @@ -Import statements allow the use of non-fully qualified names. The use of a fully qualified name -which is covered by an import statement is redundant. Consider using the non-fully qualified name. Example: -
        -import java.util.List;
        -
        -public class Foo {
        -   private java.util.List list1; // Unnecessary FQN
        -   private List list2; // More appropriate given import of 'java.util.List'
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryLocalBeforeReturn.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryLocalBeforeReturn.html deleted file mode 100644 index 6a28d00c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryLocalBeforeReturn.html +++ /dev/null @@ -1,5 +0,0 @@ -Avoid unnecessarily creating local variables - -

        - This rule is deprecated, use {rule:squid:S1488} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryParentheses.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryParentheses.html deleted file mode 100644 index f66dd4ca..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryParentheses.html +++ /dev/null @@ -1,12 +0,0 @@ -Sometimes expressions are wrapped in unnecessary parentheses, making them look like a function call. Example : -
        -public class Foo {
        -  boolean bar() {
        -    return (true);
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:UselessParenthesesCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryReturn.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryReturn.html deleted file mode 100644 index 391507b1..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryReturn.html +++ /dev/null @@ -1 +0,0 @@ -Avoid unnecessary return statements diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryWrapperObjectCreation.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryWrapperObjectCreation.html deleted file mode 100644 index 272f5432..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnnecessaryWrapperObjectCreation.html +++ /dev/null @@ -1,5 +0,0 @@ -Parsing method should be called directy instead. - -

        - This rule is deprecated, use {rule:squid:S1158} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnsynchronizedStaticDateFormatter.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnsynchronizedStaticDateFormatter.html deleted file mode 100644 index 026ecf20..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnsynchronizedStaticDateFormatter.html +++ /dev/null @@ -1,5 +0,0 @@ -SimpleDateFormat is not synchronized. Sun recomends separate format instances for each thread. If multiple threads must access a static formatter, the formatter must be synchronized either on method or block level. - -

        - This rule is deprecated, use {rule:squid:S2156} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedFormalParameter.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedFormalParameter.html deleted file mode 100644 index 38635cb2..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedFormalParameter.html +++ /dev/null @@ -1,5 +0,0 @@ -

        Avoid passing parameters to methods or constructors and then not using those parameters.

        - -

        - This rule is deprecated, use {rule:squid:S1172} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedImports.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedImports.html deleted file mode 100644 index 5422468d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedImports.html +++ /dev/null @@ -1,10 +0,0 @@ -Avoid unused import statements. Example : -
        -// this is bad
        -import java.io.File;
        -public class Foo {}
        -  
        - -

        - This rule is deprecated, use {rule:squid:UselessImportCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedImportsWithTypeResolution.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedImportsWithTypeResolution.html deleted file mode 100644 index 2b9193d3..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedImportsWithTypeResolution.html +++ /dev/null @@ -1,10 +0,0 @@ -Avoid unused import statements. This rule will find unused on demand imports, i.e. import com.foo.*. Example: -
        -import java.io.*; // not referenced or required
        -
        -public class Foo {}
        -
        - -

        - This rule is deprecated, use {rule:squid:UselessImportCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedLocalVariable.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedLocalVariable.html deleted file mode 100644 index 5e32529b..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedLocalVariable.html +++ /dev/null @@ -1,5 +0,0 @@ -Detects when a local variable is declared and/or assigned, but not used. - -

        - This rule is deprecated, use {rule:squid:S1481} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedModifier.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedModifier.html deleted file mode 100644 index 11ba3f8c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedModifier.html +++ /dev/null @@ -1 +0,0 @@ -Fields in interfaces are automatically public static final, and methods are public abstract. Classes or interfaces nested in an interface are automatically public and static (all nested interfaces are automatically static). For historical reasons, modifiers which are implied by the context are accepted by the compiler, but are superfluous. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedNullCheckInEquals.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedNullCheckInEquals.html deleted file mode 100644 index adb81810..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedNullCheckInEquals.html +++ /dev/null @@ -1 +0,0 @@ -After checking an object reference for null, you should invoke equals() on that object rather than passing it to another object's equals() method. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedPrivateField.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedPrivateField.html deleted file mode 100644 index 53c55849..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedPrivateField.html +++ /dev/null @@ -1,5 +0,0 @@ -Detects when a private field is declared and/or assigned a value, but not used. - -

        - This rule is deprecated, use {rule:squid:S1068} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedPrivateMethod.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedPrivateMethod.html deleted file mode 100644 index 23304e66..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UnusedPrivateMethod.html +++ /dev/null @@ -1,9 +0,0 @@ -

        - Unused Private Method detects when a private method is declared but is unused. This PMD rule should be switched off - and replaced by its equivalent from Squid that is more effective : it generates less false-positives and detects more - dead code. -

        - -

        - This rule is deprecated, use {rule:squid:UnusedPrivateMethod} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseArrayListInsteadOfVector.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseArrayListInsteadOfVector.html deleted file mode 100644 index c3b7c1a2..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseArrayListInsteadOfVector.html +++ /dev/null @@ -1,5 +0,0 @@ -ArrayList is a much better Collection implementation than Vector. - -

        - This rule is deprecated, use {rule:squid:S1149} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseArraysAsList.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseArraysAsList.html deleted file mode 100644 index 4accd649..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseArraysAsList.html +++ /dev/null @@ -1 +0,0 @@ -The class java.util.Arrays has a asList method that should be use when you want to create a new List from an array of objects. It is faster than executing a loop to cpy all the elements of the array one by one diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseCollectionIsEmpty.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseCollectionIsEmpty.html deleted file mode 100644 index 0f9bea51..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseCollectionIsEmpty.html +++ /dev/null @@ -1,5 +0,0 @@ -The isEmpty() method on java.util.Collection is provided to see if a collection has any elements. Comparing the value of size() to 0 merely duplicates existing behavior. - -

        - This rule is deprecated, use {rule:squid:S1155} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseConcurrentHashMap.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseConcurrentHashMap.html deleted file mode 100644 index a419810b..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseConcurrentHashMap.html +++ /dev/null @@ -1 +0,0 @@ -Since Java5 brought a new implementation of the Map interface, specially designed for concurrent application. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseCorrectExceptionLogging.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseCorrectExceptionLogging.html deleted file mode 100644 index 28f85921..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseCorrectExceptionLogging.html +++ /dev/null @@ -1,5 +0,0 @@ -To make sure the full stacktrace is printed out, use the logging statement with 2 arguments: a String and a Throwable. - -

        - This rule is deprecated, use {rule:squid:S1166} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseEqualsToCompareStrings.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseEqualsToCompareStrings.html deleted file mode 100644 index 0523fdaa..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseEqualsToCompareStrings.html +++ /dev/null @@ -1,5 +0,0 @@ -Using "==" or "!=" to compare strings only works if intern version is used on both sides. - -

        - This rule is deprecated, use {rule:squid:StringEqualityComparisonCheck} or {rule:squid:S1698} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseIndexOfChar.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseIndexOfChar.html deleted file mode 100644 index b524e42f..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseIndexOfChar.html +++ /dev/null @@ -1 +0,0 @@ -Use String.indexOf(char) when checking for the index of a single character; it executes faster. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseLocaleWithCaseConversions.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseLocaleWithCaseConversions.html deleted file mode 100644 index 06fee3f8..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseLocaleWithCaseConversions.html +++ /dev/null @@ -1 +0,0 @@ -When doing a String.toLowerCase()/toUpperCase() call, use a Locale. This avoids problems with certain locales, i.e. Turkish. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseNotifyAllInsteadOfNotify.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseNotifyAllInsteadOfNotify.html deleted file mode 100644 index a343c3a7..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseNotifyAllInsteadOfNotify.html +++ /dev/null @@ -1,5 +0,0 @@ -Thread.notify() awakens a thread monitoring the object. If more than one thread is monitoring, then only one is chosen. The thread chosen is arbitrary; thus it's usually safer to call notifyAll() instead. - -

        - This rule is deprecated, use {rule:squid:S2446} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseObjectForClearerAPI.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseObjectForClearerAPI.html deleted file mode 100644 index 731d7039..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseObjectForClearerAPI.html +++ /dev/null @@ -1,25 +0,0 @@ -When you write a public method, you should be thinking in terms of an API. If your method is public, it means other class -will use it, therefore, you want (or need) to offer a comprehensive and evolutive API. If you pass a lot of information -as a simple series of Strings, you may think of using an Object to represent all those information. You'll get a simplier -API (such as doWork(Workload workload), rather than a tedious series of Strings) and more importantly, if you need at some -point to pass extra data, you'll be able to do so by simply modifying or extending Workload without any modification to -your API. Example: -
        -public class MyClass {
        -  public void connect(String username,
        -    String pssd,
        -    String databaseName,
        -    String databaseAdress)
        -    // Instead of those parameters object
        -    // would ensure a cleaner API and permit
        -    // to add extra data transparently (no code change):
        -    // void connect(UserData data);
        -    {
        -
        -  }
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:S00107} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseProperClassLoader.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseProperClassLoader.html deleted file mode 100644 index acdff781..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseProperClassLoader.html +++ /dev/null @@ -1 +0,0 @@ -In J2EE getClassLoader() might not work as expected. Use Thread.currentThread().getContextClassLoader() instead. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseStringBufferForStringAppends.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseStringBufferForStringAppends.html deleted file mode 100644 index 727d5921..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseStringBufferForStringAppends.html +++ /dev/null @@ -1 +0,0 @@ -Finds usages of += for appending strings. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseStringBufferLength.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseStringBufferLength.html deleted file mode 100644 index cc069ef5..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseStringBufferLength.html +++ /dev/null @@ -1 +0,0 @@ -Use StringBuffer.length() to determine StringBuffer length rather than using StringBuffer.toString().equals() or StringBuffer.toString().length() ==. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseUtilityClass.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseUtilityClass.html deleted file mode 100644 index 28da7ec7..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseUtilityClass.html +++ /dev/null @@ -1,8 +0,0 @@ -For classes that only have static methods, consider making them utility classes. -Note that this doesn't apply to abstract classes, since their subclasses may well include non-static methods. -Also, if you want this class to be a utility class, remember to add a private constructor to prevent instantiation. -(Note, that this use was known before PMD 5.1.0 as UseSingleton). - -

        - This rule is deprecated, use {rule:squid:S1118} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseVarargs.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseVarargs.html deleted file mode 100644 index d2a6367d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UseVarargs.html +++ /dev/null @@ -1,14 +0,0 @@ -Java 5 introduced the varargs parameter declaration for methods and constructors. This syntactic -sugar provides flexibility for users of these methods and constructors, allowing them to avoid -having to deal with the creation of an array. Example: -
        -public class Foo {
        -   public void foo(String s, Object[] args) {
        -      // Do something here...
        -   }
        -
        -   public void bar(String s, Object... args) {
        -      // Ahh, varargs tastes much better...
        -   }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessOperationOnImmutable.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessOperationOnImmutable.html deleted file mode 100644 index cf5d4d1d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessOperationOnImmutable.html +++ /dev/null @@ -1 +0,0 @@ -An operation on an Immutable object (BigDecimal or BigInteger) won't change the object itself. The result of the operation is a new object. Therefore, ignoring the operation result is an error. diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessOverridingMethod.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessOverridingMethod.html deleted file mode 100644 index 573667ec..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessOverridingMethod.html +++ /dev/null @@ -1,5 +0,0 @@ -The overriding method merely calls the same method defined in a superclass - -

        - This rule is deprecated, use {rule:squid:S1185} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessParentheses.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessParentheses.html deleted file mode 100644 index 6a14cbd6..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessParentheses.html +++ /dev/null @@ -1,18 +0,0 @@ -Useless parentheses should be removed. Example: -
        -public class Foo {
        -
        -   private int _bar1;
        -   private Integer _bar2;
        -
        -   public void setBar(int n) {
        -      _bar1 = Integer.valueOf((n)); // here
        -      _bar2 = (n); // and here
        -   }
        -
        -}
        -
        - -

        - This rule is deprecated, use {rule:squid:UselessParenthesesCheck} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessQualifiedThis.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessQualifiedThis.html deleted file mode 100644 index 600d6b40..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessQualifiedThis.html +++ /dev/null @@ -1,30 +0,0 @@ -

        Look for qualified this usages in the same class.

        - -

        Examples:

        - -
        -public class Foo {
        -  final Foo otherFoo = Foo.this;  // use "this" directly
        -
        -  public void doSomething() {
        -    final Foo anotherFoo = Foo.this;  // use "this" directly
        -  }
        -
        -  private ActionListener returnListener() {
        -    return new ActionListener() {
        -      @Override
        -      public void actionPerformed(ActionEvent e) {
        -        doSomethingWithQualifiedThis(Foo.this);  // This is fine
        -      }
        -    };
        -  }
        -
        -  private class Foo3 {
        -    final Foo myFoo = Foo.this;  // This is fine
        -  }
        -
        -  private class Foo2 {
        -    final Foo2 myFoo2 = Foo2.this;  // Use "this" direclty
        -  }
        -}
        -
        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessStringValueOf.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessStringValueOf.html deleted file mode 100644 index fda101b7..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/UselessStringValueOf.html +++ /dev/null @@ -1,5 +0,0 @@ -No need to call String.valueOf to append to a string; just use the valueOf() argument directly. - -

        - This rule is deprecated, use {rule:squid:S1153} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/VariableNamingConventions.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/VariableNamingConventions.html deleted file mode 100644 index ae557f5c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/VariableNamingConventions.html +++ /dev/null @@ -1,5 +0,0 @@ -A variable naming conventions rule - customize this to your liking. Currently, it checks for final variables that should be fully capitalized and non-final variables that should not include underscores. - -

        - This rule is deprecated, use {rule:squid:S00115} and {rule:squid:S00116} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/WhileLoopsMustUseBraces.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/WhileLoopsMustUseBraces.html deleted file mode 100644 index 1bde211d..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/WhileLoopsMustUseBraces.html +++ /dev/null @@ -1,7 +0,0 @@ -

        - Avoid using 'while' statements without using curly braces. -

        - -

        - This rule is deprecated, use {rule:squid:S00121} instead. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/XPathRule.html b/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/XPathRule.html deleted file mode 100644 index 68d85836..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/l10n/pmd/rules/pmd/XPathRule.html +++ /dev/null @@ -1,26 +0,0 @@ -PMD provides a very handy method for creating new rules by writing an XPath query. When the XPath query finds a match, a violation is created. -Let's take a simple example: assume we have a Factory class that must be always declared final. -We'd like to report a violation each time a declaration of Factory is not declared final. Consider the following class: -
        -public class a {
        -  Factory f1;
        -
        -  void myMethod() {
        -    Factory f2;
        -    int a;
        -  }
        -}
        -
        -The following expression does the magic we need: -
        -//VariableDeclarator
        - [../Type/ReferenceType/ClassOrInterfaceType
        -  [@Image = 'Factory'] and ..[@Final='false']]
        -
        -See the XPath rule - tutorial for more information. - -

        - This rule is deprecated, please see the documentation on Extending - Coding Rules. -

        diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-java.xml b/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-java.xml new file mode 100644 index 00000000..199f722c --- /dev/null +++ b/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-java.xml @@ -0,0 +1,9263 @@ + + + + + AbstractClassWithoutAbstractMethod + Abstract class without abstract method + category/java/bestpractices.xml/AbstractClassWithoutAbstractMethod + MAJOR + Title of issues: This abstract class does not have any abstract methods +

        The abstract class does not contain any abstract methods. An abstract class suggests +an incomplete implementation, which is to be completed by subclasses implementing the +abstract methods. If the class is intended to be used as a base class only (not to be instantiated +directly) a protected constructor can be provided to prevent direct instantiation.

        +

        Example

        +

         public abstract class Foo {
        +   void int method1() { ... }
        +   void int method2() { ... }
        +   // consider using abstract methods or removing
        +   // the abstract modifier and adding protected constructors
        + }

        +

        Alternative rule: java:S1694

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative +
        + + AbstractClassWithoutAnyMethod + Abstract class without any method + category/java/design.xml/AbstractClassWithoutAnyMethod + BLOCKER + Title of issues: No abstract method which means that the keyword is most likely used to prevent instantiation. Use a private or protected constructor instead. +

        If an abstract class does not provide any methods, it may be acting as a simple data container +that is not meant to be instantiated. In this case, it is probably better to use a private or +protected constructor in order to prevent instantiation than make the class misleadingly abstract.

        +

        Example

        +

         public abstract class Example {
        +     String field;
        +     int otherField;
        + }

        +

        Alternative rule: java:S1694

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + AccessorClassGeneration + Accessor class generation + category/java/bestpractices.xml/AccessorClassGeneration + MAJOR + Title of issues: Avoid instantiation through private constructors from outside of the constructor's class. +

        Instantiation by way of private constructors from outside the constructor's class often causes the +generation of an accessor. A factory method, or non-privatization of the constructor can eliminate this +situation. The generated class file is actually an interface. It gives the accessing class the ability +to invoke a new hidden package scope constructor that takes the interface as a supplementary parameter. +This turns a private constructor effectively into one with package scope, and is challenging to discern.

        +

        Note: This rule is only executed for Java 10 or lower. +Since Java 11, JEP 181: Nest-Based Access Control has been implemented. This +means that in Java 11 and above accessor classes are not generated anymore.

        +

        Example

        +

         public class Outer {
        +  void method(){
        +   Inner ic = new Inner();//Causes generation of accessor class
        +  }
        +  public class Inner {
        +   private Inner(){}
        +  }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + AccessorMethodGeneration + Accessor method generation + category/java/bestpractices.xml/AccessorMethodGeneration + MAJOR + Title of issues: Consider giving this member package visibility to access it from {0} without a synthetic accessor method +

        When accessing private fields / methods from another class, the Java compiler will generate accessor methods +with package-private visibility. This adds overhead, and to the dex method count on Android. This situation can +be avoided by changing the visibility of the field / method from private to package-private.

        +

        Note: This rule is only executed for Java 10 or lower. +Since Java 11, JEP 181: Nest-Based Access Control has been implemented. This +means that in Java 11 and above accessor classes are not generated anymore.

        +

        Example

        +

         public class OuterClass {
        +     private int counter;
        +     /* package */ int id;
        + 
        +     public class InnerClass {
        +         InnerClass() {
        +             OuterClass.this.counter++; // wrong accessor method will be generated
        +         }
        + 
        +         public int getOuterClassId() {
        +             return OuterClass.this.id; // id is package-private, no accessor method needed
        +         }
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + violationSuppressRegex + + + STRING + +
        + + AddEmptyString + Add empty string + category/java/performance.xml/AddEmptyString + MAJOR + Title of issues: Do not add empty strings +

        The conversion of literals to strings by concatenating them with empty strings is inefficient. +It is much better to use one of the type-specific toString() methods instead or String.valueOf().

        +

        Example

        +

         String s = "" + 123;                // inefficient
        + String t = Integer.toString(456);   // preferred approach

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + AppendCharacterWithChar + Append character with char + category/java/performance.xml/AppendCharacterWithChar + MAJOR + Title of issues: Avoid appending characters as strings in StringBuffer.append. +

        Avoid concatenating characters as strings in StringBuffer/StringBuilder.append methods.

        +

        Example

        +

         StringBuffer sb = new StringBuffer();
        + sb.append("a");     // avoid this
        + 
        + StringBuffer sb = new StringBuffer();
        + sb.append('a');     // use this instead

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + ArrayIsStoredDirectly + Array is stored directly + category/java/bestpractices.xml/ArrayIsStoredDirectly + MAJOR + Title of issues: The user-supplied array '{0}' is stored directly. +

        Constructors and methods receiving arrays should clone objects and store the copy. +This prevents future changes from the user from affecting the original array.

        +

        Example

        +

         public class Foo {
        +     private String [] x;
        +         public void foo (String [] param) {
        +         // Don't do this, make a copy of the array at least
        +         this.x=param;
        +     }
        + }

        +

        Alternative rule: java:S2384

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative + + allowPrivate + + true + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + AssignmentInOperand + Assignment in operand + category/java/errorprone.xml/AssignmentInOperand + MAJOR + Title of issues: Avoid assignment to {0} in operand +

        Avoid assignments in operands; this can make code more complicated and harder to read.

        +

        Example

        +

         public void bar() {
        +     int x = 2;
        +     if ((x = getX()) == 3) {
        +       System.out.println("3!");
        +     }
        + }

        +

        Alternative rule: java:S1121

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + allowIf + + false + BOOLEAN + + + allowFor + + false + BOOLEAN + + + allowWhile + + false + BOOLEAN + + + allowIncrementDecrement + + false + BOOLEAN + + + allowDoWhile + + false + BOOLEAN + + + allowSwitch + + false + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + AssignmentToNonFinalStatic + Assignment to non final static + category/java/errorprone.xml/AssignmentToNonFinalStatic + MAJOR + Title of issues: Possible unsafe assignment to non-final static field '{0}' in a constructor. +

        Identifies a possible unsafe usage of a static field.

        +

        Example

        +

         public class StaticField {
        +    static int x;
        +    public FinalFields(int y) {
        +     x = y; // unsafe
        +    }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone + + violationSuppressRegex + + + STRING + +
        + + AtLeastOneConstructor + At least one constructor + category/java/codestyle.xml/AtLeastOneConstructor + MINOR + Title of issues: Each class should declare at least one constructor +

        Each non-static class should declare at least one constructor. +Classes with solely static members are ignored, refer to UseUtilityClassRule to detect those.

        +

        Example

        +

         public class Foo {
        +    // missing constructor
        +   public void doSomething() { ... }
        +   public void doOtherThing { ... }
        + }

        +

        Alternative rules: java:S1118, java:S1258

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + ignoredAnnotations + + lombok.Data,lombok.Value,lombok.Builder,lombok.NoArgsConstructor,lombok.RequiredArgsConstructor,lombok.AllArgsConstructor + STRING + +
        + + AvoidAccessibilityAlteration + Avoid accessibility alteration + category/java/errorprone.xml/AvoidAccessibilityAlteration + MAJOR + Title of issues: You should not modify visibility of constructors, methods or fields using setAccessible() +

        Methods such as getDeclaredConstructors(), getDeclaredMethods(), and getDeclaredFields() also +return private constructors, methods and fields. These can be made accessible by calling setAccessible(true). +This gives access to normally protected data which violates the principle of encapsulation.

        +

        This rule detects calls to setAccessible and finds possible accessibility alterations. +If the call to setAccessible is wrapped within a PrivilegedAction, then the access alteration +is assumed to be deliberate and is not reported.

        +

        Note that with Java 17 the Security Manager, which is used for PrivilegedAction execution, +is deprecated: JEP 411: Deprecate the Security Manager for Removal. +For future-proof code, deliberate access alteration should be suppressed using the usual +suppression methods (e.g. by using @SuppressWarnings annotation).

        +

        Example

        +

         import java.lang.reflect.Constructor;
        + import java.lang.reflect.Field;
        + import java.lang.reflect.Method;
        + import java.security.AccessController;
        + import java.security.PrivilegedAction;
        + 
        + public class Violation {
        +     private void invalidSetAccessCalls() throws NoSuchMethodException, SecurityException {
        +         Constructor<?> constructor = this.getClass().getDeclaredConstructor(String.class);
        +         // call to forbidden setAccessible
        +         constructor.setAccessible(true);
        + 
        +         Method privateMethod = this.getClass().getDeclaredMethod("aPrivateMethod");
        +         // call to forbidden setAccessible
        +         privateMethod.setAccessible(true);
        + 
        +         // deliberate accessibility alteration
        +         String privateField = AccessController.doPrivileged(new PrivilegedAction<String>() {
        +             @Override
        +             public String run() {
        +                 try {
        +                     Field field = Violation.class.getDeclaredField("aPrivateField");
        +                     field.setAccessible(true);
        +                     return (String) field.get(null);
        +                 } catch (ReflectiveOperationException | SecurityException e) {
        +                     throw new RuntimeException(e);
        +                 }
        +             }
        +         });
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + AvoidArrayLoops + Avoid array loops + category/java/performance.xml/AvoidArrayLoops + MAJOR + Title of issues: Arrays.copyOf or System.arraycopy are more efficient +

        Instead of manually copying data between two arrays, use the more efficient Arrays.copyOf +or System.arraycopy method instead.

        +

        To copy only part of the array, use Arrays.copyOfRange or System.arraycopy.

        +

        If you want to copy/move elements inside the _same_ array (e.g. shift the elements), use System.arraycopy.

        +

        Examples

        +

        Example 1

        +

         class Scratch {
        +     void copy_a_to_b() {
        +         int[] a = new int[10];
        +         int[] b = new int[10];
        +         for (int i = 0; i < a.length; i++) {
        +             b[i] = a[i];
        +         }
        +         // equivalent
        +         b = Arrays.copyOf(a, a.length);
        +         // equivalent
        +         System.arraycopy(a, 0, b, 0, a.length);
        + 
        +         int[] c = new int[10];
        +         // this will not trigger the rule
        +         for (int i = 0; i < c.length; i++) {
        +             b[i] = a[c[i]];
        +         }
        +     }
        + }

        +

        Example 2

        +

         class Scratch {
        +     void shift_left(int[] a) {
        +         for (int i = 0; i < a.length - 1; i++) {
        +             a[i] = a[i + 1];
        +         }
        +         // equivalent
        +         System.arraycopy(a, 1, a, 0, a.length - 1);
        +     }
        +     void shift_right(int[] a) {
        +         for (int i = a.length - 1; i > 0; i--) {
        +             a[i] = a[i - 1];
        +         }
        +         // equivalent
        +         System.arraycopy(a, 0, a, 1, a.length - 1);
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + AvoidAssertAsIdentifier + Avoid assert as identifier + category/java/errorprone.xml/AvoidAssertAsIdentifier + CRITICAL + Title of issues: Avoid using assert as an identifier; it became a reserved word in JDK 1.4 +

        Use of the term assert will conflict with newer versions of Java since it is a reserved word.

        +

        Since Java 1.4, the token assert became a reserved word and using it as an identifier will +result in a compilation failure for Java 1.4 and later. This rule is therefore only useful +for old Java code before Java 1.4. It can be used to identify problematic code prior to a Java update.

        +

        Example

        +

         public class A {
        +     public class Foo {
        +         String assert = "foo";
        +     }
        + }

        +

        Alternative rule: java:S1190

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + AvoidBranchingStatementAsLastInLoop + Avoid branching statement as last in loop + category/java/errorprone.xml/AvoidBranchingStatementAsLastInLoop + CRITICAL + Title of issues: Avoid using a branching statement as the last in a loop. +

        Using a branching statement as the last part of a loop may be a bug, and/or is confusing. +Ensure that the usage is not a bug, or consider using another approach.

        +

        Example

        +

         // unusual use of branching statement in a loop
        + for (int i = 0; i < 10; i++) {
        +     if (i*i <= 25) {
        +         continue;
        +     }
        +     break;
        + }
        + 
        + // this makes more sense...
        + for (int i = 0; i < 10; i++) {
        +     if (i*i > 25) {
        +         break;
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone + + checkBreakLoopTypes + + for,do,while + STRING + + + checkContinueLoopTypes + + for,do,while + STRING + + + checkReturnLoopTypes + + for,do,while + STRING + +
        + + AvoidCalendarDateCreation + Avoid calendar date creation + category/java/performance.xml/AvoidCalendarDateCreation + MAJOR + Title of issues: A Calendar is used to get the current time, this is expensive. +

        Problem: java.util.Calendar is a heavyweight object and expensive to create. It should only be used, if +calendar calculations are needed.

        +

        Solution: Use new Date(), Java 8+ java.time.LocalDateTime.now() or ZonedDateTime.now().

        +

        Example

        +

         import java.time.LocalDateTime;
        + import java.util.Calendar;
        + import java.util.Date;
        + 
        + public class DateStuff {
        +     private Date bad1() {
        +         return Calendar.getInstance().getTime(); // now
        +     }
        +     private Date good1a() {
        +         return new Date(); // now
        +     }
        +     private LocalDateTime good1b() {
        +         return LocalDateTime.now();
        +     }
        +     private long bad2() {
        +         return Calendar.getInstance().getTimeInMillis();
        +     }
        +     private long good2() {
        +         return System.currentTimeMillis();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + AvoidCallingFinalize + Avoid calling finalize + category/java/errorprone.xml/AvoidCallingFinalize + MAJOR + Title of issues: Avoid calling finalize() explicitly +

        The method Object.finalize() is called by the garbage collector on an object when garbage collection determines +that there are no more references to the object. It should not be invoked by application logic.

        +

        Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

        +

        Example

        +

         void foo() {
        +     Bar b = new Bar();
        +     b.finalize();
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + AvoidCatchingGenericException + Avoid catching generic exception + category/java/design.xml/AvoidCatchingGenericException + MAJOR + Title of issues: Avoid catching generic exceptions such as NullPointerException, RuntimeException, Exception in try-catch block +

        Avoid catching generic exceptions such as NullPointerException, RuntimeException, Exception in try-catch block.

        +

        Example

        +

         package com.igate.primitive;
        + 
        + public class PrimitiveType {
        + 
        +     public void downCastPrimitiveType() {
        +         try {
        +             System.out.println(" i [" + i + "]");
        +         } catch(Exception e) {
        +             e.printStackTrace();
        +         } catch(RuntimeException e) {
        +             e.printStackTrace();
        +         } catch(NullPointerException e) {
        +             e.printStackTrace();
        +         }
        +     }
        + }

        +

        Alternative rule: java:S2221

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + AvoidCatchingNPE + Avoid catching NPE + category/java/errorprone.xml/AvoidCatchingNPE + MAJOR + Title of issues: Avoid catching NullPointerException; consider removing the cause of the NPE. +

        Code should never throw NullPointerExceptions under normal circumstances. A catch block may hide the +original error, causing other, more subtle problems later on.

        +

        Example

        +

         public class Foo {
        +     void bar() {
        +         try {
        +             // do something
        +         } catch (NullPointerException npe) {
        +         }
        +     }
        + }

        +

        Alternative rule: java:S1696

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + AvoidCatchingThrowable + Avoid catching Throwable + category/java/errorprone.xml/AvoidCatchingThrowable + MAJOR + Title of issues: A catch statement should never catch throwable since it includes errors. +

        Catching Throwable errors is not recommended since its scope is very broad. It includes runtime issues such as +OutOfMemoryError that should be exposed and managed separately.

        +

        Example

        +

         public void bar() {
        +     try {
        +         // do something
        +     } catch (Throwable th) {  // should not catch Throwable
        +         th.printStackTrace();
        +     }
        + }

        +

        Alternative rule: java:S1181

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + AvoidDecimalLiteralsInBigDecimalConstructor + Avoid decimal literals in BigDecimal constructor + category/java/errorprone.xml/AvoidDecimalLiteralsInBigDecimalConstructor + MAJOR + Title of issues: Avoid creating BigDecimal with a decimal (float/double) literal. Use a String literal +

        One might assume that the result of "new BigDecimal(0.1)" is exactly equal to 0.1, but it is actually +equal to .1000000000000000055511151231257827021181583404541015625. +This is because 0.1 cannot be represented exactly as a double (or as a binary fraction of any finite +length). Thus, the long value that is being passed in to the constructor is not exactly equal to 0.1, +appearances notwithstanding.

        +

        The (String) constructor, on the other hand, is perfectly predictable: 'new BigDecimal("0.1")' is +exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the +(String) constructor be used in preference to this one.

        +

        Example

        +

         BigDecimal bd = new BigDecimal(1.123);       // loss of precision, this would trigger the rule
        + 
        + BigDecimal bd = new BigDecimal("1.123");     // preferred approach
        + 
        + BigDecimal bd = new BigDecimal(12);          // preferred approach, ok for integer values

        +

        Alternative rule: java:S2111

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + AvoidDeeplyNestedIfStmts + Avoid deeply nested if stmts + category/java/design.xml/AvoidDeeplyNestedIfStmts + MAJOR + Title of issues: Deeply nested if..then statements are hard to read +

        Avoid creating deeply nested if-then statements since they are harder to read and error-prone to maintain.

        +

        Example

        +

         public class Foo {
        +   public void bar(int x, int y, int z) {
        +     if (x>y) {
        +       if (y>z) {
        +         if (z==x) {
        +          // !! too deep
        +         }
        +       }
        +     }
        +   }
        + }

        +

        Alternative rule: java:S134

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + problemDepth + + 3 + INTEGER + +
        + + AvoidDollarSigns + Avoid dollar signs + category/java/codestyle.xml/AvoidDollarSigns + MINOR + Title of issues: Avoid using dollar signs in variable/method/class/interface names +

        Avoid using dollar signs in variable/method/class/interface names.

        +

        Example

        +

         public class Fo$o {  // not a recommended name
        + }

        +

        Alternative rules: java:S114, java:S115, java:S116, java:S117

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative +
        + + AvoidDuplicateLiterals + Avoid duplicate literals + category/java/errorprone.xml/AvoidDuplicateLiterals + MAJOR + Title of issues: The String literal {0} appears {1} times in this file; the first occurrence is on line {2} +

        Code containing duplicate String literals can usually be improved by declaring the String as a constant field.

        +

        Example

        +

         private void bar() {
        +      buz("Howdy");
        +      buz("Howdy");
        +      buz("Howdy");
        +      buz("Howdy");
        + }
        + private void buz(String x) {}

        +

        Alternative rule: java:S1192

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + maxDuplicateLiterals + + 4 + INTEGER + + + minimumLength + + 3 + INTEGER + + + skipAnnotations + + false + BOOLEAN + + + exceptionList + + + STRING + + + violationSuppressRegex + + + STRING + +
        + + AvoidEnumAsIdentifier + Avoid enum as identifier + category/java/errorprone.xml/AvoidEnumAsIdentifier + CRITICAL + Title of issues: Avoid using enum as an identifier; it's a reserved word in JDK 1.5 +

        Use of the term enum will conflict with newer versions of Java since it is a reserved word.

        +

        Since Java 1.5, the token enum became a reserved word and using it as an identifier will +result in a compilation failure for Java 1.5 and later. This rule is therefore only useful +for old Java code before Java 1.5. It can be used to identify problematic code prior to a Java update.

        +

        Example

        +

         public class A {
        +     public class Foo {
        +         String enum = "foo";
        +     }
        + }

        +

        Alternative rule: java:S1190

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + AvoidFieldNameMatchingMethodName + Avoid field name matching method name + category/java/errorprone.xml/AvoidFieldNameMatchingMethodName + MAJOR + Title of issues: Field {0} has the same name as a method +

        It can be confusing to have a field name with the same name as a method. While this is permitted, +having information (field) and actions (method) is not clear naming. Developers versed in +Smalltalk often prefer this approach as the methods denote accessor methods.

        +

        Example

        +

         public class Foo {
        +     Object bar;
        +     // bar is data or an action or both?
        +     void bar() {
        +     }
        + }

        +

        Alternative rule: java:S1845

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + AvoidFieldNameMatchingTypeName + Avoid field name matching type name + category/java/errorprone.xml/AvoidFieldNameMatchingTypeName + MAJOR + Title of issues: 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.

        +

        Example

        +

         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
        + }

        +

        Alternative rule: java:S1700

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + AvoidFileStream + Avoid file stream + category/java/performance.xml/AvoidFileStream + BLOCKER + Title of issues: Avoid instantiating FileInputStream, FileOutputStream, FileReader, or FileWriter +

        The FileInputStream and FileOutputStream classes contains a finalizer method which will cause garbage +collection pauses. +See JDK-8080225 for details.

        +

        The FileReader and FileWriter constructors instantiate FileInputStream and FileOutputStream, +again causing garbage collection issues while finalizer methods are called.

        +
        • Use Files.newInputStream(Paths.get(fileName)) instead of new FileInputStream(fileName).
        • Use Files.newOutputStream(Paths.get(fileName)) instead of new FileOutputStream(fileName).
        • Use Files.newBufferedReader(Paths.get(fileName)) instead of new FileReader(fileName).
        • Use Files.newBufferedWriter(Paths.get(fileName)) instead of new FileWriter(fileName).
        +

        Please note, that the java.nio API does not throw a FileNotFoundException anymore, instead +it throws a NoSuchFileException. If your code dealt explicitly with a FileNotFoundException, +then this needs to be adjusted. Both exceptions are subclasses of IOException, so catching +that one covers both.

        +

        Example

        +

         // these instantiations cause garbage collection pauses, even if properly closed
        + 
        +     FileInputStream fis = new FileInputStream(fileName);
        +     FileOutputStream fos = new FileOutputStream(fileName);
        +     FileReader fr = new FileReader(fileName);
        +     FileWriter fw = new FileWriter(fileName);
        + 
        +     // the following instantiations help prevent Garbage Collection pauses, no finalization
        + 
        +     try(InputStream is = Files.newInputStream(Paths.get(fileName))) {
        +     }
        +     try(OutputStream os = Files.newOutputStream(Paths.get(fileName))) {
        +     }
        +     try(BufferedReader br = Files.newBufferedReader(Paths.get(fileName), StandardCharsets.UTF_8)) {
        +     }
        +     try(BufferedWriter wr = Files.newBufferedWriter(Paths.get(fileName), StandardCharsets.UTF_8)) {
        +     }

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + AvoidInstanceofChecksInCatchClause + Avoid instanceof checks in catch clause + category/java/errorprone.xml/AvoidInstanceofChecksInCatchClause + MAJOR + Title of issues: An instanceof check is being performed on the caught exception. Create a separate catch clause for {0}. +

        Each caught exception type should be handled in its own catch clause.

        +

        Example

        +

         try { // Avoid this
        +     // do something
        + } catch (Exception ee) {
        +     if (ee instanceof IOException) {
        +         cleanup();
        +     }
        + }
        + 
        + try {  // Prefer this:
        +     // do something
        + } catch (IOException ee) {
        +     cleanup();
        + }

        +

        Alternative rule: java:S1193

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + AvoidInstantiatingObjectsInLoops + Avoid instantiating objects in loops + category/java/performance.xml/AvoidInstantiatingObjectsInLoops + MAJOR + Title of issues: Avoid instantiating new objects inside loops +

        New objects created within loops should be checked to see if they can created outside them and reused.

        +

        Example

        +

         public class Something {
        +     public static void main( String as[] ) {
        +         for (int i = 0; i < 10; i++) {
        +             Foo f = new Foo(); // Avoid this whenever you can it's really expensive
        +         }
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + AvoidLiteralsInIfCondition + Avoid literals in if condition + category/java/errorprone.xml/AvoidLiteralsInIfCondition + MAJOR + Title of issues: Avoid using literals such as {0} in if statements +

        Avoid using hard-coded literals in conditional statements. By declaring them as static variables +or private members with descriptive names maintainability is enhanced. By default, the literals "-1" and "0" are ignored. +More exceptions can be defined with the property "ignoreMagicNumbers".

        +

        The rule doesn't consider deeper expressions by default, but this can be enabled via the property ignoreExpressions. +With this property set to false, if-conditions like i == 1 + 5 are reported as well. Note that in that case, +the property ignoreMagicNumbers is not taken into account, if there are multiple literals involved in such an expression.

        +

        Example

        +

         private static final int MAX_NUMBER_OF_REQUESTS = 10;
        + 
        + public void checkRequests() {
        + 
        +     if (i == 10) {                        // magic number, buried in a method
        +       doSomething();
        +     }
        + 
        +     if (i == MAX_NUMBER_OF_REQUESTS) {    // preferred approach
        +       doSomething();
        +     }
        + 
        +     if (aString.indexOf('.') != -1) {}     // magic number -1, by default ignored
        +     if (aString.indexOf('.') >= 0) { }     // alternative approach
        + 
        +     if (aDouble > 0.0) {}                  // magic number 0.0
        +     if (aDouble >= Double.MIN_VALUE) {}    // preferred approach
        + 
        +     // with rule property "ignoreExpressions" set to "false"
        +     if (i == pos + 5) {}  // violation: magic number 5 within an (additive) expression
        +     if (i == pos + SUFFIX_LENGTH) {} // preferred approach
        +     if (i == 5 && "none".equals(aString)) {} // 2 violations: magic number 5 and literal "none"
        + }

        +

        Alternative rule: java:S109

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + ignoreMagicNumbers + + -1,0 + STRING + + + ignoreExpressions + + true + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + AvoidLosingExceptionInformation + Avoid losing exception information + category/java/errorprone.xml/AvoidLosingExceptionInformation + CRITICAL + Title of issues: Avoid statements in a catch block that invoke accessors on the exception without using the information +

        Statements in a catch block that invoke accessors on the exception without using the information +only add to code size. Either remove the invocation, or use the return result.

        +

        Deprecated: This rule is deprecated since PMD 7.17.0 and will be removed with PMD 8.0.0. +This rule has been replaced by {% rule UselessPureMethodCall %}.

        +

        Example

        +

         public void bar() {
        +     try {
        +         // do something
        +     } catch (SomeException se) {
        +         se.getMessage();
        +     }
        + }

        +

        Alternative rule: java:S1166

        +

        Full documentation

        ]]>
        + DEPRECATED + pmd + errorprone + has-sonar-alternative +
        + + AvoidMessageDigestField + Avoid message digest field + category/java/bestpractices.xml/AvoidMessageDigestField + MAJOR + Title of issues: You shouldn't declare field of MessageDigest type, because unsynchronized access could cause problems +

        Declaring a MessageDigest instance as a field make this instance directly available to multiple threads. + Such sharing of MessageDigest instances should be avoided if possible since it leads to wrong results + if the access is not synchronized correctly. + Just create a new instance and use it locally, where you need it. + Creating a new instance is easier than synchronizing access to a shared instance.

        +

        Example

        +

         import java.security.MessageDigest;
        + public class AvoidMessageDigestFieldExample {
        +     private final MessageDigest sharedMd;
        +     public AvoidMessageDigestFieldExample() throws Exception {
        +         sharedMd = MessageDigest.getInstance("SHA-256");
        +     }
        +     public byte[] calculateHashShared(byte[] data) {
        +         // sharing a MessageDigest like this without synchronizing access
        +         // might lead to wrong results
        +         sharedMd.reset();
        +         sharedMd.update(data);
        +         return sharedMd.digest();
        +     }
        + 
        +     // better
        +     public byte[] calculateHash(byte[] data) throws Exception {
        +         MessageDigest md = MessageDigest.getInstance("SHA-256");
        +         md.update(data);
        +         return md.digest();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + AvoidMultipleUnaryOperators + Avoid multiple unary operators + category/java/errorprone.xml/AvoidMultipleUnaryOperators + CRITICAL + Title of issues: Using multiple unary operators may be a bug, and/or is confusing. +

        The use of multiple unary operators may be problematic, and/or confusing. +Ensure that the intended usage is not a bug, or consider simplifying the expression.

        +

        Example

        +

         // These are typo bugs, or at best needlessly complex and confusing:
        + int i = - -1;
        + int j = + - +1;
        + int z = ~~2;
        + boolean b = !!true;
        + boolean c = !!!true;
        + 
        + // These are better:
        + int i = 1;
        + int j = -1;
        + int z = 2;
        + boolean b = true;
        + boolean c = false;
        + 
        + // And these just make your brain hurt:
        + int i = ~-2;
        + int j = -~7;

        +

        Alternative rule: java:S881

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + AvoidPrintStackTrace + Avoid print stack trace + category/java/bestpractices.xml/AvoidPrintStackTrace + MAJOR + Title of issues: Avoid printStackTrace(); use a logger call instead. +

        Avoid printStackTrace(); use a logger call instead.

        +

        Example

        +

         class Foo {
        +     void bar() {
        +         try {
        +             // do something
        +         } catch (Exception e) {
        +             e.printStackTrace();
        +         }
        +     }
        + }

        +

        Alternative rule: java:S1148

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative +
        + + AvoidProtectedFieldInFinalClass + Avoid protected field in final class + category/java/codestyle.xml/AvoidProtectedFieldInFinalClass + MINOR + Title of issues: Avoid protected fields in a final class. Change to private or package access. +

        Do not use protected fields in final classes since they cannot be subclassed. +Clarify your intent by using private or package access modifiers instead.

        +

        Example

        +

         public final class Bar {
        +   private int x;
        +   protected int y;  // bar cannot be subclassed, so is y really private or package visible?
        +   Bar() {}
        + }

        +

        Alternative rule: java:S2156

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative +
        + + AvoidProtectedMethodInFinalClassNotExtending + Avoid protected method in final class not extending + category/java/codestyle.xml/AvoidProtectedMethodInFinalClassNotExtending + MINOR + Title of issues: Avoid protected methods in a final class that doesn't extend anything other than Object. Change to private or package access. +

        Do not use protected methods in most final classes since they cannot be subclassed. This should +only be allowed in final classes that extend other classes with protected methods (whose +visibility cannot be reduced). Clarify your intent by using private or package access modifiers instead.

        +

        Example

        +

         public final class Foo {
        +   private int bar() {}
        +   protected int baz() {} // Foo cannot be subclassed, and doesn't extend anything, so is baz() really private or package visible?
        + }

        +

        Alternative rule: java:S2156

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative +
        + + AvoidReassigningCatchVariables + Avoid reassigning catch variables + category/java/bestpractices.xml/AvoidReassigningCatchVariables + MAJOR + Title of issues: Avoid reassigning caught exception '{0}' +

        Reassigning exception variables caught in a catch statement should be avoided because of:

        +

        1) If it is needed, multi catch can be easily added and code will still compile.

        +

        2) Following the principle of least surprise we want to make sure that a variable caught in a catch statement +is always the one thrown in a try block.

        +

        Example

        +

         public class Foo {
        +     public void foo() {
        +         try {
        +             // do something
        +         } catch (Exception e) {
        +             e = new NullPointerException(); // not recommended
        +         }
        + 
        +         try {
        +             // do something
        +         } catch (MyException | ServerException e) {
        +             e = new RuntimeException(); // won't compile
        +         }
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + violationSuppressRegex + + + STRING + +
        + + AvoidReassigningLoopVariables + Avoid reassigning loop variables + category/java/bestpractices.xml/AvoidReassigningLoopVariables + MAJOR + Title of issues: Avoid reassigning the loop control variable '{0}' +

        Reassigning loop variables can lead to hard-to-find bugs. Prevent or limit how these variables can be changed.

        +

        In foreach-loops, configured by the foreachReassign property:

        +
        • deny: Report any reassignment of the loop variable in the loop body. _This is the default._
        • allow: Don't check the loop variable.
        • firstOnly: Report any reassignments of the loop variable, except as the first statement in the loop body. _This is useful if some kind of normalization or clean-up of the value before using is permitted, but any other change of the variable is not._
        +

        In for-loops, configured by the forReassign property:

        +
        • deny: Report any reassignment of the control variable in the loop body. _This is the default._
        • allow: Don't check the control variable.
        • skip: Report any reassignments of the control variable, except conditional increments/decrements (++, --, +=, -=). _This prevents accidental reassignments or unconditional increments of the control variable._
        +

        Example

        +

         public class Foo {
        +   private void foo() {
        +     for (String s : listOfStrings()) {
        +       s = s.trim(); // OK, when foreachReassign is "firstOnly" or "allow"
        +       doSomethingWith(s);
        + 
        +       s = s.toUpper(); // OK, when foreachReassign is "allow"
        +       doSomethingElseWith(s);
        +     }
        + 
        +     for (int i=0; i < 10; i++) {
        +       if (check(i)) {
        +         i++; // OK, when forReassign is "skip" or "allow"
        +       }
        + 
        +       i = 5;  // OK, when forReassign is "allow"
        + 
        +       doSomethingWith(i);
        +     }
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + foreachReassign + + deny + SINGLE_SELECT_LIST,values="deny,firstOnly,allow" + + + forReassign + + deny + SINGLE_SELECT_LIST,values="deny,skip,allow" + + + violationSuppressRegex + + + STRING + +
        + + AvoidReassigningParameters + Avoid reassigning parameters + category/java/bestpractices.xml/AvoidReassigningParameters + CRITICAL + Title of issues: Avoid reassigning parameters such as '{0}' +

        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.

        +

        Example

        +

         public class Hello {
        +   private void greet(String name) {
        +     name = name.trim();
        +     System.out.println("Hello " + name);
        + 
        +     // preferred
        +     String trimmedName = name.trim();
        +     System.out.println("Hello " + trimmedName);
        +   }
        + }

        +

        Alternative rule: java:S1226

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + AvoidRethrowingException + Avoid rethrowing exception + category/java/design.xml/AvoidRethrowingException + MAJOR + Title of issues: A catch statement that catches an exception only to rethrow it should be avoided. +

        Catch blocks that merely rethrow a caught exception only add to code size and runtime complexity.

        +

        Example

        +

         public void bar() {
        +     try {
        +         // do something
        +     }  catch (SomeException se) {
        +        throw se;
        +     }
        + }

        +

        Alternative rule: java:S1166

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + AvoidStringBufferField + Avoid StringBuffer field + category/java/bestpractices.xml/AvoidStringBufferField + MAJOR + Title of issues: StringBuffers can grow quite a lot, and so may become a source of memory leak (if the owning class has a long life time). +

        StringBuffers/StringBuilders can grow considerably, and so may become a source of memory leaks +if held within objects with long lifetimes.

        +

        Example

        +

         public class Foo {
        +     private StringBuffer buffer;    // potential memory leak as an instance variable;
        + }

        +

        Alternative rule: java:S1149

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative +
        + + AvoidSynchronizedAtMethodLevel + Avoid synchronized at method level + category/java/multithreading.xml/AvoidSynchronizedAtMethodLevel + MAJOR + Title of issues: Use block level locking rather than method level synchronization +

        Method-level synchronization will pin virtual threads and can cause performance problems. Additionally, it can cause +problems when new code is added to the method. Block-level ReentrantLock helps to ensure that only the code that +needs mutual exclusion will be locked.

        +

        Example

        +

         public class Foo {
        +     // Try to avoid this:
        +     synchronized void foo() {
        +         // code, that doesn't need synchronization
        +         // ...
        +         // code, that requires synchronization
        +         if (!sharedData.has("bar")) {
        +             sharedData.add("bar");
        +         }
        +         // more code, that doesn't need synchronization
        +         // ...
        +     }
        +     // Prefer this:
        +     Lock instanceLock = new ReentrantLock();
        + 
        +     void bar() {
        +         // code, that doesn't need synchronization
        +         // ...
        +         try {
        +             instanceLock.lock();  // or instanceLock.tryLock(long time, TimeUnit unit)
        +             if (!sharedData.has("bar")) {
        +                 sharedData.add("bar");
        +             }
        +         } finally {
        +             instanceLock.unlock();
        +         }
        +         // more code, that doesn't need synchronization
        +         // ...
        +     }
        + 
        +     // Try to avoid this for static methods:
        +     static synchronized void fooStatic() {
        +     }
        + 
        +     // Prefer this:
        +     private static Lock CLASS_LOCK = new ReentrantLock();
        + 
        +     static void barStatic() {
        +         // code, that doesn't need synchronization
        +         // ...
        +         try {
        +             CLASS_LOCK.lock();
        +             // code, that requires synchronization
        +         } finally {
        +             CLASS_LOCK.unlock();
        +         }
        +         // more code, that doesn't need synchronization
        +         // ...
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + multithreading +
        + + AvoidSynchronizedStatement + Avoid synchronized statement + category/java/multithreading.xml/AvoidSynchronizedStatement + MAJOR + Title of issues: Use ReentrantLock rather than synchronization +

        Synchronization will pin virtual threads and can cause performance problems.

        +

        Example

        +

         public class Foo {
        +     // Try to avoid this:
        +     void foo() {
        +         // code that doesn't need mutual exclusion
        +         synchronized(this) {
        +             // code that requires mutual exclusion
        +         }
        +         // more code that doesn't need mutual exclusion
        +     }
        +     // Prefer this:
        +     Lock instanceLock = new ReentrantLock();
        + 
        +     void foo() {
        +         // code that doesn't need mutual exclusion
        +         try {
        +             instanceLock.lock();  // or instanceLock.tryLock(long time, TimeUnit unit)
        +             // code that requires mutual exclusion
        +         } finally {
        +             instanceLock.unlock();
        +         }
        +         // more code that doesn't need mutual exclusion
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + multithreading +
        + + AvoidThreadGroup + Avoid ThreadGroup + category/java/multithreading.xml/AvoidThreadGroup + MAJOR + Title of issues: Avoid using java.lang.ThreadGroup; it is not thread safe +

        Avoid using java.lang.ThreadGroup; although it is intended to be used in a threaded environment +it contains methods that are not thread-safe.

        +

        Example

        +

         public class Bar {
        +     void buz() {
        +         ThreadGroup tg = new ThreadGroup("My threadgroup");
        +         tg = new ThreadGroup(tg, "my thread group");
        +         tg = Thread.currentThread().getThreadGroup();
        +         tg = System.getSecurityManager().getThreadGroup();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + multithreading +
        + + AvoidThrowingNewInstanceOfSameException + Avoid throwing new instance of same exception + category/java/design.xml/AvoidThrowingNewInstanceOfSameException + MAJOR + Title of issues: A catch statement that catches an exception only to wrap it in a new instance of the same type of exception and throw it should be avoided +

        Catch blocks that merely rethrow a caught exception wrapped inside a new instance of the same type only add to +code size and runtime complexity.

        +

        Example

        +

         public void bar() {
        +     try {
        +         // do something
        +     } catch (SomeException se) {
        +         // harmless comment
        +         throw new SomeException(se);
        +     }
        + }

        +

        Alternative rule: java:S1166

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + AvoidThrowingNullPointerException + Avoid throwing NullPointerException + category/java/design.xml/AvoidThrowingNullPointerException + BLOCKER + Title of issues: Avoid throwing null pointer exceptions. +

        Avoid throwing NullPointerExceptions manually. These are confusing because most people will assume that the +virtual machine threw it. To avoid a method being called with a null parameter, you may consider +using an IllegalArgumentException instead, making it clearly seen as a programmer-initiated exception. +However, there are better ways to handle this:

        +

        >Effective Java, 3rd Edition, Item 72: Favor the use of standard exceptions +> +>Arguably, every erroneous method invocation boils down to an illegal argument or state, +but other exceptions are standardly used for certain kinds of illegal arguments and states. +If a caller passes null in some parameter for which null values are prohibited, convention dictates that +NullPointerException be thrown rather than IllegalArgumentException.

        +

        To implement that, you are encouraged to use java.util.Objects.requireNonNull() +(introduced in Java 1.7). This method is designed primarily for doing parameter +validation in methods and constructors with multiple parameters.

        +

        Your parameter validation could thus look like the following: +

         public class Foo {
        +     private String exampleValue;
        + 
        +     void setExampleValue(String exampleValue) {
        +       // check, throw and assignment in a single standard call
        +       this.exampleValue = Objects.requireNonNull(exampleValue, "exampleValue must not be null!");
        +     }
        +   }

        +

        Example

        +

         public class Foo {
        +     void bar() {
        +         throw new NullPointerException();
        +     }
        + }

        +

        Alternative rule: java:S1695

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + AvoidThrowingRawExceptionTypes + Avoid throwing raw exception types + category/java/design.xml/AvoidThrowingRawExceptionTypes + BLOCKER + Title of issues: Avoid throwing raw exception type {0}. +

        Avoid throwing certain exception types. Rather than throw a raw RuntimeException, Throwable, +Exception, or Error, use a subclassed exception or error instead.

        +

        Example

        +

         public class Foo {
        +     public void bar() throws Exception {
        +         throw new Exception();
        +     }
        + }

        +

        Alternative rule: java:S112

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + AvoidUncheckedExceptionsInSignatures + Avoid unchecked exceptions in signatures + category/java/design.xml/AvoidUncheckedExceptionsInSignatures + MAJOR + Title of issues: A method or constructor should not explicitly declare unchecked exception {0} in its 'throws' clause +

        Reports unchecked exceptions in the throws clause of a method or constructor. +Java doesn't force the caller to handle an unchecked exception, +so it's unnecessary except for documentation. A better practice is to document the +exceptional cases with a @throws Javadoc tag, which allows being more descriptive.

        +

        Example

        +

         public void foo() throws RuntimeException {
        + }

        +

        Full documentation

        ]]>
        + pmd + design + + violationSuppressRegex + + + STRING + +
        + + AvoidUsingHardCodedIP + Avoid using hard coded IP + category/java/bestpractices.xml/AvoidUsingHardCodedIP + MAJOR + Title of issues: Do not hard code the IP address ${variableName} +

        Application with hard-coded IP addresses can become impossible to deploy in some cases. +Externalizing IP addresses is preferable.

        +

        Example

        +

         public class Foo {
        +     private String ip = "127.0.0.1";     // not recommended
        + }

        +

        Alternative rule: java:S1313

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative + + checkAddressTypes + + IPv4,IPv6,IPv4 mapped IPv6 + SINGLE_SELECT_LIST,multiple=true,values="IPv4,IPv6,IPv4 mapped IPv6" + +
        + + AvoidUsingNativeCode + Avoid using native code + category/java/codestyle.xml/AvoidUsingNativeCode + MAJOR + Title of issues: The use of native code is not recommended. +

        Unnecessary reliance on Java Native Interface (JNI) calls directly reduces application portability +and increases the maintenance burden.

        +

        Example

        +

         public class SomeJNIClass {
        + 
        +      public SomeJNIClass() {
        +          System.loadLibrary("nativelib");
        +      }
        + 
        +      static {
        +          System.loadLibrary("nativelib");
        +      }
        + 
        +      public void invalidCallsInMethod() throws SecurityException, NoSuchMethodException {
        +          System.loadLibrary("nativelib");
        +      }
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + AvoidUsingOctalValues + Avoid using octal values + category/java/errorprone.xml/AvoidUsingOctalValues + MAJOR + Title of issues: Avoid integer literals that start with zero (interpreted as octal), remove the leading 0 to get a decimal literal (or use explicit 0x, 0b prefixes) +

        Integer literals that start with zero are interpreted as octal (base-8) values in Java, which can lead to +unexpected behavior and bugs. Most developers expect decimal (base-10) interpretation, making octal literals +a common source of confusion and errors. For example, 012 equals 10 in decimal, not 12 as might be expected. +This rule helps prevent such mistakes by flagging integer literals that could be misinterpreted as decimal values. +Use decimal literals without leading zeros, or use explicit prefixes like 0x for hexadecimal or 0b for binary values to make the intended base clear.

        +

        Example

        +

         // Bad: These look like decimal but are actually octal
        + int timeout = 060;     // Actually 48 in decimal, not 60!
        + int count = 012;       // Actually 10 in decimal, not 12!
        + 
        + // Good: Use decimal literals
        + int timeout = 60;      // Clear decimal value
        + int count = 12;        // Clear decimal value
        + 
        + // Good: Use explicit prefixes for other bases
        + int hexValue = 0xFF;   // Clearly hexadecimal
        + int binaryValue = 0b1010; // Clearly binary (Java 7+)

        +

        Alternative rule: java:S1314

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + strict + + false + BOOLEAN + +
        + + AvoidUsingVolatile + Avoid using volatile + category/java/multithreading.xml/AvoidUsingVolatile + CRITICAL + Title of issues: Use of modifier volatile is not recommended. +

        Use of the keyword 'volatile' is generally used to fine tune a Java application, and therefore, requires +a good expertise of the Java Memory Model. Moreover, its range of action is somewhat misknown. Therefore, +the volatile keyword should not be used for maintenance purpose and portability.

        +

        Example

        +

         public class Data {
        +   private volatile String var1; // not suggested
        +   private          String var2; // preferred
        + }

        +

        Full documentation

        ]]>
        + pmd + multithreading +
        + + BigIntegerInstantiation + BigInteger instantiation + category/java/performance.xml/BigIntegerInstantiation + MAJOR + Title of issues: Don't create instances of already existing BigInteger and BigDecimal (ZERO, ONE, TEN) +

        Don't create instances of already existing BigInteger (BigInteger.ZERO, BigInteger.ONE), +for Java 1.5 onwards, BigInteger.TEN and BigDecimal (BigDecimal.ZERO, BigDecimal.ONE, BigDecimal.TEN) and +for Java 9 onwards BigInteger.TWO.

        +

        Example

        +

         BigInteger bi1 = new BigInteger("1");    // reference BigInteger.ONE instead
        + BigInteger bi2 = new BigInteger("0");    // reference BigInteger.ZERO instead
        + BigInteger bi3;
        + bi3 = new BigInteger("0");               // reference BigInteger.ZERO instead
        + 
        + BigDecimal bd1 = new BigDecimal(0);      // reference BigDecimal.ZERO instead
        + BigDecimal bd2 = new BigDecimal("0.") ;  // reference BigDecimal.ZERO instead
        + BigDecimal bd3 = new BigDecimal(10);     // reference BigDecimal.TEN instead

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + BooleanGetMethodName + Boolean get method name + category/java/codestyle.xml/BooleanGetMethodName + MINOR + Title of issues: A 'getX()' method which returns a boolean or Boolean should be named 'isX()' +

        Methods that return boolean or Boolean results should be named as predicate statements to denote this. + I.e., 'isReady()', 'hasValues()', 'canCommit()', 'willFail()', etc. Avoid the use of the 'get' prefix for these methods.

        +

        Example

        +

         public boolean getFoo();            // bad
        + public Boolean getFoo();            // bad
        + public boolean isFoo();             // ok
        + public Boolean isFoo();             // ok
        + public boolean getFoo(boolean bar); // ok, unless checkParameterizedMethods=true

        +

        Full documentation

        ]]>
        + pmd + codestyle + + checkParameterizedMethods + + false + BOOLEAN + +
        + + BrokenNullCheck + Broken null check + category/java/errorprone.xml/BrokenNullCheck + CRITICAL + Title of issues: This expression will throw a NullPointerException +

        The null check is broken since it will throw a NullPointerException itself. +It is likely that you used || instead of && or vice versa.

        +

        Example

        +

         public String bar(String string) {
        +   // should be &&
        +     if (string!=null || !string.equals(""))
        +         return string;
        +   // should be ||
        +     if (string==null && string.equals(""))
        +         return string;
        + }

        +

        Alternative rule: java:S1697

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + CallSuperFirst + Call super first + category/java/errorprone.xml/CallSuperFirst + MAJOR + Title of issues: super should be called at the start of the method +

        Super should be called at the start of the method

        +

        Example

        +

         import android.app.Activity;
        + import android.os.Bundle;
        + 
        + public class DummyActivity extends Activity {
        +     public void onCreate(Bundle bundle) {
        +         // missing call to super.onCreate(bundle)
        +         foo();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + CallSuperInConstructor + Call super in constructor + category/java/codestyle.xml/CallSuperInConstructor + MINOR + Title of issues: It is a good practice to call super() in a constructor +

        It is a good practice to call super() in a constructor. If super() is not called but +another constructor (such as an overloaded constructor) is called, this rule will not report it.

        +

        Example

        +

         public class Foo extends Bar{
        +   public Foo() {
        +    // call the constructor of Bar
        +    super();
        +   }
        +  public Foo(int code) {
        +   // do something with code
        +    this();
        +    // no problem with this
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + CallSuperLast + Call super last + category/java/errorprone.xml/CallSuperLast + MAJOR + Title of issues: super should be called at the end of the method +

        Super should be called at the end of the method

        +

        Example

        +

         import android.app.Activity;
        + 
        + public class DummyActivity extends Activity {
        +     public void onPause() {
        +         foo();
        +         // missing call to super.onPause()
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + CheckResultSet + Check result set + category/java/bestpractices.xml/CheckResultSet + MAJOR + Title of issues: Always check the return of one of the navigation method (next,previous,first,last) of a ResultSet. +

        Always check the return values of navigation methods (next, previous, first, last) of a ResultSet. +If the value return is 'false', it should be handled properly.

        +

        Example

        +

         Statement stat = conn.createStatement();
        + ResultSet rst = stat.executeQuery("SELECT name FROM person");
        + rst.next();     // what if it returns false? bad form
        + String firstName = rst.getString(1);
        + 
        + Statement stat = conn.createStatement();
        + ResultSet rst = stat.executeQuery("SELECT name FROM person");
        + if (rst.next()) {    // result is properly examined and used
        +     String firstName = rst.getString(1);
        +     } else  {
        +         // handle missing data
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + CheckSkipResult + Check skip result + category/java/errorprone.xml/CheckSkipResult + MAJOR + Title of issues: Check the value returned by the skip() method of an InputStream to see if the requested number of bytes has been skipped. +

        The skip() method may skip a smaller number of bytes than requested. Check the returned value to find out if it was the case or not.

        +

        Example

        +

         public class Foo {
        + 
        +    private FileInputStream _s = new FileInputStream("file");
        + 
        +    public void skip(int n) throws IOException {
        +       _s.skip(n); // You are not sure that exactly n bytes are skipped
        +    }
        + 
        +    public void skipExactly(int n) throws IOException {
        +       while (n != 0) {
        +          long skipped = _s.skip(n);
        +          if (skipped == 0)
        +             throw new EOFException();
        +          n -= skipped;
        +       }
        +    }

        +

        Alternative rule: java:S2674

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + ClassCastExceptionWithToArray + ClassCastException with toArray + category/java/errorprone.xml/ClassCastExceptionWithToArray + MAJOR + Title of issues: This usage of the Collection.toArray() method will throw a ClassCastException. +

        When deriving an array of a specific class from your Collection, one should provide an array of +the same class as the parameter of the toArray() method. Doing otherwise will result +in a ClassCastException.

        +

        Example

        +

         Collection c = new ArrayList();
        + Integer obj = new Integer(1);
        + c.add(obj);
        + 
        +     // this would trigger the rule (and throw a ClassCastException if executed)
        + Integer[] a = (Integer [])c.toArray();
        + 
        +    // this is fine and will not trigger the rule
        + Integer[] b = (Integer [])c.toArray(new Integer[0]);

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + ClassNamingConventions + Class naming conventions + category/java/codestyle.xml/ClassNamingConventions + MAJOR + Title of issues: The {0} name '{1}' doesn't match '{2}' +

        Configurable naming conventions for type declarations. This rule reports + type declarations which do not match the regex that applies to their + specific kind (e.g. enum or interface). Each regex can be configured through + properties.

        +

        By default, this rule uses the standard Java naming convention (Pascal case).

        +

        The rule can detect utility classes and enforce a different naming convention + on those. E.g. setting the property utilityClassPattern to + [A-Z][a-zA-Z0-9]+(Utils?|Helper|Constants) reports any utility class, whose name + does not end in "Util(s)", "Helper" or "Constants".

        +

        For this rule, a utility class is defined as: a concrete class that does not + inherit from a super class or implement any interface and only has static fields + or methods.

        +

        This rule detects test classes using the following convention: Test classes are top-level classes, that + either inherit from JUnit 3 TestCase or have at least one method annotated with the Test annotations from + JUnit4/5 or TestNG.

        +

        Example

        +

         // This is Pascal case, the recommended naming convention in Java
        + // Note that the default values of this rule don't allow underscores
        + // or accented characters in type names
        + public class FooBar {}
        + 
        + // You may want abstract classes to be named 'AbstractXXX',
        + // in which case you can customize the regex for abstract
        + // classes to 'Abstract[A-Z]\w+'
        + public abstract class Thing {}
        + 
        + // This class doesn't respect the convention, and will be flagged
        + public class Éléphant {}

        +

        Alternative rules: java:S101, java:S114

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + classPattern + + [A-Z][a-zA-Z0-9]* + STRING + + + abstractClassPattern + + [A-Z][a-zA-Z0-9]* + STRING + + + interfacePattern + + [A-Z][a-zA-Z0-9]* + STRING + + + enumPattern + + [A-Z][a-zA-Z0-9]* + STRING + + + annotationPattern + + [A-Z][a-zA-Z0-9]* + STRING + + + utilityClassPattern + + [A-Z][a-zA-Z0-9]* + STRING + + + testClassPattern + + ^Test.*$|^[A-Z][a-zA-Z0-9]*Test(s|Case)?$ + STRING + + + violationSuppressRegex + + + STRING + +
        + + ClassWithOnlyPrivateConstructorsShouldBeFinal + Class with only private constructors should be final + category/java/design.xml/ClassWithOnlyPrivateConstructorsShouldBeFinal + BLOCKER + Title of issues: This class has only private constructors and may be final +

        Reports classes that may be made final because they cannot be extended from outside +their compilation unit anyway. This is because all their constructors are private, +so a subclass could not call the super constructor.

        +

        Example

        +

         public class Foo {  //Should be final
        +     private Foo() { }
        + }

        +

        Alternative rule: java:S2974

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + CloneMethodMustBePublic + Clone method must be public + category/java/errorprone.xml/CloneMethodMustBePublic + MAJOR + Title of issues: clone() method must be public if the class implements Cloneable +

        The java manual says "By convention, classes that implement this interface should override +Object.clone (which is protected) with a public method."

        +

        Example

        +

         public class Foo implements Cloneable {
        +     @Override
        +     protected Object clone() throws CloneNotSupportedException { // Violation, must be public
        +     }
        + }
        + 
        + public class Foo implements Cloneable {
        +     @Override
        +     protected Foo clone() { // Violation, must be public
        +     }
        + }
        + 
        + public class Foo implements Cloneable {
        +     @Override
        +     public Object clone() // Ok
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + CloneMethodMustImplementCloneable + Clone method must implement Cloneable + category/java/errorprone.xml/CloneMethodMustImplementCloneable + MAJOR + Title of issues: clone() method should be implemented only if implementing Cloneable interface +

        The method clone() should only be implemented if the class implements the Cloneable interface with the exception of +a final method that only throws CloneNotSupportedException.

        +

        The rule can also detect, if the class implements or extends a Cloneable class.

        +

        Example

        +

         public class MyClass {
        +  public Object clone() throws CloneNotSupportedException {
        +   return foo;
        +  }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + CloneMethodReturnTypeMustMatchClassName + Clone method return type must match class name + category/java/errorprone.xml/CloneMethodReturnTypeMustMatchClassName + MAJOR + Title of issues: The return type of the clone() method must be the class name when implements Cloneable +

        If a class implements Cloneable the return type of the method clone() must be the class name. That way, the caller +of the clone method doesn't need to cast the returned clone to the correct type.

        +

        Note: Such a covariant return type is only possible with Java 1.5 or higher.

        +

        Example

        +

         public class Foo implements Cloneable {
        +     @Override
        +     protected Object clone() { // Violation, Object must be Foo
        +     }
        + }
        + 
        + public class Foo implements Cloneable {
        +     @Override
        +     public Foo clone() { //Ok
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + CloseResource + Close resource + category/java/errorprone.xml/CloseResource + MAJOR + Title of issues: Ensure that resources like this {0} object are closed after use +

        Ensure that resources (like java.sql.Connection, java.sql.Statement, and java.sql.ResultSet objects +and any subtype of java.lang.AutoCloseable) are always closed after use. +Failing to do so might result in resource leaks.

        +

        Note: It suffices to configure the super type, e.g. java.lang.AutoCloseable, so that this rule automatically triggers +on any subtype (e.g. java.io.FileInputStream). Additionally specifying java.sql.Connection helps in detecting +the types, if the type resolution / auxclasspath is not correctly setup.

        +

        Note: Since PMD 6.16.0 the default value for the property types contains java.lang.AutoCloseable and detects +now cases where the standard java.io.*Stream classes are involved. In order to restore the old behaviour, +just remove "AutoCloseable" from the types.

        +

        Example

        +

         public class Bar {
        +     public void withSQL() {
        +         Connection c = pool.getConnection();
        +         try {
        +             // do stuff
        +         } catch (SQLException ex) {
        +            // handle exception
        +         } finally {
        +             // oops, should close the connection using 'close'!
        +             // c.close();
        +         }
        +     }
        + 
        +     public void withFile() {
        +         InputStream file = new FileInputStream(new File("/tmp/foo"));
        +         try {
        +             int c = file.in();
        +         } catch (IOException e) {
        +             // handle exception
        +         } finally {
        +             // TODO: close file
        +         }
        +     }
        + }

        +

        Alternative rule: java:S2095

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + closeTargets + + + STRING + + + types + + java.lang.AutoCloseable,java.sql.Connection,java.sql.Statement,java.sql.ResultSet + STRING + + + closeAsDefaultTarget + + true + BOOLEAN + + + allowedResourceTypes + + java.io.ByteArrayOutputStream,java.io.ByteArrayInputStream,java.io.StringWriter,java.io.CharArrayWriter,java.util.stream.Stream,java.util.stream.IntStream,java.util.stream.LongStream,java.util.stream.DoubleStream + STRING + + + closeNotInFinally + + false + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + CognitiveComplexity + Cognitive complexity + category/java/design.xml/CognitiveComplexity + MAJOR + Title of issues: The {0} '{1}' has a cognitive complexity of {2}, current threshold is {3} +

        Methods that are highly complex are difficult to read and more costly to maintain. If you include too much decisional + logic within a single method, you make its behavior hard to understand and more difficult to modify.

        +

        Cognitive complexity is a measure of how difficult it is for humans to read and understand a method. Code that contains + a break in the control flow is more complex, whereas the use of language shorthands doesn't increase the level of + complexity. Nested control flows can make a method more difficult to understand, with each additional nesting of the + control flow leading to an increase in cognitive complexity.

        +

        Information about Cognitive complexity can be found in the original paper here: + https://www.sonarsource.com/docs/CognitiveComplexity.pdf

        +

        By default, this rule reports methods with a complexity of 15 or more. Reported methods should be broken down into less + complex components.

        +

        Example

        +

         public class Foo {
        +   // Has a cognitive complexity of 0
        +   public void createAccount() {
        +     Account account = new Account("PMD");
        +     // save account
        +   }
        + 
        +   // Has a cognitive complexity of 1
        +   public Boolean setPhoneNumberIfNotExisting(Account a, String phone) {
        +     if (a.phone == null) {                          // +1
        +       a.phone = phone;
        +       return true;
        +     }
        + 
        +     return false;
        +   }
        + 
        +   // Has a cognitive complexity of 4
        +   public void updateContacts(List<Contact> contacts) {
        +     List<Contact> contactsToUpdate = new ArrayList<Contact>();
        + 
        +     for (Contact contact : contacts) {                           // +1
        +       if (contact.department.equals("Finance")) {                // +2 (nesting = 1)
        +         contact.title = "Finance Specialist";
        +         contactsToUpdate.add(contact);
        +       } else if (contact.department.equals("Sales")) {           // +1
        +         contact.title = "Sales Specialist";
        +         contactsToUpdate.add(contact);
        +       }
        +     }
        +     // save contacts
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + design + + reportLevel + + 15 + INTEGER + + + violationSuppressRegex + + + STRING + +
        + + CollapsibleIfStatements + Collapsible if statements + category/java/design.xml/CollapsibleIfStatements + MAJOR + Title of issues: This if statement could be combined with its parent +

        Reports nested 'if' statements that can be merged together by joining their +conditions with a boolean && operator in between.

        +

        Example

        +

         class Foo {
        + 
        +     void bar() {
        +         if (x) {            // original implementation
        +             if (y) {
        +                 // do stuff
        +             }
        +         }
        +     }
        + 
        +     void bar() {
        +         if (x && y) {        // clearer implementation
        +             // do stuff
        +         }
        +     }
        + }

        +

        Alternative rule: java:S1066

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + CollectionTypeMismatch + Collection type mismatch + category/java/errorprone.xml/CollectionTypeMismatch + MAJOR + Title of issues: Object of type '{0}' cannot be in collection expecting '{1}' +

        Detects method calls on collections where the passed object cannot possibly be in the collection +due to type mismatch. This helps catch potential programming errors where incompatible types +are used with collection methods like contains(), remove(), indexOf(), etc.

        +

        Methods checked include:

        +
        • Collection: contains(), remove(), removeAll(), retainAll(), containsAll()
        • List: indexOf(), lastIndexOf()
        • Map: containsKey(), containsValue(), get(), getOrDefault(), remove()
        • Deque: removeFirstOccurrence(), removeLastOccurrence()
        • Hashtable: contains() (legacy method that checks values)
        • ConcurrentHashMap: contains() (legacy method that checks values)
        +

        Example

        +

         List<Integer> numbers = Arrays.asList(1, 2, 3);
        + numbers.remove("string"); // violation: String cannot be in Integer list
        + 
        + Map<String, Integer> map = new HashMap<>();
        + map.get(42); // violation: Integer key cannot be in String-keyed map
        + 
        + Set<String> names = new HashSet<>(); 
        + names.contains(123); // violation: Integer cannot be in String set

        +

        Full documentation

        ]]>
        + pmd + errorprone + + violationSuppressRegex + + + STRING + +
        + + CommentContent + Comment content + category/java/documentation.xml/CommentContent + MAJOR + Title of issues: Invalid words or phrases found +

        A rule for the politically correct... we don't want to offend anyone.

        +

        Example

        +

         //OMG, this is horrible, Bob is an idiot !!!

        +

        Full documentation

        ]]>
        + pmd + documentation + + forbiddenRegex + + idiot|jerk + STRING + +
        + + CommentDefaultAccessModifier + Comment default access modifier + category/java/codestyle.xml/CommentDefaultAccessModifier + MINOR + Title of issues: Missing commented default access modifier on {0} '{1}' +

        To avoid mistakes if we want that an Annotation, Class, Enum, Method, Constructor or Field have a default access modifier +we must add a comment at the beginning of its declaration. +By default, the comment must be /* default */ or /* package */, if you want another, you have to provide a regular expression.

        +

        This rule ignores by default all cases that have a @VisibleForTesting annotation or any JUnit5/TestNG annotation. Use the +property "ignoredAnnotations" to customize the recognized annotations.

        +

        Example

        +

         public class Foo {
        +     final String stringValue = "some string";
        +     String getString() {
        +        return stringValue;
        +     }
        + 
        +     class NestedFoo {
        +     }
        + }
        + 
        + // should be
        + public class Foo {
        +     /* default */ final String stringValue = "some string";
        +     /* default */ String getString() {
        +        return stringValue;
        +     }
        + 
        +     /* default */ class NestedFoo {
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + ignoredAnnotations + + android.support.annotation.VisibleForTesting,co.elastic.clients.util.VisibleForTesting,com.google.common.annotations.VisibleForTesting,org.junit.jupiter.api.AfterAll,org.junit.jupiter.api.AfterEach,org.junit.jupiter.api.BeforeAll,org.junit.jupiter.api.BeforeEach,org.junit.jupiter.api.RepeatedTest,org.junit.jupiter.api.Test,org.junit.jupiter.api.TestFactory,org.junit.jupiter.api.TestTemplate,org.junit.jupiter.api.extension.RegisterExtension,org.junit.jupiter.params.ParameterizedTest,org.testng.annotations.AfterClass,org.testng.annotations.AfterGroups,org.testng.annotations.AfterMethod,org.testng.annotations.AfterSuite,org.testng.annotations.AfterTest,org.testng.annotations.BeforeClass,org.testng.annotations.BeforeGroups,org.testng.annotations.BeforeMethod,org.testng.annotations.BeforeSuite,org.testng.annotations.BeforeTest,org.testng.annotations.Test + STRING + + + regex + + \/\*\s*(default|package)\s*\*\/ + STRING + + + checkTopLevelTypes + + false + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + CommentRequired + Comment required + category/java/documentation.xml/CommentRequired + MAJOR + Title of issues: Comment is required +

        Denotes whether javadoc (formal) comments are required (or unwanted) for specific language elements.

        +

        Example

        +

         /**
        + *
        + *
        + * @author Jon Doe
        + */

        +

        Full documentation

        ]]>
        + pmd + documentation + + methodWithOverrideCommentRequirement + + Ignored + SINGLE_SELECT_LIST,values="Required,Ignored,Unwanted" + + + accessorCommentRequirement + + Ignored + SINGLE_SELECT_LIST,values="Required,Ignored,Unwanted" + + + classCommentRequirement + + Required + SINGLE_SELECT_LIST,values="Required,Ignored,Unwanted" + + + fieldCommentRequirement + + Required + SINGLE_SELECT_LIST,values="Required,Ignored,Unwanted" + + + publicMethodCommentRequirement + + Required + SINGLE_SELECT_LIST,values="Required,Ignored,Unwanted" + + + protectedMethodCommentRequirement + + Required + SINGLE_SELECT_LIST,values="Required,Ignored,Unwanted" + + + enumCommentRequirement + + Required + SINGLE_SELECT_LIST,values="Required,Ignored,Unwanted" + + + serialVersionUIDCommentRequired + + Ignored + SINGLE_SELECT_LIST,values="Required,Ignored,Unwanted" + + + serialPersistentFieldsCommentRequired + + Ignored + SINGLE_SELECT_LIST,values="Required,Ignored,Unwanted" + +
        + + CommentSize + Comment size + category/java/documentation.xml/CommentSize + MAJOR + Title of issues: Comment is too large +

        Determines whether the dimensions of non-header comments found are within the specified limits.

        +

        Example

        +

         /**
        + *
        + *   too many lines!
        + *
        + *
        + *
        + *
        + *
        + *
        + *
        + *
        + *
        + *
        + *
        + *
        + */

        +

        Full documentation

        ]]>
        + pmd + documentation + + maxLines + + 6 + INTEGER + + + maxLineLength + + 80 + INTEGER + +
        + + CompareObjectsWithEquals + Compare objects with equals + category/java/errorprone.xml/CompareObjectsWithEquals + MAJOR + Title of issues: Use equals() to compare object references. +

        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.

        +

        Example

        +

         class Foo {
        +   boolean bar(String a, String b) {
        +     return a == b;
        +   }
        + }

        +

        Alternative rule: java:S1698

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + typesThatCompareByReference + + + STRING + +
        + + ComparisonWithNaN + Comparison with NaN + category/java/errorprone.xml/ComparisonWithNaN + MAJOR + Title of issues: Comparisons with NaN always return false +

        Reports comparisons with double and float NaN (Not-a-Number) values. + These are specified + to have unintuitive behavior: NaN is considered unequal to itself. + This means a check like someDouble == Double.NaN will always return + false, even if someDouble is really the NaN value. To test whether a + value is the NaN value, one should instead use Double.isNaN(someDouble) + (or Float.isNaN). The != operator should be treated similarly. + Finally, comparisons like someDouble <= Double.NaN are nonsensical + and will always evaluate to false.

        +

        This rule has been renamed from "BadComparison" in PMD 6.36.0.

        +

        Example

        +

         boolean x = (y == Double.NaN);

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + ConfusingArgumentToVarargsMethod + Confusing argument to varargs method + category/java/errorprone.xml/ConfusingArgumentToVarargsMethod + MAJOR + Title of issues: Unclear if a varargs or non-varargs call is intended. Cast to {0} or {0}[], or pass varargs parameters separately to clarify intent. +

        Reports a confusing argument passed to a varargs method.

        +

        This can occur when an array is passed as a single varargs argument, when the array type is not exactly the + type of array that the varargs method expects. If, that array is a subtype of the component type of the expected + array type, then it might not be clear what value the called varargs method will receive. + For instance if you have: +

         void varargs(Object... parm);
        + and call it like so: +
         varargs(new String[]{"a"});
        + it is not clear whether you intended the method to receive the value new Object[]{ new String[] {"a"} } or + just new String[] {"a"} (the latter happens). This confusion occurs because String[] is both a subtype + of Object[] and of Object. To clarify your intent in this case, use a cast or pass individual elements like so: +
         // varargs call
        +             // parm will be `new Object[] { "a" }`
        +             varargs("a");
        + 
        +             // non-varargs call
        +             // parm will be `new String[] { "a" }`
        +             varargs((Object[]) new String[]{"a"});
        + 
        +             // varargs call
        +             // parm will be `new Object[] { new String[] { "a" } }`
        +             varargs((Object) new String[]{"a"});

        +

        Another confusing case is when you pass null as the varargs argument. Here it is not clear whether you intended + to pass an array with a single null element, or a null array (the latter happens). This can similarly be clarified + with a cast.

        +

        Example

        +

         import java.util.Arrays;
        + 
        +             abstract class C {
        +                 abstract void varargs(Object... args);
        +                 static {
        +                     varargs(new String[] { "a" });
        +                     varargs(null);
        +                 }
        +             }

        +

        Full documentation

        ]]>
        + pmd + errorprone + + violationSuppressRegex + + + STRING + +
        + + ConfusingTernary + Confusing ternary + category/java/codestyle.xml/ConfusingTernary + MINOR + Title of issues: Avoid if (x != y) ..; else ..; +

        Avoid negation within an "if" expression with an "else" clause. For example, rephrase: +if (x != y) diff(); else same(); as: if (x == y) same(); else diff();.

        +

        Most "if (x != y)" cases without an "else" are often return cases, so consistent use of this +rule makes the code easier to read. Also, this resolves trivial ordering problems, such +as "does the error case go first?" or "does the common case go first?".

        +

        Example

        +

         boolean bar(int x, int y) {
        +     return (x != y) ? diff : same;
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + ignoreElseIf + + false + BOOLEAN + +
        + + ConsecutiveAppendsShouldReuse + Consecutive appends should reuse + category/java/performance.xml/ConsecutiveAppendsShouldReuse + MAJOR + Title of issues: StringBuffer (or StringBuilder).append is called consecutively without reusing the target variable. +

        Consecutive calls to StringBuffer/StringBuilder .append should be chained, reusing the target object. This can improve the performance +by producing a smaller bytecode, reducing overhead and improving inlining. A complete analysis can be found here

        +

        Example

        +

         String foo = " ";
        + 
        + StringBuffer buf = new StringBuffer();
        + buf.append("Hello"); // poor
        + buf.append(foo);
        + buf.append("World");
        + 
        + StringBuffer buf = new StringBuffer();
        + buf.append("Hello").append(foo).append("World"); // good

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + ConsecutiveLiteralAppends + Consecutive literal appends + category/java/performance.xml/ConsecutiveLiteralAppends + MAJOR + Title of issues: StringBuffer (or StringBuilder).append is called {0} consecutive times with literals. Use a single append with a single combined String. +

        Consecutively calling StringBuffer/StringBuilder.append(...) with literals should be avoided. +Since the literals are constants, they can already be combined into a single String literal and this String +can be appended in a single method call.

        +

        Example

        +

         StringBuilder buf = new StringBuilder();
        + buf.append("Hello").append(" ").append("World");    // poor
        + buf.append("Hello World");                          // good
        + 
        + buf.append('h').append('e').append('l').append('l').append('o'); // poor
        + buf.append("hello");                                             // good
        + 
        + buf.append(1).append('m');  // poor
        + buf.append("1m");           // good

        +

        Full documentation

        ]]>
        + pmd + performance + + threshold + + 1 + INTEGER + + + violationSuppressRegex + + + STRING + +
        + + ConstantsInInterface + Constants in interface + category/java/bestpractices.xml/ConstantsInInterface + MAJOR + Title of issues: Using constants in interfaces is a bad practice. +

        Using constants in interfaces is a bad practice. Interfaces define types, constants are implementation details better placed in classes or enums. If the constants are best viewed as members of an enumerated type, you should export them with an enum type. +For other scenarios, consider using a utility class. See Effective Java's 'Use interfaces only to define types'.

        +

        Example

        +

         public interface ConstantInterface {
        +     public static final int CONST1 = 1; // violation, no fields allowed in interface!
        +     static final int CONST2 = 1;        // violation, no fields allowed in interface!
        +     final int CONST3 = 1;               // violation, no fields allowed in interface!
        +     int CONST4 = 1;                     // violation, no fields allowed in interface!
        + }
        + 
        + // with ignoreIfHasMethods = false
        + public interface AnotherConstantInterface {
        +     public static final int CONST1 = 1; // violation, no fields allowed in interface!
        + 
        +     int anyMethod();
        + }
        + 
        + // with ignoreIfHasMethods = true
        + public interface YetAnotherConstantInterface {
        +     public static final int CONST1 = 1; // no violation
        + 
        +     int anyMethod();
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + ignoreIfHasMethods + + true + BOOLEAN + +
        + + ConstructorCallsOverridableMethod + Constructor calls overridable method + category/java/errorprone.xml/ConstructorCallsOverridableMethod + BLOCKER + Title of issues: Overridable {0} called during object construction{1} +

        Reports calls to overridable methods on this during object initialization. These +are invoked on an incompletely constructed object and can be difficult to debug if overridden. +This is because the subclass usually assumes that the superclass is completely initialized +in all methods. If that is not the case, bugs can appear in the constructor, for instance, +some fields that are still null may cause a NullPointerException or be stored somewhere +else to blow up later.

        +

        To avoid this problem, only use methods that are static, private, or final in constructors. +Note that those methods also must not call overridable methods transitively to be safe.

        +

        Example

        +

         public class SeniorClass {
        +   public SeniorClass(){
        +       toString(); //may throw NullPointerException if overridden
        +   }
        +   public String toString(){
        +     return "IAmSeniorClass";
        +   }
        + }
        + public class JuniorClass extends SeniorClass {
        +   private String name;
        +   public JuniorClass(){
        +     super(); //Automatic call leads to NullPointerException
        +     name = "JuniorClass";
        +   }
        +   public String toString(){
        +     return name.toUpperCase();
        +   }
        + }

        +

        Alternative rule: java:S1699

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + ControlStatementBraces + Control statement braces + category/java/codestyle.xml/ControlStatementBraces + MINOR + Title of issues: This statement should have braces +

        Enforce a policy for braces on control statements. It is recommended to use braces on 'if ... else' + statements and loop statements, even if they are optional. This usually makes the code clearer, and + helps prepare the future when you need to add another statement. That said, this rule lets you control + which statements are required to have braces via properties.

        +

        From 6.2.0 on, this rule supersedes WhileLoopMustUseBraces, ForLoopMustUseBraces, IfStmtMustUseBraces, + and IfElseStmtMustUseBraces.

        +

        Example

        +

         while (true)    // not recommended
        +   x++;
        + 
        + while (true) {  // preferred approach
        +   x++;
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + checkIfElseStmt + + true + BOOLEAN + + + checkSingleIfStmt + + true + BOOLEAN + + + checkWhileStmt + + true + BOOLEAN + + + checkForStmt + + true + BOOLEAN + + + checkDoWhileStmt + + true + BOOLEAN + + + checkCaseStmt + + false + BOOLEAN + + + allowEmptyLoop + + false + BOOLEAN + +
        + + CouplingBetweenObjects + Coupling between objects + category/java/design.xml/CouplingBetweenObjects + MAJOR + Title of issues: A value of {0} may denote a high amount of coupling within the class (threshold: {1}) +

        This rule counts the number of unique attributes, local variables, and return types within an object. +A number higher than the specified threshold can indicate a high degree of coupling.

        +

        Example

        +

         import com.Blah;
        + import org.Bar;
        + import org.Bardo;
        + 
        + public class Foo {
        +     private Blah var1;
        +     private Bar var2;
        + 
        +     //followed by many imports of unique objects
        +     ObjectC doWork() {
        +         Bardo var55;
        +         ObjectA var44;
        +         ObjectZ var93;
        +         return something();
        +     }
        + }

        +

        Alternative rule: java:S1200

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + threshold + + 20 + INTEGER + + + violationSuppressRegex + + + STRING + +
        + + CyclomaticComplexity + Cyclomatic complexity + category/java/design.xml/CyclomaticComplexity + MAJOR + Title of issues: The {0} '{1}' has a{2} cyclomatic complexity of {3}. +

        The complexity of methods directly affects maintenance costs and readability. Concentrating too much decisional logic +in a single method makes its behaviour hard to read and change.

        +

        Cyclomatic complexity assesses the complexity of a method by counting the number of decision points in a method, +plus one for the method entry. Decision points are places where the control flow jumps to another place in the +program. As such, they include all control flow statements, such as if, while, for, and case. For more +details on the calculation, see the documentation CYCLO.

        +

        Generally, numbers ranging from 1-4 denote low complexity, 5-7 denote moderate complexity, 8-10 denote +high complexity, and 11+ is very high complexity. By default, this rule reports methods with a complexity >= 10. +Additionally, classes with many methods of moderate complexity get reported as well once the total of their +methods' complexities reaches 80, even if none of the methods was directly reported.

        +

        Reported methods should be broken down into several smaller methods. Reported classes should probably be broken down +into subcomponents.

        +

        Example

        +

         class Foo {
        +   void baseCyclo() {                // Cyclo = 1
        +     highCyclo();
        +   }
        + 
        +   void highCyclo() {                // Cyclo = 10: reported!
        +     int x = 0, y = 2;
        +     boolean a = false, b = true;
        + 
        +     if (a && (y == 1 ? b : true)) { // +3
        +       if (y == x) {                 // +1
        +         while (true) {              // +1
        +           if (x++ < 20) {           // +1
        +             break;                  // +1
        +           }
        +         }
        +       } else if (y == t && !d) {    // +2
        +         x = a ? y : x;              // +1
        +       } else {
        +         x = 2;
        +       }
        +     }
        +   }
        + }

        +

        Alternative rule: java:S1541

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + classReportLevel + + 80 + INTEGER + + + methodReportLevel + + 10 + INTEGER + + + cycloOptions + + + STRING + + + violationSuppressRegex + + + STRING + +
        + + DanglingJavadoc + Dangling javadoc + category/java/documentation.xml/DanglingJavadoc + MAJOR + Title of issues: Javadoc comment does not belong to any class, method or field +

        Javadoc comments that do not belong to a class, method or field are ignored by the JavaDoc tool +and don't end up in the generated API documentation. Such comments are either misplaced +(e.g. between annotations and method declaration) or should be block comments.

        +

        In order to fix this violation, the comment should be moved to the correct place, +converted into a block comment or removed completely.

        +

        Example

        +

         public class Foo {
        +   /**
        +    * Public methods // wrong
        +    */
        + 
        +   /**
        +    * A setter // OK
        +    */
        +    public void setFoo() {
        + 
        +    }
        + 
        + }

        +

        Full documentation

        ]]>
        + pmd + documentation +
        + + DataClass + Data class + category/java/design.xml/DataClass + MAJOR + Title of issues: The class '{0}' is suspected to be a Data Class (WOC={1}, NOPA={2}, NOAM={3}, WMC={4}) +

        Data Classes are simple data holders, which reveal most of their state, and +without complex functionality. The lack of functionality may indicate that +their behaviour is defined elsewhere, which is a sign of poor data-behaviour +proximity. By directly exposing their internals, Data Classes break encapsulation, +and therefore reduce the system's maintainability and understandability. Moreover, +classes tend to strongly rely on their data representation, which makes for a brittle +design.

        +

        Refactoring a Data Class should focus on restoring a good data-behaviour proximity. In +most cases, that means moving the operations defined on the data back into the class. +In some other cases it may make sense to remove entirely the class and move the data +into the former client classes.

        +

        The rule uses metrics to implement its detection strategy. The violation message gives information about the values of these metrics:

        + +

        The rule identifies a god class by looking for classes which have all of the following properties:

        +
        • High NOPA + NOAM
        • Low WOC
        • Low WMC
        +

        Example

        +

         public class DataClass {
        + 
        +   // class exposes public attributes
        +   public String name = "";
        +   public int bar = 0;
        +   public int na = 0;
        + 
        +   private int bee = 0;
        + 
        +   // and private ones through getters
        +   public void setBee(int n) {
        +     bee = n;
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + design + + violationSuppressRegex + + + STRING + +
        + + DefaultLabelNotLastInSwitch + Default label not last in switch + category/java/bestpractices.xml/DefaultLabelNotLastInSwitch + MAJOR + Title of issues: The default label should be the last label in a switch statement or expression +

        By convention, the default label should be the last label in a switch statement or switch expression.

        +

        Note: This rule has been renamed from "DefaultLabelNotLastInSwitchStmt" with PMD 7.7.0.

        +

        Example

        +

         public class Foo {
        +   void bar(int a) {
        +    switch (a) {
        +     case 1:  // do something
        +        break;
        +     default:  // the default case should be last, by convention
        +        break;
        +     case 2:
        +        break;
        +    }
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + DetachedTestCase + Detached test case + category/java/errorprone.xml/DetachedTestCase + MAJOR + Title of issues: Probable detached JUnit test case. +

        The method appears to be a test case since it has public or default visibility, +non-static access, no arguments, no return value, has no annotations, but is a +member of a class that has one or more JUnit test cases. If it is a utility +method, it should likely have private visibility. If it is an ignored test, it +should be annotated with @Test and @Ignore.

        +

        Example

        +

         public class MyTest {
        +     @Test
        +     public void someTest() {
        +     }
        + 
        +     // violation: Not annotated
        +     public void someOtherTest () {
        +     }
        + 
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + DoNotCallGarbageCollectionExplicitly + Do not call garbage collection explicitly + category/java/errorprone.xml/DoNotCallGarbageCollectionExplicitly + CRITICAL + Title of issues: Do not explicitly trigger a garbage collection. +

        Calls to System.gc(), Runtime.getRuntime().gc(), and System.runFinalization() are not advised. +Code should have the same behavior whether the garbage collection is disabled using the option +-Xdisableexplicitgc or not.

        +

        Moreover, "modern" JVMs do a very good job handling garbage collections. If memory usage issues unrelated to memory +leaks develop within an application, it should be dealt with JVM options rather than within the code itself.

        +

        Example

        +

         public class GCCall {
        +     public GCCall() {
        +         // Explicit gc call !
        +         System.gc();
        +     }
        + 
        +     public void doSomething() {
        +         // Explicit gc call !
        +         Runtime.getRuntime().gc();
        +     }
        + 
        +     public explicitGCcall() {
        +         // Explicit gc call !
        +         System.gc();
        +     }
        + 
        +     public void doSomething() {
        +         // Explicit gc call !
        +         Runtime.getRuntime().gc();
        +     }
        + }

        +

        Alternative rule: java:S1215

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + DoNotExtendJavaLangError + Do not extend java.lang.Error + category/java/design.xml/DoNotExtendJavaLangError + MAJOR + Title of issues: Exceptions should not extend java.lang.Error +

        Errors are system exceptions. Do not extend them.

        +

        Example

        +

         public class Foo extends Error { }

        +

        Alternative rule: java:S1194

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + DoNotExtendJavaLangThrowable + Do not extend java.lang.Throwable + category/java/errorprone.xml/DoNotExtendJavaLangThrowable + MAJOR + Title of issues: Exceptions should not extend java.lang.Throwable +

        Extend Exception or RuntimeException instead of Throwable.

        +

        Example

        +

         public class Foo extends Throwable { }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + DoNotHardCodeSDCard + Do not hard code SDCard + category/java/errorprone.xml/DoNotHardCodeSDCard + MAJOR + Title of issues: Do not hardcode /sdcard. +

        Use Environment.getExternalStorageDirectory() instead of "/sdcard"

        +

        Example

        +

         public class MyActivity extends Activity {
        +     protected void foo() {
        +         String storageLocation = "/sdcard/mypackage";   // hard-coded, poor approach
        + 
        +        storageLocation = Environment.getExternalStorageDirectory() + "/mypackage"; // preferred approach
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + DoNotTerminateVM + Do not terminate VM + category/java/errorprone.xml/DoNotTerminateVM + MAJOR + Title of issues: System.exit() should not be used in J2EE/JEE apps +

        Web applications should not call System.exit(), since only the web container or the +application server should stop the JVM. Otherwise a web application would terminate all other applications +running on the same application server.

        +

        This rule also checks for the equivalent calls Runtime.getRuntime().exit() and Runtime.getRuntime().halt().

        +

        This rule has been renamed from "DoNotCallSystemExit" in PMD 6.29.0.

        +

        Example

        +

         public void bar() {
        +     System.exit(0);                 // never call this when running in an application server!
        + }
        + public void foo() {
        +     Runtime.getRuntime().exit(0);   // never stop the JVM manually, the container will do this.
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + DoNotThrowExceptionInFinally + Do not throw exception in finally + category/java/errorprone.xml/DoNotThrowExceptionInFinally + MINOR + Title of issues: A throw statement in a finally block makes the control flow hard to understand. +

        Throwing exceptions within a 'finally' block is confusing since they may mask other exceptions +or code defects. +

        Note: This is a PMD implementation of the Lint4j rule "A throw in a finally block"

        +

        Example

        +

         public class Foo {
        +     public void bar() {
        +         try {
        +             // Here do some stuff
        +         } catch( Exception e) {
        +             // Handling the issue
        +         } finally {
        +             // is this really a good idea ?
        +             throw new Exception();
        +         }
        +     }
        + }

        +

        Alternative rule: java:S1163

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + DoNotUseThreads + Do not use threads + category/java/multithreading.xml/DoNotUseThreads + MAJOR + Title of issues: To be compliant to J2EE, a webapp should not use any thread. +

        The J2EE specification explicitly forbids the use of threads. Threads are resources, that should be managed and monitored by the J2EE server. +If the application creates threads on its own or uses own custom thread pools, then these threads are not managed, which could lead to resource exhaustion. +Also, EJBs might be moved between machines in a cluster and only managed resources can be moved along.

        +

        Example

        +

         // This is not allowed
        + public class UsingThread extends Thread {
        + 
        + }
        + 
        + // Neither this,
        + public class UsingExecutorService {
        + 
        +     public void methodX() {
        +         ExecutorService executorService = Executors.newFixedThreadPool(5);
        +     }
        + }
        + 
        + // Nor this,
        + public class Example implements ExecutorService {
        + 
        + }
        + 
        + // Nor this,
        + public class Example extends AbstractExecutorService {
        + 
        + }
        + 
        + // Nor this
        + public class UsingExecutors {
        + 
        +     public void methodX() {
        +         Executors.newSingleThreadExecutor().submit(() -> System.out.println("Hello!"));
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + multithreading +
        + + DontCallThreadRun + Dont call thread run + category/java/multithreading.xml/DontCallThreadRun + MINOR + Title of issues: Don't call Thread.run() explicitly, use Thread.start() +

        Explicitly calling Thread.run() method will execute in the caller's thread of control. Instead, call Thread.start() for the intended behavior.

        +

        Example

        +

         Thread t = new Thread();
        + t.run();            // use t.start() instead
        + new Thread().run(); // same violation

        +

        Alternative rule: java:S1217

        +

        Full documentation

        ]]>
        + pmd + multithreading + has-sonar-alternative +
        + + DontImportSun + Dont import sun + category/java/errorprone.xml/DontImportSun + MINOR + Title of issues: Avoid importing anything from the 'sun.*' packages +

        Avoid importing anything from the 'sun.*' packages. These packages are not portable +and are likely to change.

        +

        If you find yourself having to depend on Sun APIs, confine this dependency to as +small a scope as possible, for instance by writing a stable wrapper class around +the unstable API. You can then suppress this rule in the implementation of the wrapper.

        +

        Example

        +

         import sun.misc.foo;
        + public class Foo {}

        +

        Alternative rule: java:S1191

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + DontUseFloatTypeForLoopIndices + Dont use float type for loop indices + category/java/errorprone.xml/DontUseFloatTypeForLoopIndices + MAJOR + Title of issues: Don't use floating point for loop indices. If you must use floating point, use double. +

        Don't use floating point for loop indices. If you must use floating point, use double +unless you're certain that float provides enough precision and you have a compelling +performance need (space or time).

        +

        Example

        +

         public class Count {
        +   public static void main(String[] args) {
        +     final int START = 2000000000;
        +     int count = 0;
        +     for (float f = START; f < START + 50; f++)
        +       count++;
        +       //Prints 0 because (float) START == (float) (START + 50).
        +       System.out.println(count);
        +       //The termination test misbehaves due to floating point granularity.
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + DoubleBraceInitialization + Double brace initialization + category/java/bestpractices.xml/DoubleBraceInitialization + MAJOR + Title of issues: Double-brace initialization should be avoided +

        Double brace initialisation is a pattern to initialise eg collections concisely. But it implicitly + generates a new .class file, and the object holds a strong reference to the enclosing object. For those + reasons, it is preferable to initialize the object normally, even though it's verbose.

        +

        This rule counts any anonymous class which only has a single initializer as an instance of double-brace + initialization. There is currently no way to find out whether a method called in the initializer is not + accessible from outside the anonymous class, and those legit cases should be suppressed for the time being.

        +

        Example

        +

         // this is double-brace initialization
        + return new ArrayList<String>(){{
        +     add("a");
        +     add("b");
        +     add("c");
        + }};
        + 
        + // the better way is to not create an anonymous class:
        + List<String> a = new ArrayList<>();
        + a.add("a");
        + a.add("b");
        + a.add("c");
        + return a;

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + DoubleCheckedLocking + Double checked locking + category/java/multithreading.xml/DoubleCheckedLocking + BLOCKER + Title of issues: Double checked locking is not thread safe in Java. +

        Partially created objects can be returned by the Double Checked Locking pattern when used in Java. +An optimizing JRE may assign a reference to the baz variable before it calls the constructor of the object the +reference points to.

        +

        Note: With Java 5, you can make Double checked locking work, if you declare the variable to be volatile.

        +

        For more details refer to: http://www.javaworld.com/javaworld/jw-02-2001/jw-0209-double.html +or http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html

        +

        Example

        +

         public class Foo {
        +     /*volatile */ Object baz = null; // fix for Java5 and later: volatile
        +     Object bar() {
        +         if (baz == null) { // baz may be non-null yet not fully created
        +             synchronized(this) {
        +                 if (baz == null) {
        +                     baz = new Object();
        +                 }
        +               }
        +         }
        +         return baz;
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + multithreading +
        + + EmptyCatchBlock + Empty catch block + category/java/errorprone.xml/EmptyCatchBlock + MAJOR + Title of issues: Avoid empty catch blocks +

        Empty Catch Block finds instances where an exception is caught, but nothing is done. +In most circumstances, this swallows an exception which should either be acted on +or reported.

        +

        Example

        +

         public void doSomething() {
        +     try {
        +         FileInputStream fis = new FileInputStream("/tmp/bugger");
        +     } catch (IOException ioe) {
        +         // not good
        +     }
        + }

        +

        Alternative rule: java:S108

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + allowCommentedBlocks + + false + BOOLEAN + + + allowExceptionNameRegex + + ^(ignored|expected)$ + STRING + +
        + + EmptyControlStatement + Empty control statement + category/java/codestyle.xml/EmptyControlStatement + MINOR + Title of issues: This control statement has an empty branch +

        Reports control statements whose body is empty, as well as empty initializers.

        +

        The checked code constructs are the following:

        +
        • bodies of try statements
        • finally clauses of try statements
        • switch statements
        • synchronized statements
        • if statements
        • loop statements: while, for, do .. while
        • initializers
        • blocks used as statements (for scoping)
        +

        This rule replaces the rules EmptyFinallyBlock, + EmptyIfStmt, EmptyInitializer, EmptyStatementBlock, + EmptySwitchStatements, EmptySynchronizedBlock, EmptyTryBlock, and EmptyWhileStmt.

        +

        Notice that {% rule java/errorprone/EmptyCatchBlock %} is still an independent rule.

        +

        EmptyStatementNotInLoop is replaced by {% rule java/codestyle/UnnecessarySemicolon %}.

        +

        Example

        +

         class Foo {
        +     {
        +         if (true); // empty if statement
        +         if (true) { // empty as well
        +         }
        +     }
        + 
        +     {} // empty initializer
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + allowCommentedBlocks + + false + BOOLEAN + +
        + + EmptyFinalizer + Empty finalizer + category/java/errorprone.xml/EmptyFinalizer + MAJOR + Title of issues: Avoid empty finalize methods +

        Empty finalize methods serve no purpose and should be removed. Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

        +

        Example

        +

         public class Foo {
        +    protected void finalize() {}
        + }

        +

        Alternative rule: java:S1186

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + EmptyMethodInAbstractClassShouldBeAbstract + Empty method in abstract class should be abstract + category/java/codestyle.xml/EmptyMethodInAbstractClassShouldBeAbstract + MAJOR + Title of issues: An empty method in an abstract class should be abstract instead +

        Empty or auto-generated methods in an abstract class should be tagged as abstract. This helps to remove their inappropriate +usage by developers who should be implementing their own versions in the concrete subclasses.

        +

        Example

        +

         public abstract class ShouldBeAbstract {
        +     public Object couldBeAbstract() {
        +         // Should be abstract method ?
        +         return null;
        +     }
        + 
        +     public void couldBeAbstract() {
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + EqualsNull + Equals null + category/java/errorprone.xml/EqualsNull + BLOCKER + Title of issues: Avoid using equals() to compare against null +

        Tests for null should not use the equals() method. The '==' operator should be used instead.

        +

        Example

        +

         String x = "foo";
        + 
        + if (x.equals(null)) {   // bad form
        +     doSomething();
        + }
        + 
        + if (x == null) {        // preferred
        +     doSomething();
        + }

        +

        Alternative rule: java:S2159

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + ExceptionAsFlowControl + Exception as flow control + category/java/design.xml/ExceptionAsFlowControl + MAJOR + Title of issues: Exception thrown at line {0} is caught in this block. +

        This rule reports exceptions thrown and caught in an enclosing try statement. +This use of exceptions as a form of goto statement is discouraged, as that may +hide actual exceptions, and obscures control flow, especially when debugging. +To fix a violation, add the necessary validation or use an alternate control structure.

        +

        Example

        +

         public void bar() {
        +     try {
        +         try {
        +         } catch (Exception e) {
        +             throw new WrapperException(e);
        +             // this is essentially a GOTO to the WrapperException catch block
        +         }
        +     } catch (WrapperException e) {
        +         // do some more stuff
        +     }
        + }

        +

        Alternative rule: java:S1141

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + ExcessiveImports + Excessive imports + category/java/design.xml/ExcessiveImports + MAJOR + Title of issues: A high number of imports can indicate a high degree of coupling within an object. +

        A high number of imports can indicate a high degree of coupling within an object. This rule +counts the number of unique imports and reports a violation if the count is above the +user-specified threshold.

        +

        Example

        +

         import blah.blah.Baz;
        + import blah.blah.Bif;
        + // 28 others from the same package elided
        + public class Foo {
        +     public void doWork() {}
        + }

        +

        Alternative rule: java:S1200

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + minimum + + 30 + INTEGER + +
        + + ExcessiveParameterList + Excessive parameter List + category/java/design.xml/ExcessiveParameterList + MAJOR + Title of issues: Avoid long parameter lists. +

        Methods with numerous parameters are a challenge to maintain, especially if most of them share the +same datatype. These situations usually denote the need for new objects to wrap the numerous parameters.

        +

        Example

        +

         public void addPerson(      // too many arguments liable to be mixed up
        +     int birthYear, int birthMonth, int birthDate, int height, int weight, int ssn) {
        + 
        +     . . . .
        + }
        + 
        + public void addPerson(      // preferred approach
        +     Date birthdate, BodyMeasurements measurements, int ssn) {
        + 
        +     . . . .
        + }

        +

        Alternative rule: java:S107

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + minimum + + 10 + INTEGER + +
        + + ExcessivePublicCount + Excessive public count + category/java/design.xml/ExcessivePublicCount + MAJOR + Title of issues: This class has a bunch of public methods and attributes +

        Classes with large numbers of public methods and attributes require disproportionate testing efforts +since combinational side effects grow rapidly and increase risk. Refactoring these classes into +smaller ones not only increases testability and reliability but also allows new variations to be +developed easily.

        +

        Example

        +

         public class Foo {
        +     public String value;
        +     public Bar something;
        +     public Variable var;
        +     // [... more more public attributes ...]
        + 
        +     public void doWork() {}
        +     public void doMoreWork() {}
        +     public void doWorkAgain() {}
        +     // [... more more public methods ...]
        + }

        +

        Alternative rule: java:S1448

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + minimum + + 45 + INTEGER + +
        + + ExhaustiveSwitchHasDefault + Exhaustive switch has default + category/java/bestpractices.xml/ExhaustiveSwitchHasDefault + MAJOR + Title of issues: The switch block is exhaustive even without the default case +

        When switching over an enum or sealed class, the compiler will ensure that all possible cases are covered. +If a case is missing, this will result in a compilation error. But if a default case is added, this compiler +check is not performed anymore, leading to difficulties in noticing bugs at runtime.

        +

        Not using a default case makes sure, a compiler error is introduced whenever a new enum constant or a +new subclass to the sealed class hierarchy is added. We will discover this problem at compile time +rather than at runtime (if at all).

        +

        Note: The fix it not necessarily just removing the default case. Maybe a case is missing which needs to be implemented.

        +

        Example

        +

         class Foo {
        +     enum MyEnum { A, B };
        + 
        +     void doSomething(MyEnum e) {
        +         switch(e) {
        +             case A -> System.out.println("a");
        +             case B -> System.out.println("b");
        +             default -> System.out.println("unnecessary default");
        +         };
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + ExtendsObject + Extends object + category/java/codestyle.xml/ExtendsObject + MINOR + Title of issues: No need to explicitly extend Object. +

        No need to explicitly extend Object.

        +

        Example

        +

         public class Foo extends Object {     // not required
        + }

        +

        Alternative rule: java:S1939

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative +
        + + FieldDeclarationsShouldBeAtStartOfClass + Field declarations should be at start of class + category/java/codestyle.xml/FieldDeclarationsShouldBeAtStartOfClass + MINOR + Title of issues: Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes. +

        Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes.

        +

        Example

        +

         public class HelloWorldBean {
        + 
        +   // Field declared before methods / inner classes - OK
        +   private String _thing;
        + 
        +   public String getMessage() {
        +     return "Hello World!";
        +   }
        + 
        +   // Field declared after methods / inner classes - avoid this
        +   private String _fieldInWrongLocation;
        + }

        +

        Alternative rule: java:S1213

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + ignoreAnonymousClassDeclarations + + true + BOOLEAN + + + ignoreInterfaceDeclarations + + false + BOOLEAN + + + ignoreEnumDeclarations + + true + BOOLEAN + +
        + + FieldNamingConventions + Field naming conventions + category/java/codestyle.xml/FieldNamingConventions + MAJOR + Title of issues: The {0} name '{1}' doesn't match '{2}' +

        Configurable naming conventions for field declarations. This rule reports variable declarations + which do not match the regex that applies to their specific kind ---e.g. constants (static final), + enum constant, final field. Each regex can be configured through properties.

        +

        By default this rule uses the standard Java naming convention (Camel case), and uses the ALL_UPPER + convention for constants and enum constants.

        +

        Example

        +

         class Foo {
        +                 int myField = 1; // This is in camel case, so it's ok
        +                 int my_Field = 1; // This contains an underscore, it's not ok by default
        +                                   // but you may allow it, or even require the "my_" prefix
        + 
        +                 final int FinalField = 1; // you may configure a different convention for final fields,
        +                                           // e.g. here PascalCase: [A-Z][a-zA-Z0-9]*
        + 
        +                 interface Interface {
        +                     double PI = 3.14; // interface "fields" use the constantPattern property
        +                 }
        + 
        +                 enum AnEnum {
        +                     ORG, NET, COM; // These use a separate property but are set to ALL_UPPER by default
        +                 }
        +             }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + publicConstantPattern + + [A-Z][A-Z_0-9]* + STRING + + + constantPattern + + [A-Z][A-Z_0-9]* + STRING + + + enumConstantPattern + + [A-Z][A-Z_0-9]* + STRING + + + finalFieldPattern + + [a-z][a-zA-Z0-9]* + STRING + + + staticFieldPattern + + [a-z][a-zA-Z0-9]* + STRING + + + defaultFieldPattern + + [a-z][a-zA-Z0-9]* + STRING + + + exclusions + + serialVersionUID,serialPersistentFields + STRING + + + violationSuppressRegex + + + STRING + +
        + + FinalFieldCouldBeStatic + Final field could be static + category/java/design.xml/FinalFieldCouldBeStatic + MAJOR + Title of issues: The final field {0} could be made static +

        If a final field is assigned to a compile-time constant, it could be made static, thus saving overhead +in each object at runtime.

        +

        Example

        +

         public class Foo {
        +   public final int BAR = 42; // this could be static and save some space
        + }

        +

        Alternative rule: java:S1170

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + FinalParameterInAbstractMethod + Final parameter in abstract method + category/java/codestyle.xml/FinalParameterInAbstractMethod + MAJOR + Title of issues: Final parameter in abstract method +

        Declaring a method parameter as final for an interface method is useless because the implementation may choose to not respect it.

        +

        Example

        +

         public interface MyInterface {
        +   void process(final Object arg); // Avoid using final here
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + FinalizeDoesNotCallSuperFinalize + Finalize does not call super finalize + category/java/errorprone.xml/FinalizeDoesNotCallSuperFinalize + MAJOR + Title of issues: Last statement in finalize method should be a call to super.finalize() +

        If the finalize() is implemented, its last action should be to call super.finalize. Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

        +

        Example

        +

         protected void finalize() {
        +     something();
        +     // neglected to call super.finalize()
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + FinalizeOnlyCallsSuperFinalize + Finalize only calls super finalize + category/java/errorprone.xml/FinalizeOnlyCallsSuperFinalize + MAJOR + Title of issues: Finalize should do something besides just calling super.finalize() +

        If the finalize() is implemented, it should do something besides just calling super.finalize(). Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

        +

        Example

        +

         protected void finalize() {
        +     super.finalize();
        + }

        +

        Alternative rule: java:S1185

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + FinalizeOverloaded + Finalize overloaded + category/java/errorprone.xml/FinalizeOverloaded + MAJOR + Title of issues: Finalize methods should not be overloaded +

        Methods named finalize() should not have parameters. It is confusing and most likely an attempt to +overload Object.finalize(). It will not be called by the VM.

        +

        Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

        +

        Example

        +

         public class Foo {
        +     // this is confusing and probably a bug
        +     protected void finalize(int a) {
        +     }
        + }

        +

        Alternative rule: java:S1175

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + FinalizeShouldBeProtected + Finalize should be protected + category/java/errorprone.xml/FinalizeShouldBeProtected + MAJOR + Title of issues: If you override finalize(), make it protected +

        When overriding the finalize(), the new method should be set as protected. If made public, +other classes may invoke it at inappropriate times.

        +

        Note that Oracle has declared Object.finalize() as deprecated since JDK 9.

        +

        Example

        +

         public void finalize() {
        +     // do something
        + }

        +

        Alternative rule: java:S1174

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + ForLoopCanBeForeach + For loop can be foreach + category/java/bestpractices.xml/ForLoopCanBeForeach + MAJOR + Title of issues: This 'for' loop can be replaced by a 'foreach' loop +

        Reports loops that can be safely replaced with the foreach syntax. The rule considers loops over +lists, arrays and iterators. A loop is safe to replace if it only uses the index variable to +access an element of the list or array, only has one update statement, and loops through every +element of the list or array left to right.

        +

        Example

        +

         public class MyClass {
        +   void loop(List<String> l) {
        +     for (int i = 0; i < l.size(); i++) { // pre Java 1.5
        +       System.out.println(l.get(i));
        +     }
        + 
        +     for (String s : l) {        // post Java 1.5
        +       System.out.println(s);
        +     }
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + ForLoopShouldBeWhileLoop + For loop should be while loop + category/java/codestyle.xml/ForLoopShouldBeWhileLoop + MINOR + Title of issues: This for loop could be simplified to a while loop +

        Some for loops can be simplified to while loops, this makes them more concise.

        +

        Example

        +

         public class Foo {
        +     void bar() {
        +         for (;true;) true; // No Init or Update part, may as well be: while (true)
        +     }
        + }

        +

        Alternative rule: java:S1264

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative +
        + + ForLoopVariableCount + For loop variable count + category/java/bestpractices.xml/ForLoopVariableCount + MAJOR + Title of issues: Too many control variables in the 'for' statement +

        Having a lot of control variables in a 'for' loop makes it harder to see what range of values +the loop iterates over. By default this rule allows a regular 'for' loop with only one variable.

        +

        Example

        +

         // this will be reported with the default setting of at most one control variable in a for loop
        + for (int i = 0, j = 0; i < 10; i++, j += 2) {
        +    foo();

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + maximumVariables + + 1 + INTEGER + +
        + + FormalParameterNamingConventions + Formal parameter naming conventions + category/java/codestyle.xml/FormalParameterNamingConventions + MAJOR + Title of issues: The {0} name '{1}' doesn't match '{2}' +

        Configurable naming conventions for formal parameters of methods and lambdas. + This rule reports formal parameters which do not match the regex that applies to their + specific kind (e.g. lambda parameter, or final formal parameter). Each regex can be + configured through properties.

        +

        By default this rule uses the standard Java naming convention (Camel case).

        +

        Example

        +

         class Foo {
        + 
        +                 abstract void bar(int myInt); // This is Camel case, so it's ok
        + 
        +                 void bar(int my_i) { // this will be reported
        + 
        +                 }
        + 
        +                 void lambdas() {
        + 
        +                     // lambdas parameters can be configured separately
        +                     Consumer<String> lambda1 = s_str -> { };
        + 
        +                     // lambda parameters with an explicit type can be configured separately
        +                     Consumer<String> lambda1 = (String str) -> { };
        + 
        +                 }
        + 
        +             }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + methodParameterPattern + + [a-z][a-zA-Z0-9]* + STRING + + + finalMethodParameterPattern + + [a-z][a-zA-Z0-9]* + STRING + + + lambdaParameterPattern + + [a-z][a-zA-Z0-9]* + STRING + + + explicitLambdaParameterPattern + + [a-z][a-zA-Z0-9]* + STRING + + + violationSuppressRegex + + + STRING + +
        + + GenericsNaming + Generics naming + category/java/codestyle.xml/GenericsNaming + MINOR + Title of issues: Generics names should be a one letter long and upper case. +

        Names for references to generic values should be limited to a single uppercase letter.

        +

        Deprecated: This rule is deprecated since PMD 7.17.0 and will be removed with PMD 8.0.0. This rule has been replaced by {% rule TypeParameterNamingConventions %}, which provides more comprehensive and configurable naming conventions for type parameters.

        +

        Example

        +

         public interface GenericDao<E extends BaseModel, K extends Serializable> extends BaseDao {
        +     // This is ok...
        + }
        + 
        + public interface GenericDao<E extends BaseModel, K extends Serializable> {
        +     // Also this
        + }
        + 
        + public interface GenericDao<e extends BaseModel, K extends Serializable> {
        +     // 'e' should be an 'E'
        + }
        + 
        + public interface GenericDao<EF extends BaseModel, K extends Serializable> {
        +    // 'EF' is not ok.
        + }

        +

        Alternative rule: java:S119

        +

        Full documentation

        ]]>
        + DEPRECATED + pmd + codestyle + has-sonar-alternative +
        + + GodClass + God class + category/java/design.xml/GodClass + MAJOR + Title of issues: Possible God Class (WMC={0}, ATFD={2}, TCC={1}) +

        The God Class rule detects the God Class design flaw using metrics. God classes do too many things, +are very big and overly complex. They should be split apart to be more object-oriented. +The rule uses the detection strategy described in "Object-Oriented Metrics in Practice". +The violations are reported against the entire class.

        +

        The rule uses metrics to implement its detection strategy. The violation message gives information about the values of these metrics:

        + +

        The rule identifies a god class by looking for classes which have all of the following properties:

        +
        • High WMC
        • High ATFD
        • Low TCC
        +

        See also the reference:

        +

        Michele Lanza and Radu Marinescu. Object-Oriented Metrics in Practice: +Using Software Metrics to Characterize, Evaluate, and Improve the Design +of Object-Oriented Systems. Springer, Berlin, 1 edition, October 2006. Page 80.

        +

        Full documentation

        ]]>
        + pmd + design + + violationSuppressRegex + + + STRING + +
        + + GuardLogStatement + Guard log statement + category/java/bestpractices.xml/GuardLogStatement + CRITICAL + Title of issues: Logger calls should be surrounded by log level guards. +

        Whenever using a log level, one should check if it is actually enabled, or +otherwise skip the associate String creation and manipulation, as well as any method calls.

        +

        An alternative to checking the log level are substituting parameters, formatters or lazy logging +with lambdas. The available alternatives depend on the actual logging framework.

        +

        Example

        +

         // Add this for performance - avoid manipulating strings if the logger may drop it
        + if (log.isDebugEnabled()) {
        +     log.debug("log something" + param1 + " and " + param2 + "concat strings");
        + }
        + 
        + // Avoid the guarding if statement with substituting parameters
        + log.debug("log something {} and {}", param1, param2);
        + 
        + // Avoid the guarding if statement with formatters
        + log.debug("log something %s and %s", param1, param2);
        + 
        + // This is still an issue, method invocations may be expensive / have side-effects
        + log.debug("log something expensive: {}", calculateExpensiveLoggingText());
        + 
        + // Avoid the guarding if statement with lazy logging and lambdas
        + log.debug("log something expensive: {}", () -> calculateExpensiveLoggingText());
        + 
        + // … alternatively use method references
        + log.debug("log something expensive: {}", this::calculateExpensiveLoggingText);

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + logLevels + + trace,debug,info,warn,error,log,finest,finer,fine,info,warning,severe + STRING + + + guardsMethods + + isTraceEnabled,isDebugEnabled,isInfoEnabled,isWarnEnabled,isErrorEnabled,isLoggable + STRING + +
        + + HardCodedCryptoKey + Hard coded crypto key + category/java/security.xml/HardCodedCryptoKey + MAJOR + Title of issues: Do not use hard coded encryption keys +

        Do not use hard coded values for cryptographic operations. Please store keys outside of source code.

        +

        Example

        +

         public class Foo {
        +     void good() {
        +         SecretKeySpec secretKeySpec = new SecretKeySpec(Properties.getKey(), "AES");
        +     }
        + 
        +     void bad() {
        +         SecretKeySpec secretKeySpec = new SecretKeySpec("my secret here".getBytes(), "AES");
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + security +
        + + IdempotentOperations + Idempotent operations + category/java/errorprone.xml/IdempotentOperations + MAJOR + Title of issues: Avoid idempotent operations (like assigning a variable to itself). +

        Avoid idempotent operations - they have no effect.

        +

        Example

        +

         public class Foo {
        +  public void bar() {
        +   int x = 2;
        +   x = x;
        +  }
        + }

        +

        Alternative rule: java:S1656

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + IdenticalCatchBranches + Identical catch branches + category/java/codestyle.xml/IdenticalCatchBranches + MINOR + Title of issues: 'catch' branch identical to '{0}' branch +

        Identical catch branches use up vertical space and increase the complexity of code without + adding functionality. It's better style to collapse identical branches into a single multi-catch + branch.

        +

        Example

        +

         try {
        +     // do something
        + } catch (IllegalArgumentException e) {
        +     throw e;
        + } catch (IllegalStateException e) { // Can be collapsed into the previous block
        +     throw e;
        + }
        + 
        + try {
        +     // do something
        + } catch (IllegalArgumentException | IllegalStateException e) { // This is better
        +     throw e;
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + violationSuppressRegex + + + STRING + +
        + + ImmutableField + Immutable field + category/java/design.xml/ImmutableField + MAJOR + Title of issues: Field '{0}' may be declared final +

        Reports non-final fields whose value never changes once object initialization ends, +and hence may be marked final.

        +

        Note that this rule does not enforce that the field value be deeply immutable itself. +An object can still have mutable state, even if all its member fields are declared final. +This is referred to as shallow immutability. For more information on mutability, +see Effective Java, 3rd Edition, Item 17: Minimize mutability.

        +

        Limitations: We can only check private fields for now.

        +

        Example

        +

         public class Foo {
        +   private int x; // could be final
        +   public Foo() {
        +       x = 7;
        +   }
        +   public void foo() {
        +      int a = x + 2;
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + design + + violationSuppressRegex + + + STRING + +
        + + ImplicitFunctionalInterface + Implicit functional interface + category/java/bestpractices.xml/ImplicitFunctionalInterface + CRITICAL + Title of issues: Annotate this interface with @FunctionalInterface or with @SuppressWarnings("PMD.ImplicitFunctionalInterface") to clarify your intent. +

        Reports functional interfaces that were not explicitly declared as such with + the annotation @FunctionalInterface. If an interface is accidentally a functional + interface, then it should bear a @SuppressWarnings("PMD.ImplicitFunctionalInterface") + annotation to make this clear.

        +

        Example

        +

         // The intent on this declaration is unclear, and the rule will report it.
        +             public interface MyInterface {
        +                 void doSomething();
        +             }
        + 
        +             // This is clearly intended as a functional interface.
        +             @FunctionalInterface
        +             public interface MyInterface {
        +                 void doSomething();
        +             }
        + 
        +             // This is clearly NOT intended as a functional interface.
        +             @SuppressWarnings("PMD.ImplicitFunctionalInterface")
        +             public interface MyInterface {
        +                 void doSomething();
        +             }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + ImplicitSwitchFallThrough + Implicit switch fall through + category/java/errorprone.xml/ImplicitSwitchFallThrough + MAJOR + Title of issues: This switch case may be reached by fallthrough from the previous case +

        Switch statements without break or return statements for each case option +may indicate problematic behaviour. Empty cases are ignored as these indicate +an intentional fall-through.

        +

        You can ignore a violation by commenting // fallthrough before the case label +which is reached by fallthrough, or with @SuppressWarnings("fallthrough").

        +

        This rule has been renamed from "MissingBreakInSwitch" in PMD 6.37.0.

        +

        Example

        +

         public void bar(int status) {
        +     switch(status) {
        +       case CANCELLED:
        +         doCancelled();
        +         // break; hm, should this be commented out?
        +       case NEW:
        +         doNew();
        +         // is this really a fall-through?
        +         // what happens if you add another case after this one?
        +       case REMOVED:
        +         doRemoved();
        +         // fallthrough - this comment just clarifies that you want a fallthrough
        +       case OTHER: // empty case - this is interpreted as an intentional fall-through
        +       case ERROR:
        +         doErrorHandling();
        +         break;
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + InefficientEmptyStringCheck + Inefficient empty string check + category/java/performance.xml/InefficientEmptyStringCheck + MAJOR + Title of issues: String.trim().length() == 0 / String.trim().isEmpty() is an inefficient way to validate a blank String. +

        String.trim().length() == 0 (or String.trim().isEmpty() for the same reason) is an inefficient +way to check if a String is really blank, as it creates a new String object just to check its size. +Consider creating a static function that loops through a string, checking Character.isWhitespace() +on each character and returning false if a non-whitespace character is found. A Smarter code to +check for an empty string would be:

        +

         private boolean checkTrimEmpty(String str) {
        +     for(int i = 0; i < str.length(); i++) {
        +         if(!Character.isWhitespace(str.charAt(i))) {
        +             return false;
        +         }
        +     }
        +     return true;
        + }

        +

        You can refer to Apache's StringUtils#isBlank (in commons-lang), +Spring's StringUtils#hasText (in the Spring framework) or Google's +CharMatcher#whitespace (in Guava) for existing implementations (some might +include the check for != null).

        +

        Example

        +

         public void bar(String string) {
        +     if (string != null && string.trim().length() > 0) {
        +         doSomething();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + InefficientStringBuffering + Inefficient string buffering + category/java/performance.xml/InefficientStringBuffering + MAJOR + Title of issues: Avoid concatenating nonliterals in a StringBuffer/StringBuilder constructor or append(). +

        Avoid concatenating non-literals in a StringBuffer constructor or append() since intermediate buffers will +need to be be created and destroyed by the JVM.

        +

        Example

        +

         // Avoid this, two buffers are actually being created here
        + StringBuffer sb = new StringBuffer("tmp = "+System.getProperty("java.io.tmpdir"));
        + 
        + // do this instead
        + StringBuffer sb = new StringBuffer("tmp = ");
        + sb.append(System.getProperty("java.io.tmpdir"));

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + InsecureCryptoIv + Insecure crypto IV + category/java/security.xml/InsecureCryptoIv + MAJOR + Title of issues: Do not use hard coded initialization vector in crypto operations +

        Do not use hard coded initialization vector in cryptographic operations. Please use a randomly generated IV.

        +

        Example

        +

         public class Foo {
        +     void good() {
        +         SecureRandom random = new SecureRandom();
        +         byte iv[] = new byte[16];
        +         random.nextBytes(bytes);
        +     }
        + 
        +     void bad() {
        +         byte[] iv = new byte[] { 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, };
        +     }
        + 
        +     void alsoBad() {
        +         byte[] iv = "secret iv in here".getBytes();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + security +
        + + InstantiationToGetClass + Instantiation to get class + category/java/errorprone.xml/InstantiationToGetClass + MINOR + Title of issues: Avoid instantiating an object just to call getClass() on it; use the .class public member instead +

        Avoid instantiating an object just to call getClass() on it; use the .class public member instead.

        +

        Example

        +

         // replace this
        + Class c = new String().getClass();
        + 
        + // with this:
        + Class c = String.class;

        +

        Alternative rule: java:S2133

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + InsufficientStringBufferDeclaration + Insufficient StringBuffer declaration + category/java/performance.xml/InsufficientStringBufferDeclaration + MAJOR + Title of issues: {0} has been initialized with size {1}, but has at least {2} characters appended. +

        Failing to pre-size a StringBuffer or StringBuilder properly could cause it to re-size many times +during runtime. This rule attempts to determine the total number the characters that are actually +passed into StringBuffer.append(), but represents a best guess "worst case" scenario. An empty +StringBuffer/StringBuilder constructor initializes the object to 16 characters. This default +is assumed if the length of the constructor can not be determined.

        +

        Example

        +

         StringBuilder bad = new StringBuilder();
        + bad.append("This is a long string that will exceed the default 16 characters");
        + 
        + StringBuilder good = new StringBuilder(41);
        + good.append("This is a long string, which is pre-sized");

        +

        Full documentation

        ]]>
        + pmd + performance + + violationSuppressRegex + + + STRING + +
        + + InvalidJavaBean + Invalid Java bean + category/java/design.xml/InvalidJavaBean + MAJOR + Title of issues: The bean '{0}' is missing a getter for property '{1}'. +

        Identifies beans, that don't follow the JavaBeans API specification.

        +

        Each non-static field should have both a getter and a setter method. If the field is just used internally and is not +a bean property, then the field should be marked as transient.

        +

        The rule verifies that the type of the field is the same as the result type of the getter. And that this type matches +the type used in the setter.

        +

        The rule also checks, that there is a no-arg or default constructor available.

        +

        Optionally the rule also verifies, that the bean implements java.io.Serializable. While this is a requirement for the +original JavaBeans specification, frameworks nowadays don't strictly require this anymore.

        +

        In order to avoid many false positives in classes that are not beans, the rule needs to be explicitly +enabled by configuring the property packages.

        +

        Example

        +

         package org.example.beans;
        + public class MyBean {        // <-- bean is not serializable, missing "implements Serializable"
        +     private String label;    // <-- missing setter for property "label"
        + 
        +     public String getLabel() {
        +         return label;
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + design + + ensureSerialization + + false + BOOLEAN + + + packages + + org.example.beans + STRING + + + violationSuppressRegex + + + STRING + +
        + + InvalidLogMessageFormat + Invalid log message format + category/java/errorprone.xml/InvalidLogMessageFormat + MINOR + Title of issues: Invalid message format +

        Check for messages in slf4j and log4j2 (since 6.19.0) loggers with non matching number of arguments and placeholders.

        +

        Since 6.32.0 in addition to parameterized message placeholders ({}) also format specifiers of string formatted +messages are supported (%s).

        +

        This rule has been renamed from "InvalidSlf4jMessageFormat" in PMD 6.19.0.

        +

        Example

        +

         LOGGER.error("forget the arg {}");
        + LOGGER.error("forget the arg %s");
        + LOGGER.error("too many args {}", "arg1", "arg2");
        + LOGGER.error("param {}", "arg1", new IllegalStateException("arg")); //The exception is shown separately, so is correct.

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + JUnit4SuitesShouldUseSuiteAnnotation + JUnit4 suites should use suite annotation + category/java/bestpractices.xml/JUnit4SuitesShouldUseSuiteAnnotation + MAJOR + Title of issues: JUnit 4 indicates test suites via annotations, not the suite method. +

        In JUnit 3, test suites are indicated by the suite() method. In JUnit 4, suites are indicated +through the @RunWith(Suite.class) annotation.

        +

        Example

        +

         public class BadExample extends TestCase{
        + 
        +     public static Test suite(){
        +         return new Suite();
        +     }
        + }
        + 
        + @RunWith(Suite.class)
        + @SuiteClasses( { TestOne.class, TestTwo.class })
        + public class GoodTest {
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + JUnit5TestShouldBePackagePrivate + JUnit5 test should be package private + category/java/bestpractices.xml/JUnit5TestShouldBePackagePrivate + MAJOR + Title of issues: JUnit 5 tests should be package-private. +

        Reports JUnit 5 test classes and methods that are not package-private. +Contrary to JUnit 4 tests, which required public visibility to be run by the engine, +JUnit 5 tests can also be run if they're package-private. Marking them as such +is a good practice to limit their visibility.

        +

        Test methods are identified as those which use @Test, @RepeatedTest, +@TestFactory, @TestTemplate or @ParameterizedTest.

        +

        Example

        +

         class MyTest { // not public, that's fine
        +     @Test
        +     public void testBad() { } // should not have a public modifier
        + 
        +     @Test
        +     protected void testAlsoBad() { } // should not have a protected modifier
        + 
        +     @Test
        +     private void testNoRun() { } // should not have a private modifier
        + 
        +     @Test
        +     void testGood() { } // package private as expected
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + JUnitSpelling + JUnit spelling + category/java/errorprone.xml/JUnitSpelling + MAJOR + Title of issues: You may have misspelled a JUnit framework method (setUp or tearDown) +

        In JUnit 3, the setUp method is used to set up all data entities required in running tests. + The tearDown method is used to clean up all data entities required in running tests. + You should not misspell method name if you want your test to set up and clean up everything correctly.

        +

        Example

        +

         import junit.framework.*;
        + 
        + public class Foo extends TestCase {
        +     public void setup() {}    // oops, should be setUp
        +     public void TearDown() {} // oops, should be tearDown
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + JUnitStaticSuite + JUnit static suite + category/java/errorprone.xml/JUnitStaticSuite + MAJOR + Title of issues: You have a suite() method that is not both public and static, so JUnit won't call it to get your TestSuite. Is that what you wanted to do? +

        The suite() method in a JUnit test needs to be both public and static.

        +

        Examples

        +

        Example 1

        +

         import junit.framework.*;
        + 
        + public class Foo extends TestCase {
        +     public void suite() {}         // oops, should be static
        + }

        +

        Example 2

        +

         import junit.framework.*;
        + 
        + public class Foo extends TestCase {
        +     private static void suite() {} // oops, should be public
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + JUnitUseExpected + JUnit use expected + category/java/bestpractices.xml/JUnitUseExpected + MAJOR + Title of issues: In JUnit4, use the @Test(expected) annotation to denote tests that should throw exceptions +

        In JUnit4, use the @Test(expected) annotation to denote tests that should throw exceptions.

        +

        Example

        +

         public class MyTest {
        +     @Test
        +     public void testBad() {
        +         try {
        +             doSomething();
        +             fail("should have thrown an exception");
        +         } catch (Exception e) {
        +         }
        +     }
        + 
        +     @Test(expected=Exception.class)
        +     public void testGood() {
        +         doSomething();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + JumbledIncrementer + Jumbled incrementer + category/java/errorprone.xml/JumbledIncrementer + MAJOR + Title of issues: Avoid modifying an outer loop incrementer in an inner loop for update expression +

        Avoid jumbled loop incrementers - it's usually a mistake, and is confusing even if intentional.

        +

        Example

        +

         public class JumbledIncrementerRule1 {
        +     public void foo() {
        +         for (int i = 0; i < 10; i++) {          // only references 'i'
        +             for (int k = 0; k < 20; i++) {      // references both 'i' and 'k'
        +                 System.out.println("Hello");
        +             }
        +         }
        +     }
        + }

        +

        Alternative rule: java:S1994

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + LambdaCanBeMethodReference + Lambda can be method reference + category/java/codestyle.xml/LambdaCanBeMethodReference + MINOR + Title of issues: Lambda expression could be written as a method reference: {0} +

        This rule reports lambda expressions that can be written more succinctly as a method reference. This is the case if the lambda is an expression lambda that only calls one method, passing the entire lambda parameter list in order to the method. For instance: +

         x -> Foo.call(x) // can be Foo::call
        +                 x -> call(x)     // can be this::call, if call is an instance method
        +                 (x, y, z) -> call(x, y, z) // can be this::call
        +                 () -> foo.get() // can be foo::get
        +                 x -> x.foo()    // can be XType::foo (where XType is the type of x)

        +

        In some cases rewriting a lambda to a method reference can change the semantics of the code. For instance in (x) -> someVar.call(x), the invocation of the lambda may produce a NullPointerException (NPE) if someVar is null. The method reference someVar::call will also NPE if someVar is null, but it will do so at the point the method reference is created, while the lambda is created without error and its NPE is only thrown if the lambda is invoked (which may be never). Code should probably not rely on this subtle semantic difference, therefore these potentially problematic lambdas are also reported by default. This behavior can be disabled by setting the property ignoreIfMayNPE to true.

        +

        The property ignoreIfMayNPE is true by default. By default, calls whose receiver is itself a method call are ignored, because they could cause side effects. This may be changed by setting the property ignoreIfReceiverIsMethod to false.

        +

        Scope limitations:

        +
        • This rule will not report lambdas of the form x -> new CtorCall().something(x), because the semantics of the method reference would be to create a single new object, while the lambda creates one object per invocation.
        • The rule cannot know if the qualifier of a method call performs side effects. This means (x) -> sideEffectingMethod().foo(x) will be reported. Suppress the warning in this case.
        +

        Example

        +

         import java.util.stream.Stream;
        + 
        +             public class LambdaCanBeMethodReference {
        +                 static {
        +                     Stream.of("abc", "d")
        +                             .mapToInt(s -> s.length()) // could be String::length
        +                             .reduce((x, y) -> Integer.sum(x, y)) // could be Integer::sum
        +                             .getAsInt();
        +                 }
        +             }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + ignoreIfMayNPE + + false + BOOLEAN + + + ignoreIfReceiverIsMethod + + true + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + LawOfDemeter + Law of demeter + category/java/design.xml/LawOfDemeter + MAJOR + Title of issues: Potential violation of the law of Demeter ({0}) +

        The law of Demeter is a simple rule that says "only talk to friends". It forbids +fetching data from "too far away", for some definition of distance, in order to +reduce coupling between classes or objects of different levels of abstraction.

        +

        The rule uses a notion of "degree", that quantifies how "far" an object is. Expressions with too high degree can only be used in certain ways. The degree of an expression is defined inductively:

        +
        • The degree of this is 0
        • The degree of a method parameter is 1
        • The degree of a new object created in a method is 1
        • The degree of a static variable is 1
        • The degree of a field access expression like expr.field is the degree of expr plus 1
        • The degree of a "getter expression" like expr.getFoo() is the degree of expr plus 1
        • The degree of a "transformation expression" like expr.withFoo("") is the degree of expr
        • The degree of a variable is the maximum degree of all the assignments that reach it
        +

        Intuitively, the more you call getters, the more the degree increases. Eventually +the degree reaches the report threshold (property trustRadius) and the expression +is reported. The details of the calculation are more involved and make room for common +patterns, like usage of collections (objects that are in a list or array have the +same degree as their container), the builder pattern, and getters that do not appear +to break a boundary of abstraction.

        +

        Be aware that this rule is prone to many false-positives and low-priority warnings. You can increase the trustRadius property to reduce them drastically. The default trustRadius of 1 corresponds to the original law of Demeter (you're only allowed one getter call on untrusted values). Given some trustRadius value:

        +
        • expressions of degree lower or equal to trustRadius are not reported
        • expressions of degree exactly trustRadius + 1 are reported, unless they are only returned from the current method, or passed as argument to another method. Without this exception it
        • values of degree strictly greater than trustRadius + 1 are not reported. The intuition is that to obtain a value of degree n > 1 then you must use an expression
        +

        See also the references:

        + +

        Example

        +

         public class Foo {
        +     /**
        +      * This example will result in one violation.
        +      */
        +     public void example(Bar b) { // b has degree 1
        +         // `b.getC()` has degree 2, it's breaking a boundary of abstraction and so is reported.
        +         b.getC().doIt();
        +         // To respect the law of Demeter, Bar should encapsulate its
        +         // C member more properly, eg by exposing a method like this:
        +         b.callDoItOnC();
        + 
        +         // a constructor call, not a method call.
        +         D d = new D();
        +         // this method call is ok, because we have create the new
        +         // instance of D locally.
        +         d.doSomethingElse();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + design + + trustRadius + + 1 + INTEGER + + + violationSuppressRegex + + + STRING + +
        + + LinguisticNaming + Linguistic naming + category/java/codestyle.xml/LinguisticNaming + MINOR + Title of issues: Linguistics Antipattern - Method name and return type is inconsistent linguistically +

        This rule finds Linguistic Naming Antipatterns. It checks for fields, that are named, as if they should + be boolean but have a different type. It also checks for methods, that according to their name, should + return a boolean, but don't. Further, it checks, that getters return something and setters won't. + Finally, it checks that methods, that start with "to" - so called transform methods - actually return + something, since according to their name, they should convert or transform one object into another. + There is additionally an option, to check for methods that contain "To" in their name - which are + also transform methods. However, this is disabled by default, since this detection is prone to + false positives.

        +

        For more information, see Linguistic Antipatterns - What They Are and How +Developers Perceive Them.

        +

        Example

        +

         public class LinguisticNaming {
        +     int isValid;    // the field name indicates a boolean, but it is an int.
        +     boolean isTrue; // correct type of the field
        + 
        +     void myMethod() {
        +         int hasMoneyLocal;      // the local variable name indicates a boolean, but it is an int.
        +         boolean hasSalaryLocal; // correct naming and type
        +     }
        + 
        +     // the name of the method indicates, it is a boolean, but the method returns an int.
        +     int isValid() {
        +         return 1;
        +     }
        +     // correct naming and return type
        +     boolean isSmall() {
        +         return true;
        +     }
        + 
        +     // the name indicates, this is a setter, but it returns something
        +     int setName() {
        +         return 1;
        +     }
        + 
        +     // the name indicates, this is a getter, but it doesn't return anything
        +     void getName() {
        +         // nothing to return?
        +     }
        + 
        +     // the name indicates, it transforms an object and should return the result
        +     void toDataType() {
        +         // nothing to return?
        +     }
        +     // the name indicates, it transforms an object and should return the result
        +     void grapeToWine() {
        +         // nothing to return?
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + ignoredAnnotations + + java.lang.Override + STRING + + + checkBooleanMethod + + true + BOOLEAN + + + checkGetters + + true + BOOLEAN + + + checkSetters + + true + BOOLEAN + + + checkPrefixedTransformMethods + + true + BOOLEAN + + + checkTransformMethods + + false + BOOLEAN + + + booleanMethodPrefixes + + is,has,can,have,will,should + STRING + + + transformMethodNames + + to,as + STRING + + + checkFields + + true + BOOLEAN + + + checkVariables + + true + BOOLEAN + + + booleanFieldPrefixes + + is,has,can,have,will,should + STRING + +
        + + LiteralsFirstInComparisons + Literals first in comparisons + category/java/bestpractices.xml/LiteralsFirstInComparisons + MAJOR + Title of issues: Position literals first in String comparisons +

        Position literals first in all String comparisons, if the second argument is null then NullPointerExceptions + can be avoided, they will just return false. Note that switching literal positions for compareTo and + compareToIgnoreCase may change the result, see examples.

        +

        Note that compile-time constant strings are treated like literals. This is because they are inlined into + the class file, are necessarily non-null, and therefore cannot cause an NPE at runtime.

        +

        Example

        +

         class Foo {
        +     boolean bar(String x) {
        +         return x.equals("2"); // should be "2".equals(x)
        +     }
        +     boolean bar(String x) {
        +         return x.equalsIgnoreCase("2"); // should be "2".equalsIgnoreCase(x)
        +     }
        +     boolean bar(String x) {
        +         return (x.compareTo("bar") > 0); // should be: "bar".compareTo(x) < 0
        +     }
        +     boolean bar(String x) {
        +         return (x.compareToIgnoreCase("bar") > 0); // should be: "bar".compareToIgnoreCase(x) < 0
        +     }
        +     boolean bar(String x) {
        +         return x.contentEquals("bar"); // should be "bar".contentEquals(x)
        +     }
        + 
        +     static final String CONSTANT = "const";
        +     {
        +         CONSTANT.equals("literal"); // not reported, this is effectively the same as writing "const".equals("foo")
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + LocalHomeNamingConvention + Local home naming convention + category/java/codestyle.xml/LocalHomeNamingConvention + MINOR + Title of issues: The Local Home interface of a Session EJB should be suffixed by 'LocalHome' +

        The Local Home interface of a Session EJB should be suffixed by 'LocalHome'.

        +

        Example

        +

         public interface MyBeautifulLocalHome extends javax.ejb.EJBLocalHome {} // proper name
        + 
        + public interface MissingProperSuffix extends javax.ejb.EJBLocalHome {}  // non-standard name

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + LocalInterfaceSessionNamingConvention + Local interface session naming convention + category/java/codestyle.xml/LocalInterfaceSessionNamingConvention + MINOR + Title of issues: The Local Interface of a Session EJB should be suffixed by 'Local' +

        The Local Interface of a Session EJB should be suffixed by 'Local'.

        +

        Example

        +

         public interface MyLocal extends javax.ejb.EJBLocalObject {}                // proper name
        + 
        + public interface MissingProperSuffix extends javax.ejb.EJBLocalObject {}    // non-standard name

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + LocalVariableCouldBeFinal + Local variable could be final + category/java/codestyle.xml/LocalVariableCouldBeFinal + MINOR + Title of issues: Local variable '{0}' could be declared final +

        A local variable assigned only once can be declared final.

        +

        Example

        +

         public class Bar {
        +     public void foo () {
        +     String txtA = "a";          // if txtA will not be assigned again it is better to do this:
        +     final String txtB = "b";
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + ignoreForEachDecl + + false + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + LocalVariableNamingConventions + Local variable naming conventions + category/java/codestyle.xml/LocalVariableNamingConventions + MAJOR + Title of issues: The {0} name '{1}' doesn't match '{2}' +

        Configurable naming conventions for local variable declarations and other locally-scoped + variables. This rule reports variable declarations which do not match the regex that applies to their + specific kind (e.g. final variable, or catch-clause parameter). Each regex can be configured through + properties.

        +

        By default this rule uses the standard Java naming convention (Camel case).

        +

        Example

        +

         class Foo {
        +                 void bar() {
        +                     int localVariable = 1; // This is in camel case, so it's ok
        +                     int local_variable = 1; // This will be reported unless you change the regex
        + 
        +                     final int i_var = 1; // final local variables can be configured separately
        + 
        +                     try {
        +                         foo();
        +                     } catch (IllegalArgumentException e_illegal) {
        +                         // exception block parameters can be configured separately
        +                     }
        + 
        +                 }
        +             }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + localVarPattern + + [a-z][a-zA-Z0-9]* + STRING + + + finalVarPattern + + [a-z][a-zA-Z0-9]* + STRING + + + catchParameterPattern + + [a-z][a-zA-Z0-9]* + STRING + + + violationSuppressRegex + + + STRING + +
        + + LogicInversion + Logic inversion + category/java/design.xml/LogicInversion + MAJOR + Title of issues: Use opposite operator instead of the logic complement operator. +

        Use opposite operator instead of negating the whole expression with a logic complement operator.

        +

        Example

        +

         public boolean bar(int a, int b) {
        + 
        +     if (!(a == b)) { // use !=
        +          return false;
        +      }
        + 
        +     if (!(a < b)) { // use >=
        +          return false;
        +     }
        + 
        +     return true;
        + }

        +

        Alternative rule: java:S1940

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + LongVariable + Long variable + category/java/codestyle.xml/LongVariable + MINOR + Title of issues: Avoid excessively long variable names like {0} +

        Fields, formal arguments, or local variable names that are too long can make the code difficult to follow.

        +

        Example

        +

         public class Something {
        +     int reallyLongIntName = -3;             // VIOLATION - Field
        +     public static void main( String argumentsList[] ) { // VIOLATION - Formal
        +         int otherReallyLongName = -5;       // VIOLATION - Local
        +         for (int interestingIntIndex = 0;   // VIOLATION - For
        +              interestingIntIndex < 10;
        +              interestingIntIndex ++ ) {
        +     }
        + }

        +

        Alternative rule: java:S117

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + minimum + + 17 + INTEGER + + + violationSuppressRegex + + + STRING + +
        + + LooseCoupling + Loose coupling + category/java/bestpractices.xml/LooseCoupling + MAJOR + Title of issues: Avoid using implementation types like '{0}'; use the interface instead +

        Excessive coupling to implementation types (e.g., HashSet) limits your ability to use alternate +implementations in the future as requirements change. Whenever available, declare variables +and parameters using a more general type (e.g, Set).

        +

        This rule reports uses of concrete collection types. User-defined types that should be treated +the same as interfaces can be configured with the property allowedTypes.

        +

        Example

        +

         import java.util.ArrayList;
        + import java.util.HashSet;
        + 
        + public class Bar {
        +     // sub-optimal approach
        +     private ArrayList<SomeType> list = new ArrayList<>();
        + 
        +     public HashSet<SomeType> getFoo() {
        +         return new HashSet<SomeType>();
        +     }
        + 
        +     // preferred approach
        +     private List<SomeType> list = new ArrayList<>();
        + 
        +     public Set<SomeType> getFoo() {
        +         return new HashSet<SomeType>();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + allowedTypes + + java.util.Properties + STRING + + + violationSuppressRegex + + + STRING + +
        + + LoosePackageCoupling + Loose package coupling + category/java/design.xml/LoosePackageCoupling + MAJOR + Title of issues: Use of '{0}' outside of package hierarchy '{1}' is not recommended; use recommended classes instead +

        Avoid using classes from the configured package hierarchy outside of the package hierarchy, +except when using one of the configured allowed classes.

        +

        Example

        +

         package some.package;
        + 
        + import some.other.package.subpackage.subsubpackage.DontUseThisClass;
        + 
        + public class Bar {
        +     DontUseThisClass boo = new DontUseThisClass();
        + }

        +

        Full documentation

        ]]>
        + pmd + design + + packages + + + STRING + + + classes + + + STRING + + + violationSuppressRegex + + + STRING + +
        + + MDBAndSessionBeanNamingConvention + MDB and session bean naming convention + category/java/codestyle.xml/MDBAndSessionBeanNamingConvention + MINOR + Title of issues: SessionBean or MessageBean should be suffixed by Bean +

        The EJB Specification states that any MessageDrivenBean or SessionBean should be suffixed by 'Bean'.

        +

        Example

        +

         public class SomeBean implements SessionBean{}                  // proper name
        + 
        + public class MissingTheProperSuffix implements SessionBean {}   // non-standard name

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + MethodArgumentCouldBeFinal + Method argument could be final + category/java/codestyle.xml/MethodArgumentCouldBeFinal + MINOR + Title of issues: Parameter '{0}' is not assigned and could be declared final +

        Reports method and constructor parameters that can be made final because they are never reassigned within the body of the method.

        +

        This rule ignores unused parameters so as not to overlap with the rule {% rule java/bestpractices/UnusedFormalParameter %}. + It will also ignore the parameters of abstract methods.

        +

        Example

        +

         class Foo {
        +     // reported, parameter can be declared final
        +     public String foo1(String param) {
        +         return param;
        +     }
        +     // not reported, parameter is declared final
        +     public String foo2(final String param) {
        +         return param.trim();
        +     }
        +     // not reported because param is unused
        +     public String unusedParam(String param) {
        +         return "abc";
        +     }
        + }

        +

        Alternative rule: java:S1226

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + MethodNamingConventions + Method naming conventions + category/java/codestyle.xml/MethodNamingConventions + MAJOR + Title of issues: The {0} name '{1}' doesn't match '{2}' +

        Configurable naming conventions for method declarations. This rule reports + method declarations which do not match the regex that applies to their + specific kind (e.g. JUnit test or native method). Each regex can be + configured through properties.

        +

        By default, this rule uses the standard Java naming convention (Camel case).

        +

        Example

        +

         public class Foo {
        +     public void fooStuff() {
        +     }
        + }

        +

        Alternative rule: java:S100

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + methodPattern + + [a-z][a-zA-Z0-9]* + STRING + + + staticPattern + + [a-z][a-zA-Z0-9]* + STRING + + + nativePattern + + [a-z][a-zA-Z0-9]* + STRING + + + junit3TestPattern + + test[A-Z0-9][a-zA-Z0-9]* + STRING + + + junit4TestPattern + + [a-z][a-zA-Z0-9]* + STRING + + + junit5TestPattern + + [a-z][a-zA-Z0-9]* + STRING + + + violationSuppressRegex + + + STRING + +
        + + MethodReturnsInternalArray + Method returns internal array + category/java/bestpractices.xml/MethodReturnsInternalArray + MAJOR + Title of issues: Returning '{0}' may expose an internal array. +

        Exposing internal arrays to the caller violates object encapsulation since elements can be +removed or replaced outside of the object that owns it. It is safer to return a copy of the array.

        +

        Example

        +

         public class SecureSystem {
        +     UserData [] ud;
        +     public UserData [] getUserData() {
        +         // Don't return directly the internal array, return a copy
        +         return ud;
        +     }
        + }

        +

        Alternative rule: java:S2384

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + MethodWithSameNameAsEnclosingClass + Method with same name as enclosing class + category/java/errorprone.xml/MethodWithSameNameAsEnclosingClass + MAJOR + Title of issues: A method should not have the same name as its containing class +

        A method should not have the same name as its containing class. +This would be confusing as it would look like a constructor.

        +

        Example

        +

         public class MyClass {
        + 
        +     public MyClass() {}         // this is OK because it is a constructor
        + 
        +     public void MyClass() {}    // this is bad because it is a method
        + }

        +

        Alternative rule: java:S1223

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + MisplacedNullCheck + Misplaced null check + category/java/errorprone.xml/MisplacedNullCheck + MAJOR + Title of issues: The null check here is misplaced; if the variable '{0}' is null there will be a NullPointerException +

        The null check here is misplaced. If the variable is null a NullPointerException will be thrown. +Either the check is useless (the variable will never be null) or it is incorrect.

        +

        Examples

        +

        Example 1

        +

         public class Foo {
        +     void bar() {
        +         if (a.equals(baz) && a != null) {} // a could be null, misplaced null check
        + 
        +         if (a != null && a.equals(baz)) {} // correct null check
        +     }
        + }

        +

        Example 2

        +

         public class Foo {
        +     void bar() {
        +         if (a.equals(baz) || a == null) {} // a could be null, misplaced null check
        + 
        +         if (a == null || a.equals(baz)) {} // correct null check
        +     }
        + }

        +

        Alternative rules: java:S1697, java:S2259

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + MissingOverride + Missing override + category/java/bestpractices.xml/MissingOverride + MAJOR + Title of issues: The method '{0}' is missing an @Override annotation. +

        Annotating overridden methods with @Override ensures at compile time that + the method really overrides one, which helps refactoring and clarifies intent.

        +

        Example

        +

         public class Foo implements Runnable {
        +                 // This method is overridden, and should have an @Override annotation
        +                 public void run() {
        + 
        +                 }
        +             }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + violationSuppressRegex + + + STRING + +
        + + MissingSerialVersionUID + Missing serialVersionUID + category/java/errorprone.xml/MissingSerialVersionUID + MAJOR + Title of issues: Classes implementing Serializable should set a serialVersionUID +

        Serializable classes should provide a serialVersionUID field. +The serialVersionUID field is also needed for abstract base classes. Each individual class in the inheritance +chain needs an own serialVersionUID field. See also Should an abstract class have a serialVersionUID.

        +

        Example

        +

         public class Foo implements java.io.Serializable {
        +     String name;
        +     // Define serialization id to avoid serialization related bugs
        +     // i.e., public static final long serialVersionUID = 4328743;
        + }

        +

        Alternative rule: java:S2057

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + MissingStaticMethodInNonInstantiatableClass + Missing static method in non instantiatable class + category/java/errorprone.xml/MissingStaticMethodInNonInstantiatableClass + MAJOR + Title of issues: Class cannot be instantiated and does not provide any static methods or fields +

        A class that has private constructors and does not have any static methods or fields cannot be used.

        +

        When one of the private constructors is annotated with one of the annotations, then the class is not considered +non-instantiatable anymore and no violation will be reported. +See the property annotations.

        +

        Example

        +

         // This class is unusable, since it cannot be
        + // instantiated (private constructor),
        + // and no static method can be called.
        + 
        + public class Foo {
        +   private Foo() {}
        +   void foo() {}
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone + + annotations + + org.springframework.beans.factory.annotation.Autowired,javax.inject.Inject,com.google.inject.Inject,lombok.Builder + STRING + +
        + + ModifierOrder + Modifier order + category/java/codestyle.xml/ModifierOrder + MAJOR + Title of issues: Wrong modifier order (the actual message is written by the rule) +

        Enforces the modifier order recommended by the JLS. Apart from sorting modifiers, this rule also enforces that all annotations appear before all modifier keywords. By setting the property typeAnnotations, you can also enforce that type annotations appear right of the modifier keywords, next to the type they apply to. This property can have three values:

        +
        • on type: Type annotations must be placed next to the type they apply to
        • on decl: Type annotations must be placed with other annotations, before modifiers. This is not enforced if the type annotations syntactically appears within the type, e.g.
        • anywhere (default): Either position fits. They still cannot be interspersed within keyword modifiers. Annotations that are not type annotations are still required to be before keyword
        +

        Example

        +

         abstract public class Foo { // Warn: `public` should appear before `abstract`
        + 
        +     // This order is not recommended, annotations should appear before keyword modifiers,
        +     // and may appear after if they are type annotations.
        +     public
        +     @Override
        +     static fooStuff() {
        +     }
        + 
        +     // This order is ok if property typeAnnotations is "anywhere", and enforced if it is "on decl":
        +     @Nullable
        +     public Object fooStuff() {}
        + 
        +     // This order is ok if property typeAnnotations is "anywhere", and enforced if it is "on type":
        +     public @Nullable Object fooStuff() {}
        + 
        + 
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + typeAnnotations + + anywhere + SINGLE_SELECT_LIST,values="ontype,ondecl,anywhere" + +
        + + MoreThanOneLogger + More than one logger + category/java/errorprone.xml/MoreThanOneLogger + CRITICAL + Title of issues: Class contains more than one logger. +

        Normally only one logger is used in each class. This rule supports slf4j, log4j, Java Util Logging and +log4j2 (since 6.19.0).

        +

        Example

        +

         public class Foo {
        +     Logger log = Logger.getLogger(Foo.class.getName());
        +     // It is very rare to see two loggers on a class, normally
        +     // log information is multiplexed by levels
        +     Logger log2= Logger.getLogger(Foo.class.getName());
        + }

        +

        Alternative rule: java:S1312

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + MutableStaticState + Mutable static state + category/java/design.xml/MutableStaticState + MAJOR + Title of issues: Do not use non-final non-private static fields +

        Non-private static fields should be made constants (or immutable references) by +declaring them final.

        +

        Non-private non-final static fields break encapsulation and can lead to hard to find +bugs, since these fields can be modified from anywhere within the program. +Callers can trivially access and modify non-private non-final static fields. Neither +accesses nor modifications can be guarded against, and newly set values cannot +be validated.

        +

        If you are using this rule, then you don't need this +rule {% rule java/errorprone/AssignmentToNonFinalStatic %}.

        +

        Example

        +

         public class Greeter { public static Foo foo = new Foo(); ... }       // avoid this
        + public class Greeter { public static final Foo FOO = new Foo(); ... } // use this instead

        +

        Full documentation

        ]]>
        + pmd + design +
        + + NPathComplexity + NPath complexity + category/java/design.xml/NPathComplexity + MAJOR + Title of issues: The {0} '{1}' has an NPath complexity of {2}, current threshold is {3} +

        The NPath complexity of a method is the number of acyclic execution paths through that method. +While cyclomatic complexity counts the number of decision points in a method, NPath counts the number of +full paths from the beginning to the end of the block of the method. That metric grows exponentially, as +it multiplies the complexity of statements in the same block. For more details on the calculation, see the +documentation NPATH.

        +

        A threshold of 200 is generally considered the point where measures should be taken to reduce +complexity and increase readability.

        +

        Example

        +

         public class Foo {
        +   public static void bar() { // Ncss = 252: reported!
        +     boolean a, b = true;
        +     try { // 2 * 2 + 2 = 6
        +       if (true) { // 2
        +         List buz = new ArrayList();
        +       }
        + 
        +       for(int i = 0; i < 19; i++) { // * 2
        +         List buz = new ArrayList();
        +       }
        +     } catch(Exception e) {
        +       if (true) { // 2
        +         e.printStackTrace();
        +       }
        +     }
        + 
        +     while (j++ < 20) { //  * 2
        +       List buz = new ArrayList();
        +     }
        + 
        +     switch(j) { // * 7
        +       case 1:
        +       case 2: break;
        +       case 3: j = 5; break;
        +       case 4: if (b && a) { bar(); } break;
        +       default: break;
        +     }
        + 
        +     do { // * 3
        +         List buz = new ArrayList();
        +     } while (a && j++ < 30);
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + design + + reportLevel + + 200 + INTEGER + + + violationSuppressRegex + + + STRING + +
        + + NcssCount + NCSS count + category/java/design.xml/NcssCount + MAJOR + Title of issues: The {0} '{1}' has a NCSS line count of {2}. +

        This rule uses the NCSS (Non-Commenting Source Statements) metric to determine the number of lines +of code in a class, method or constructor. NCSS ignores comments, blank lines, and only counts actual +statements. For more details on the calculation, see the documentation +NCSS.

        +

        Example

        +

         import java.util.Collections;       // +0
        + import java.io.IOException;         // +0
        + 
        + class Foo {                         // +1, total Ncss = 12
        + 
        +   public void bigMethod()           // +1
        +       throws IOException {
        +     int x = 0, y = 2;               // +1
        +     boolean a = false, b = true;    // +1
        + 
        +     if (a || b) {                   // +1
        +       try {                         // +1
        +         do {                        // +1
        +           x += 2;                   // +1
        +         } while (x < 12);
        + 
        +         System.exit(0);             // +1
        +       } catch (IOException ioe) {   // +1
        +         throw new PatheticFailException(ioe); // +1
        +       }
        +     } else {
        +       assert false;                 // +1
        +     }
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + design + + methodReportLevel + + 60 + INTEGER + + + classReportLevel + + 1500 + INTEGER + + + ncssOptions + + + STRING + + + violationSuppressRegex + + + STRING + +
        + + NoPackage + No package + category/java/codestyle.xml/NoPackage + MINOR + Title of issues: All classes, interfaces, enums and annotations must belong to a named package +

        Detects when a class, interface, enum or annotation does not have a package definition.

        +

        Example

        +

         // no package declaration
        + public class ClassInDefaultPackage {
        + }

        +

        Alternative rule: java:S1220

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative +
        + + NonCaseLabelInSwitch + Non case label in switch + category/java/errorprone.xml/NonCaseLabelInSwitch + MAJOR + Title of issues: A non-case label was present in a switch statement or expression +

        A non-case label (e.g. a named break/continue label) was present in a switch statement or switch expression. +This is legal, but confusing. It is easy to mix up the case labels and the non-case labels.

        +

        Note: This rule was renamed from NonCaseLabelInSwitchStatement with PMD 7.7.0.

        +

        Example

        +

         public class Foo {
        +   void bar(int a) {
        +    switch (a) {
        +      case 1:
        +        // do something
        +      mylabel: // this is legal, but confusing!
        +        break;
        +      default:
        +        break;
        +     }
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + NonExhaustiveSwitch + Non exhaustive switch + category/java/bestpractices.xml/NonExhaustiveSwitch + MAJOR + Title of issues: Switch statements or expressions should be exhaustive, add a default case (or missing enum branches) +

        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.

        +

        This rule doesn't consider Switch Statements, that use Pattern Matching, since for these the + compiler already ensures that all cases are covered. The same is true for Switch Expressions, + which are also not considered by this rule.

        +

        Example

        +

         class Foo {{
        +     int x = 2;
        +     switch (x) {
        +       case 1: int j = 6;
        +       case 2: int j = 8;
        +       // missing default: here
        +     }
        + }}

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + NonSerializableClass + Non serializable class + category/java/errorprone.xml/NonSerializableClass + MAJOR + Title of issues: The field '{0}' of serializable class '{1}' is of non-serializable type '{2}'. +

        If a class is marked as Serializable, then all fields need to be serializable as well. In order to exclude +a field, it can be marked as transient. Static fields are not considered.

        +

        This rule reports all fields, that are not serializable.

        +

        If a class implements the methods to perform manual serialization (writeObject, readObject) or uses +a replacement object (writeReplace, readResolve) then this class is ignored.

        +

        Note: This rule has been revamped with PMD 6.52.0. It was previously called "BeanMembersShouldSerialize". +The property prefix has been deprecated, since in a serializable class all fields have to be +serializable regardless of the name.

        +

        Example

        +

         class Buzz implements java.io.Serializable {
        +     private static final long serialVersionUID = 1L;
        + 
        +     private transient int someFoo;          // good, it's transient
        +     private static int otherFoo;            // also OK, it's static
        +     private java.io.FileInputStream stream; // bad - FileInputStream is not serializable
        + 
        +     public void setStream(FileInputStream stream) {
        +         this.stream = stream;
        +     }
        + 
        +     public int getSomeFoo() {
        +           return this.someFoo;
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone + + checkAbstractTypes + + false + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + NonStaticInitializer + Non static initializer + category/java/errorprone.xml/NonStaticInitializer + MAJOR + Title of issues: Non-static initializers are confusing +

        A non-static initializer block will be called any time a constructor is invoked (just prior to +invoking the constructor). While this is a valid language construct, it is rarely used and is +confusing.

        +

        Example

        +

         public class MyClass {
        +   // this block gets run before any call to a constructor
        +   {
        +     System.out.println("I am about to construct myself");
        +   }
        + }

        +

        Alternative rule: java:S1171

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + NonThreadSafeSingleton + Non thread safe singleton + category/java/multithreading.xml/NonThreadSafeSingleton + MAJOR + Title of issues: Singleton is not thread safe +

        Non-thread safe singletons can result in bad state changes. Eliminate +static singletons if possible by instantiating the object directly. Static +singletons are usually not needed as only a single instance exists anyway. +Other possible fixes are to synchronize the entire method or to use an +initialize-on-demand holder class.

        +

        Refrain from using the double-checked locking pattern. The Java Memory Model doesn't +guarantee it to work unless the variable is declared as volatile, adding an unneeded +performance penalty. Reference

        +

        See Effective Java, item 48.

        +

        Example

        +

         private static Foo foo = null;
        + 
        + //multiple simultaneous callers may see partially initialized objects
        + public static Foo getFoo() {
        +     if (foo==null) {
        +         foo = new Foo();
        +     }
        +     return foo;
        + }

        +

        Alternative rule: java:S2444

        +

        Full documentation

        ]]>
        + pmd + multithreading + has-sonar-alternative + + checkNonStaticMethods + + true + BOOLEAN + + + checkNonStaticFields + + false + BOOLEAN + +
        + + NullAssignment + Null assignment + category/java/errorprone.xml/NullAssignment + MAJOR + Title of issues: Assigning an Object to null is a code smell. Consider refactoring. +

        Assigning a "null" to a variable (outside of its declaration) is usually bad form. Sometimes, this type +of assignment is an indication that the programmer doesn't completely understand what is going on in the code.

        +

        NOTE: This sort of assignment may used in some cases to dereference objects and encourage garbage collection.

        +

        Example

        +

         public void bar() {
        +   Object x = null; // this is OK
        +   x = new Object();
        +      // big, complex piece of code here
        +   x = null; // this is not required
        +      // big, complex piece of code here
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + OneDeclarationPerLine + One declaration per line + category/java/bestpractices.xml/OneDeclarationPerLine + MINOR + Title of issues: Use one line for each declaration, it enhances code readability. +

        Java allows the use of several variables declaration of the same type on one line. +However, it can lead to quite messy code. This rule looks for several declarations on the same line.

        +

        Example

        +

         String name;            // separate declarations
        + String lastname;
        + 
        + String name, lastname;  // combined declaration, a violation
        + 
        + String name,
        +        lastname;        // combined declaration on multiple lines, no violation by default.
        +                         // Set property strictMode to true to mark this as violation.

        +

        Alternative rule: java:S122

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative + + strictMode + + false + BOOLEAN + +
        + + OnlyOneReturn + Only one return + category/java/codestyle.xml/OnlyOneReturn + MINOR + Title of issues: A method should have only one exit point, and that should be the last statement in the method +

        A method should have only one exit point, and that should be the last statement in the method.

        +

        Example

        +

         public class OneReturnOnly1 {
        +   public String foo(int x) {
        +     if (x > 0) {
        +       return "hey";   // first exit
        +     }
        +     return "hi";    // second exit
        +   }
        + }

        +

        Alternative rule: java:S1142

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative +
        + + OptimizableToArrayCall + Optimizable toArray call + category/java/performance.xml/OptimizableToArrayCall + MAJOR + Title of issues: This call to Collection.toArray() may be optimizable +

        Calls to a collection's toArray(E[]) method should specify a target array of zero size. This allows the JVM +to optimize the memory allocation and copying as much as possible.

        +

        Previous versions of this rule (pre PMD 6.0.0) suggested the opposite, but current JVM implementations +perform always better, when they have full control over the target array. And allocation an array via +reflection is nowadays as fast as the direct allocation.

        +

        See also Arrays of Wisdom of the Ancients

        +

        Note: If you don't need an array of the correct type, then the simple toArray() method without an array +is faster, but returns only an array of type Object[].

        +

        Example

        +

         List<Foo> foos = getFoos();
        + 
        + // much better; this one allows the jvm to allocate an array of the correct size and effectively skip
        + // the zeroing, since each array element will be overridden anyways
        + Foo[] fooArray = foos.toArray(new Foo[0]);
        + 
        + // inefficient, the array needs to be zeroed out by the jvm before it is handed over to the toArray method
        + Foo[] fooArray = foos.toArray(new Foo[foos.size()]);

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + OverrideBothEqualsAndHashCodeOnComparable + Override both equals and hash code on comparable + category/java/errorprone.xml/OverrideBothEqualsAndHashCodeOnComparable + MAJOR + Title of issues: When implementing Comparable both equals() and hashCode() should be overridden +

        Classes that implement Comparable should override both equals() and + hashCode() if instances of these classes are used in collections. This is + to ensure that the class's natural ordering is consistent with equals(). + Failing to do so can lead to unexpected behavior in sets which then do not + conform to the Set interface. While the Set interface relies on + equals() to determine object equality, sorted sets like TreeSet use + compareTo() instead. The same issue can arise when such objects are used + as keys in sorted maps.

        +

        Note 1: This rule is related to {% rule OverrideBothEqualsAndHashcode %}. It + will report missing equals() and/or hashCode() methods for classes only + that implement Comparable.

        +

        Note 2: This rule also reports records that implement Comparable. While + for records, equals() and hashCode() are generated, you still must make + sure that compareTo() is consistent with equals().

        +

        Example

        +

         public class Bar implements Comparable<Bar> {  // poor - missing equals() and hashCode()
        +     public int compareTo(Bar other) {
        +         // some comparison
        +     }
        + }
        + 
        + public class Baz implements Comparable<Baz> {  // poor - missing hashCode()
        +     public int compareTo(Baz other) {
        +         // some comparison
        +     }
        +     public boolean equals(Object o) {
        +         if (o == null || getClass() != o.getClass()) {
        +             return false;
        +         }
        +         return compareTo((Baz) o) == 0;
        +     }
        + }
        + 
        + public class Foo implements Comparable<Foo> {  // correct
        +     public int compareTo(Foo other) {
        +         // some comparison
        +     }
        +     public boolean equals(Object o) {
        +         if (o == null || getClass() != o.getClass()) {
        +             return false;
        +         }
        +         return compareTo((Foo) o) == 0;
        +     }
        +     public int hashCode() {
        +         // return hash code
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + OverrideBothEqualsAndHashcode + Override both equals and hashcode + category/java/errorprone.xml/OverrideBothEqualsAndHashcode + MAJOR + Title of issues: Ensure you override both equals() and hashCode() +

        Override both public boolean Object.equals(Object other) and public int Object.hashCode() or override neither. +Even if you are inheriting a hashCode() from a parent class, consider implementing hashCode() and explicitly +delegating to your superclass.

        +

        Not overriding both methods could violate the contract between equals() and hashCode(). Most importantly, +if two instances are equal, then they must have the same hash code. Using such invalid instances in hash-based +collections like HashSet or HashMap could lead to duplicated or missing entries.

        +

        This rule does not consider types that implement Comparable. There is a separate rule +{% rule OverrideBothEqualsAndHashCodeOnComparable %} for this.

        +

        Example

        +

         public class Bar {        // poor, missing a hashcode() method
        +     public boolean equals(Object o) {
        +       // do some comparison
        +     }
        + }
        + 
        + public class Baz {        // poor, missing an equals() method
        +     public int hashCode() {
        +       // return some hash value
        +     }
        + }
        + 
        + public class Foo {        // perfect, both methods provided
        +     public boolean equals(Object other) {
        +       // do some comparison
        +     }
        +     public int hashCode() {
        +       // return some hash value
        +     }
        + }

        +

        Alternative rule: java:S1206

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + PackageCase + Package case + category/java/codestyle.xml/PackageCase + MINOR + Title of issues: Package name contains upper case characters +

        Detects when a package definition contains uppercase characters.

        +

        Example

        +

         package com.MyCompany;  // should be lowercase name
        + 
        + public class SomeClass {
        + }

        +

        Alternative rule: java:S120

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative +
        + + PrematureDeclaration + Premature declaration + category/java/codestyle.xml/PrematureDeclaration + MINOR + Title of issues: Declaration of '{0}' can be moved closer to its usages +

        Checks for variables that are defined before they might be used. A declaration is +deemed to be premature if there are some statements that may return or throw an +exception between the time the variable is declared and the time it is first read.

        +

        Some variables cannot be declared close to their first usage because of side-effects +occurring before they're first used. We try to avoid reporting those by considering +most method and constructor invocations to be impure. See the second example.

        +

        Note that this rule is meant to improve code readability but is not an optimization. +A smart JIT will not care whether the variable is declared prematurely or not, as it +can reorder code.

        +

        Examples

        +

        Example 1

        +

         public int getLength(String[] strings) {
        + 
        +     int length = 0; // could be moved closer to the loop
        + 
        +     if (strings == null || strings.length == 0) return 0;
        + 
        +     for (String str : strings) {
        +         length += str.length();
        +     }
        + 
        +     return length;
        + }

        +

        Example 2

        +

         public int getLength(String[] strings) {
        + 
        +     int startTime = System.nanoTime(); // cannot be moved because initializer is impure
        + 
        +     if (strings == null || strings.length == 0) {
        +         // some error logic
        +         throw new SomeException(...);
        +     }
        + 
        +     for (String str : strings) {
        +         length += str.length();
        +     }
        + 
        +     return System.nanoTime() - startTime;
        + }

        +

        Alternative rule: java:S1941

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + PreserveStackTrace + Preserve stack trace + category/java/bestpractices.xml/PreserveStackTrace + MAJOR + Title of issues: Thrown exception does not preserve the stack trace of exception '{0}' on all code paths +

        Reports exceptions that are thrown from within a catch block, yet don't refer to the +exception parameter declared by that catch block. The stack trace of the original +exception could be lost, which makes the thrown exception less informative.

        +

        To preserve the stack trace, the original exception may be used as the cause of +the new exception, using Throwable#initCause, or passed as a constructor argument +to the new exception. It may also be preserved using Throwable#addSuppressed. +The rule actually assumes that any method or constructor that takes the original +exception as argument preserves the original stack trace.

        +

        The rule allows InvocationTargetException and PrivilegedActionException to be +replaced by their cause exception. The discarded part of the stack trace is in those +cases only JDK-internal code, which is not very useful. The rule also ignores exceptions +whose name starts with ignored.

        +

        Example

        +

         public class Foo {
        +     void good() {
        +         try{
        +             Integer.parseInt("a");
        +         } catch (Exception e) {
        +             throw new Exception(e); // Ok, this initializes the cause of the new exception
        +         }
        +         try {
        +             Integer.parseInt("a");
        +         } catch (Exception e) {
        +             throw (IllegalStateException)new IllegalStateException().initCause(e); // second possibility to create exception chain.
        +         }
        +     }
        +     void wrong() {
        +         try{
        +             Integer.parseInt("a");
        +         } catch (Exception e) {
        +             // Violation: this only preserves the message and not the stack trace
        +             throw new Exception(e.getMessage());
        +         }
        +     }
        + }

        +

        Alternative rule: java:S1166

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + PrimitiveWrapperInstantiation + Primitive wrapper instantiation + category/java/bestpractices.xml/PrimitiveWrapperInstantiation + MAJOR + Title of issues: Do not use new {0}(...), prefer {0}.valueOf(...) +

        Reports usages of primitive wrapper constructors. They are deprecated + since Java 9 and should not be used. Even before Java 9, they can + be replaced with usage of the corresponding static valueOf factory method + (which may be automatically inserted by the compiler since Java 1.5). + This has the advantage that it may reuse common instances instead of creating + a new instance each time.

        +

        Note that for Boolean, the named constants Boolean.TRUE and Boolean.FALSE + are preferred instead of Boolean.valueOf.

        +

        Example

        +

         public class Foo {
        +                 private Integer ZERO = new Integer(0);      // violation
        +                 private Integer ZERO1 = Integer.valueOf(0); // better
        +                 private Integer ZERO1 = 0;                  // even better
        +             }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + violationSuppressRegex + + + STRING + +
        + + ProperCloneImplementation + Proper clone implementation + category/java/errorprone.xml/ProperCloneImplementation + CRITICAL + Title of issues: Object clone() should be implemented with super.clone() +

        Object clone() should be implemented with super.clone().

        +

        Example

        +

         class Foo{
        +     public Object clone(){
        +         return new Foo(); // This is bad
        +     }
        + }

        +

        Alternative rule: java:S1182

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + ProperLogger + Proper logger + category/java/errorprone.xml/ProperLogger + MAJOR + Title of issues: Logger should be defined private static final and have the correct class +

        A logger should normally be defined private static final and be associated with the correct class. +private final Log log; is also allowed for rare cases where loggers need to be passed around, +with the restriction that the logger needs to be passed into the constructor.

        +

        Example

        +

         public class Foo {
        + 
        +     private static final Log LOG = LogFactory.getLog(Foo.class);    // proper way
        + 
        +     protected Log LOG = LogFactory.getLog(Testclass.class);         // wrong approach
        + }

        +

        Alternative rule: java:S1312

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative + + staticLoggerName + + LOG + STRING + + + loggerName + + log + STRING + + + loggerClass + + org.apache.commons.logging.Log + STRING + +
        + + RedundantFieldInitializer + Redundant field initializer + category/java/performance.xml/RedundantFieldInitializer + MAJOR + Title of issues: Avoid using redundant field initializer for '${variableName}' +

        Java will initialize fields with known default values so any explicit initialization of those same defaults +is redundant and results in a larger class file (approximately three additional bytecode instructions per field).

        +

        Example

        +

         public class C {
        +     boolean b   = false;    // examples of redundant initializers
        +     byte by     = 0;
        +     short s     = 0;
        +     char c      = 0;
        +     int i       = 0;
        +     long l      = 0;
        + 
        +     float f     = .0f;    // all possible float literals
        +     double d    = 0d;     // all possible double literals
        +     Object o    = null;
        + 
        +     MyClass mca[] = null;
        +     int i1 = 0, ia1[] = null;
        + 
        +     class Nested {
        +         boolean b = false;
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + RelianceOnDefaultCharset + Reliance on default charset + category/java/bestpractices.xml/RelianceOnDefaultCharset + MAJOR + Title of issues: Specify a character set instead of relying on the default charset +

        Be sure to specify a character set for APIs that use the JVM's default character set to ensure +stable encoding behavior between different JVMs, programs, and servers. Using the platform's +default charset makes the code less portable and might lead to unexpected behavior when running +on different systems.

        +

        Additional, since Java 18, the default charset for these APIs is consistently UTF-8 +(see JEP 400). While this reduces unexpected behavior +on different systems, it is still advised to explicitly specify a character set, +especially if UTF-8 is not the desired charset.

        +

        Example

        +

         public class Foo {
        +     void bad() throws IOException {
        +         new InputStreamReader(inputStream);  // violation
        +         new OutputStreamWriter(outputStream);  // violation
        +         URLEncoder.encode("test string");  // violation (deprecated)
        +         new PrintStream(outputStream);  // violation
        +         new PrintWriter("output.txt");  // violation
        +         new Scanner(inputStream);  // violation
        +         new Formatter();  // violation
        +         "test".getBytes();  // violation
        +         new ByteArrayOutputStream().toString();  // violation
        +         new FileReader("input.txt");  // violation
        +         new FileWriter("output.txt");  // violation
        +     }
        + 
        +     void good() throws IOException {
        +         new InputStreamReader(inputStream, StandardCharsets.UTF_8);  // ok
        +         new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);  // ok
        +         URLEncoder.encode("test string", StandardCharsets.UTF_8);  // ok
        +         new PrintStream(outputStream, true, StandardCharsets.UTF_8);  // ok
        +         new PrintWriter("output.txt", StandardCharsets.UTF_8);  // ok
        +         new Scanner(inputStream, StandardCharsets.UTF_8);  // ok
        +         new Formatter(Locale.US);  // ok
        +         "test".getBytes(StandardCharsets.UTF_8);  // ok
        +         new ByteArrayOutputStream().toString(StandardCharsets.UTF_8);  // ok
        +         new FileReader("input.txt", StandardCharsets.UTF_8);  // ok
        +         new FileWriter("output.txt", StandardCharsets.UTF_8);  // ok
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + RemoteInterfaceNamingConvention + Remote interface naming convention + category/java/codestyle.xml/RemoteInterfaceNamingConvention + MINOR + Title of issues: Remote Interface of a Session EJB should NOT be suffixed +

        Remote Interface of a Session EJB should not have a suffix.

        +

        Example

        +

         /* Poor Session suffix */
        + public interface BadSuffixSession extends javax.ejb.EJBObject {}
        + 
        + /* Poor EJB suffix */
        + public interface BadSuffixEJB extends javax.ejb.EJBObject {}
        + 
        + /* Poor Bean suffix */
        + public interface BadSuffixBean extends javax.ejb.EJBObject {}

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + RemoteSessionInterfaceNamingConvention + Remote session interface naming convention + category/java/codestyle.xml/RemoteSessionInterfaceNamingConvention + MINOR + Title of issues: Remote Home interface of a Session EJB should be suffixed by 'Home' +

        A Remote Home interface type of a Session EJB should be suffixed by 'Home'.

        +

        Example

        +

         public interface MyBeautifulHome extends javax.ejb.EJBHome {}       // proper name
        + 
        + public interface MissingProperSuffix extends javax.ejb.EJBHome {}   // non-standard name

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + ReplaceEnumerationWithIterator + Replace Enumeration with Iterator + category/java/bestpractices.xml/ReplaceEnumerationWithIterator + MAJOR + Title of issues: Consider replacing this Enumeration with the newer java.util.Iterator +

        Consider replacing Enumeration usages with the newer java.util.Iterator

        +

        Example

        +

         public class Foo implements Enumeration {
        +     private int x = 42;
        +     public boolean hasMoreElements() {
        +         return true;
        +     }
        +     public Object nextElement() {
        +         return String.valueOf(i++);
        +     }
        + }

        +

        Alternative rule: java:S1150

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative +
        + + ReplaceHashtableWithMap + Replace Hashtable with Map + category/java/bestpractices.xml/ReplaceHashtableWithMap + MAJOR + Title of issues: Consider replacing this Hashtable with the newer java.util.Map +

        Consider replacing Hashtable usage with the newer java.util.Map if thread safety is not required.

        +

        Example

        +

         public class Foo {
        +     void bar() {
        +         Hashtable h = new Hashtable();
        +     }
        + }

        +

        Alternative rule: java:S1149

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative +
        + + ReplaceJavaUtilCalendar + Replace java util calendar + category/java/errorprone.xml/ReplaceJavaUtilCalendar + MAJOR + Title of issues: Usage of java.util.Calendar should be replaced with classes from java.time +

        The legacy java.util.Calendar API is error-prone, mutable, and not thread-safe. It has confusing month indexing +(January = 0), inconsistent field semantics, and verbose usage patterns. The modern java.time API +(introduced in Java 8) provides immutable, thread-safe alternatives with clear, intuitive methods.

        +

        Use LocalDate (for date-only operations), LocalDateTime (for date and time), or ZonedDateTime +(when timezone is important) from java.time package instead.

        +

        Note: Since JPA 3.2 (Jakarta Persistence) usage of java.util.Date and java.util.Calendar and others is +deprecated there as well in favour of java.time API.

        +

        Example

        +

         import java.util.Calendar;
        + import java.util.GregorianCalendar;
        + import java.time.LocalDate;
        + import java.time.LocalDateTime;
        + import java.time.ZonedDateTime;
        + 
        + public class Foo {
        +     void problematic() {
        +         // Problematic - using legacy Calendar API
        +         Calendar cal = Calendar.getInstance();
        +         cal.set(2024, Calendar.JANUARY, 15); // Month indexing is confusing (0-based)
        +         cal.add(Calendar.DAY_OF_MONTH, 7);
        +         
        +         Calendar specific = new GregorianCalendar(2024, 0, 15); // Also problematic
        +     }
        +     
        +     void preferred() {
        +         // Preferred - using modern java.time API
        +         LocalDate date = LocalDate.of(2024, 1, 15); // Month indexing is intuitive (1-based)
        +         LocalDate weekLater = date.plusDays(7);
        +         
        +         LocalDateTime dateTime = LocalDateTime.now();
        +         ZonedDateTime zonedDateTime = ZonedDateTime.now();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + ReplaceJavaUtilDate + Replace java util date + category/java/errorprone.xml/ReplaceJavaUtilDate + MAJOR + Title of issues: Usage of java.util.Date should be replaced with classes from java.time +

        The legacy java.util.Date class is mutable, not thread-safe, and has a confusing API. Many of its methods +are deprecated, it doesn't handle timezones properly, and it represents both date and time even when only +one is needed. The constructor parameters are particularly error-prone: year is "years since 1900" and +month is 0-based (January = 0). The modern java.time API (introduced in Java 8) provides better type safety, +immutability, and clearer semantics.

        +

        Use LocalDate (date only), LocalTime (time only), LocalDateTime (date and time), Instant (timestamp), +or ZonedDateTime (date-time with timezone) from java.time package instead.

        +

        Note: This includes subtypes such as java.sql.Date, java.sql.Time and java.sql.Timestamp. +Since JPA 3.2 (Jakarta Persistence) usage of java.util.Date and java.util.Calendar and others is +deprecated there as well in favour of java.time API.

        +

        Example

        +

         import java.util.Date;
        + import java.time.Instant;
        + import java.time.LocalDate;
        + import java.time.LocalDateTime;
        + import java.time.ZonedDateTime;
        + 
        + public class Foo {
        +     void problematic() {
        +         // Problematic - using legacy Date API
        +         Date now = new Date();
        +         Date epoch = new Date(0L);
        +         Date custom = new Date(124, 0, 15); // Deprecated constructor: year=1900+124=2024, month=0=January
        +         
        +         // Mutable operations are error-prone
        +         now.setTime(System.currentTimeMillis());
        +     }
        +     
        +     void preferred() {
        +         // Preferred - using modern java.time API
        +         Instant now = Instant.now(); // For timestamps
        +         LocalDate today = LocalDate.now(); // For date only
        +         LocalDateTime dateTime = LocalDateTime.now(); // For date and time
        +         ZonedDateTime zonedDateTime = ZonedDateTime.now(); // With timezone
        +         
        +         // Immutable operations are safer
        +         LocalDate tomorrow = today.plusDays(1);
        +         LocalDateTime nextHour = dateTime.plusHours(1);
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + ReplaceVectorWithList + Replace Vector with List + category/java/bestpractices.xml/ReplaceVectorWithList + MAJOR + Title of issues: Consider replacing this Vector with the newer java.util.List +

        Consider replacing Vector usages with the newer java.util.ArrayList if expensive thread-safe operations are not required.

        +

        Example

        +

         import java.util.Vector;
        + public class Foo {
        +     void bar() {
        +         Vector v = new Vector();
        +     }
        + }

        +

        Alternative rule: java:S1149

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative +
        + + ReturnEmptyCollectionRatherThanNull + Return empty collection rather than null + category/java/errorprone.xml/ReturnEmptyCollectionRatherThanNull + BLOCKER + Title of issues: Return an empty collection rather than 'null'. +

        For any method that returns an collection (such as an array, Collection or Map), it is better to return +an empty one rather than a null reference. This removes the need for null checking all results and avoids +inadvertent NullPointerExceptions.

        +

        See Effective Java, 3rd Edition, Item 54: Return empty collections or arrays instead of null

        +

        Example

        +

         public class Example {
        +     // Not a good idea...
        +     public int[] badBehavior() {
        +         // ...
        +         return null;
        +     }
        + 
        +     // Good behavior
        +     public String[] bonnePratique() {
        +         //...
        +         return new String[0];
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + ReturnFromFinallyBlock + Return from finally block + category/java/errorprone.xml/ReturnFromFinallyBlock + MAJOR + Title of issues: Avoid returning from a finally block +

        Avoid returning from a finally block, this can discard exceptions.

        +

        Example

        +

         public class Bar {
        +     public String foo() {
        +         try {
        +             throw new Exception( "My Exception" );
        +         } catch (Exception e) {
        +             throw e;
        +         } finally {
        +             return "A. O. K."; // return not recommended here
        +         }
        +     }
        + }

        +

        Alternative rule: java:S1143

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + ShortClassName + Short class name + category/java/codestyle.xml/ShortClassName + MINOR + Title of issues: Avoid short class names like {0} +

        Short Classnames with fewer than e.g. five characters are not recommended.

        +

        Example

        +

         public class Foo {
        + }

        +

        Alternative rule: java:S101

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + minimum + + 5 + INTEGER + + + violationSuppressRegex + + + STRING + +
        + + ShortMethodName + Short method name + category/java/codestyle.xml/ShortMethodName + MINOR + Title of issues: Avoid using short method names +

        Method names that are very short are not helpful to the reader.

        +

        Example

        +

         public class ShortMethod {
        +     public void a( int i ) { // Violation
        +     }
        + }

        +

        Alternative rule: java:S100

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + minimum + + 3 + INTEGER + +
        + + ShortVariable + Short variable + category/java/codestyle.xml/ShortVariable + MINOR + Title of issues: Avoid variables with short names like {0} +

        Fields, local variables, enum constant names or parameter names that are very short are not helpful to the reader.

        +

        Example

        +

         public class Something {
        +     private int q = 15;                         // field - too short
        +     public static void main( String as[] ) {    // formal arg - too short
        +         int r = 20 + q;                         // local var - too short
        +         for (int i = 0; i < 10; i++) {          // not a violation (inside 'for' loop)
        +             r += q;
        +         }
        +         for (Integer i : numbers) {             // not a violation (inside 'for-each' loop)
        +             r += q;
        +         }
        +     }
        + }

        +

        Alternative rule: java:S117

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + minimum + + 3 + INTEGER + + + violationSuppressRegex + + + STRING + +
        + + SignatureDeclareThrowsException + Signature declare throws Exception + category/java/design.xml/SignatureDeclareThrowsException + MAJOR + Title of issues: A method/constructor should not explicitly throw java.lang.Exception +

        A method/constructor shouldn't explicitly throw the generic java.lang.Exception, since it +is unclear which exceptions that can be thrown from the methods. It might be +difficult to document and understand such vague interfaces. Use either a class +derived from RuntimeException or a checked exception.

        +

        Example

        +

         public void foo() throws Exception {
        + }

        +

        Alternative rule: java:S112

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + IgnoreJUnitCompletely + + false + BOOLEAN + +
        + + SimpleDateFormatNeedsLocale + SimpleDateFormat needs Locale + category/java/errorprone.xml/SimpleDateFormatNeedsLocale + MAJOR + Title of issues: When instantiating a SimpleDateFormat object, specify a Locale +

        Be sure to specify a Locale when creating SimpleDateFormat instances to ensure that locale-appropriate +formatting is used.

        +

        Example

        +

         public class Foo {
        +   // Should specify Locale.US (or whatever)
        +   private SimpleDateFormat sdf = new SimpleDateFormat("pattern");
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + SimplifiableTestAssertion + Simplifiable test assertion + category/java/bestpractices.xml/SimplifiableTestAssertion + MAJOR + Title of issues: Assertion may be simplified using {0} +

        Reports test assertions that may be simplified using a more specific + assertion method. This enables better error messages, and makes the + assertions more readable.

        +

        Example

        +

         import org.junit.Test;
        + import static org.junit.Assert.*;
        + 
        + class SomeTestClass {
        +     Object a,b;
        +     @Test
        +     void testMethod() {
        +         assertTrue(a.equals(b)); // could be assertEquals(a, b);
        +         assertTrue(!a.equals(b)); // could be assertNotEquals(a, b);
        + 
        +         assertTrue(!something); // could be assertFalse(something);
        +         assertFalse(!something); // could be assertTrue(something);
        + 
        +         assertTrue(a == b); // could be assertSame(a, b);
        +         assertTrue(a != b); // could be assertNotSame(a, b);
        + 
        +         assertTrue(a == null); // could be assertNull(a);
        +         assertTrue(a != null); // could be assertNotNull(a);
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + violationSuppressRegex + + + STRING + +
        + + SimplifiedTernary + Simplified ternary + category/java/design.xml/SimplifiedTernary + MAJOR + Title of issues: This conditional expression can be simplified with || or && +

        Reports ternary expression with the form condition ? literalBoolean : foo +or condition ? foo : literalBoolean.

        +

        These expressions can be simplified as follows:

        +
        • condition ? true : expr simplifies to condition || expr
        • condition ? false : expr simplifies to !condition && expr
        • condition ? expr : true simplifies to !condition || expr
        • condition ? expr : false simplifies to condition && expr
        +

        Example

        +

         public class Foo {
        +     public boolean test() {
        +         return condition ? true : something(); // can be as simple as return condition || something();
        +     }
        + 
        +     public void test2() {
        +         final boolean value = condition ? false : something(); // can be as simple as value = !condition && something();
        +     }
        + 
        +     public boolean test3() {
        +         return condition ? something() : true; // can be as simple as return !condition || something();
        +     }
        + 
        +     public void test4() {
        +         final boolean otherValue = condition ? something() : false; // can be as simple as condition && something();
        +     }
        + 
        +     public boolean test5() {
        +         return condition ? true : false; // can be as simple as return condition;
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + design +
        + + SimplifyBooleanExpressions + Simplify boolean expressions + category/java/design.xml/SimplifyBooleanExpressions + MAJOR + Title of issues: Avoid unnecessary comparisons in boolean expressions +

        Avoid unnecessary comparisons in boolean expressions, they serve no purpose and impacts readability.

        +

        Example

        +

         public class Bar {
        +   // can be simplified to
        +   // bar = isFoo();
        +   private boolean bar = (isFoo() == true);
        + 
        +   public isFoo() { return false;}
        + }

        +

        Alternative rule: java:S1125

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + SimplifyBooleanReturns + Simplify boolean returns + category/java/design.xml/SimplifyBooleanReturns + MAJOR + Title of issues: This if statement can be replaced by {0} +

        Avoid unnecessary if-then-else statements when returning a boolean. The result of +the conditional test can be returned instead.

        +

        Example

        +

         public boolean isBarEqualTo(int x) {
        +     if (bar == x) {      // this bit of code...
        +         return true;
        +     } else {
        +         return false;
        +     }
        + }
        + 
        + public boolean isBarEqualTo(int x) {
        +     return bar == x;    // can be replaced with this
        + }

        +

        Alternative rule: java:S1126

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + SimplifyConditional + Simplify conditional + category/java/design.xml/SimplifyConditional + MAJOR + Title of issues: No need to check for null before an instanceof +

        No need to check for null before an instanceof; the instanceof keyword returns false when given a null argument.

        +

        Example

        +

         class Foo {
        +   void bar(Object x) {
        +     if (x != null && x instanceof Bar) {
        +       // just drop the "x != null" check
        +     }
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + design +
        + + SingleMethodSingleton + Single method singleton + category/java/errorprone.xml/SingleMethodSingleton + CRITICAL + Title of issues: Class contains multiple getInstance methods. Please review. +

        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.

        +

        Example

        +

         public class Singleton {
        + 
        +     private static Singleton singleton = new Singleton( );
        + 
        +     private Singleton(){ }
        + 
        +     public static Singleton getInstance( ) {
        +         return singleton;
        +     }
        + 
        +     public static Singleton getInstance(Object obj){
        +         Singleton singleton = (Singleton) obj;
        +         return singleton;           //violation
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + SingletonClassReturningNewInstance + Singleton class returning new instance + category/java/errorprone.xml/SingletonClassReturningNewInstance + CRITICAL + Title of issues: getInstance method always creates a new object and hence does not comply to Singleton Design Pattern behaviour. Please review +

        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.

        +

        Example

        +

         class Singleton {
        +     private static Singleton instance = null;
        +     public static Singleton getInstance() {
        +         synchronized(Singleton.class) {
        +             return new Singleton(); // this should be assigned to the field
        +         }
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + SingularField + Singular field + category/java/design.xml/SingularField + MAJOR + Title of issues: Perhaps '{0}' could be replaced by a local variable. +

        Reports fields which may be converted to a local variable. This is so because +in every method where the field is used, it is assigned before it is first read. +Hence, the value that the field had before the method call may not be observed, +so it might as well not be stored in the enclosing object.

        +

        Limitations:

        +
        • We can only check private fields for now.
        • The rule is not aware of threading, so it may cause false positives in concurrent code. Such FPs are best handled by suppression (see also the ignoredAnnotations property).
        +

        Example

        +

         public class Foo {
        +     private int x; // this will be reported
        + 
        +     public int foo(int y) {
        +        x = y + 5; // assigned before any read
        +        return x;
        +     }
        + 
        +     public int fooOk(int y) {
        +        int z = y + 5; // might as well be a local like here
        +        return z;
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + design + + ignoredAnnotations + + java.lang.Deprecated,javafx.fxml.FXML,lombok.Getter,lombok.Setter,lombok.experimental.Delegate + STRING + + + violationSuppressRegex + + + STRING + +
        + + StaticEJBFieldShouldBeFinal + Static EJBField should be final + category/java/errorprone.xml/StaticEJBFieldShouldBeFinal + MAJOR + Title of issues: EJB's shouldn't have non-final static fields +

        According to the J2EE specification, an EJB should not have any static fields +with write access. However, static read-only fields are allowed. This ensures proper +behavior especially when instances are distributed by the container on several JREs.

        +

        Example

        +

         public class SomeEJB extends EJBObject implements EJBLocalHome {
        + 
        +     private static int CountA;          // poor, field can be edited
        + 
        +     private static final int CountB;    // preferred, read-only access
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + StringBufferInstantiationWithChar + StringBuffer instantiation with char + category/java/errorprone.xml/StringBufferInstantiationWithChar + MINOR + Title of issues: Argument to new StringBuilder() or new StringBuffer() is implicitly converted from char to int +

        Individual character values provided as initialization arguments will be converted into integers. +This can lead to internal buffer sizes that are larger than expected. Some examples:

        +

         new StringBuffer()      //  16
        + new StringBuffer(6)     //  6
        + new StringBuffer("hello world")  // 11 + 16 = 27
        + new StringBuffer('A')   //  chr(A) = 65
        + new StringBuffer("A")   //  1 + 16 = 17
        + 
        + new StringBuilder()     //  16
        + new StringBuilder(6)    //  6
        + new StringBuilder("hello world")  // 11 + 16 = 27
        + new StringBuilder('C')   //  chr(C) = 67
        + new StringBuilder("A")   //  1 + 16 = 17

        +

        Example

        +

         // misleading instantiation, these buffers
        + // are actually sized to 99 characters long
        + StringBuffer  sb1 = new StringBuffer('c');
        + StringBuilder sb2 = new StringBuilder('c');
        + 
        + // in these forms, just single characters are allocated
        + StringBuffer  sb3 = new StringBuffer("c");
        + StringBuilder sb4 = new StringBuilder("c");

        +

        Alternative rule: java:S1317

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + StringInstantiation + String instantiation + category/java/performance.xml/StringInstantiation + CRITICAL + Title of issues: Avoid instantiating String objects; this is usually unnecessary. +

        Avoid instantiating String objects; this is usually unnecessary since they are immutable and can be safely shared.

        +

        Example

        +

         private String bar = new String("bar"); // just do a String bar = "bar";

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + StringToString + String to string + category/java/performance.xml/StringToString + MAJOR + Title of issues: Avoid calling toString() on String objects; this is unnecessary. +

        Avoid calling toString() on objects already known to be string instances; this is unnecessary.

        +

        Example

        +

         private String baz() {
        +     String bar = "howdy";
        +     return bar.toString();
        + }

        +

        Alternative rule: java:S1858

        +

        Full documentation

        ]]>
        + pmd + performance + has-sonar-alternative +
        + + SuspiciousEqualsMethodName + Suspicious equals method name + category/java/errorprone.xml/SuspiciousEqualsMethodName + CRITICAL + Title of issues: The method name and parameter number are suspiciously close to equals(Object) +

        The method name and parameter number are suspiciously close to Object.equals, which can denote an +intention to override it. However, the method does not override Object.equals, but overloads it instead. +Overloading Object.equals method is confusing for other programmers, error-prone and hard to maintain, +especially when using inheritance, because @Override annotations used in subclasses can provide a false +sense of security. For more information on Object.equals method, see Effective Java, 3rd Edition, +Item 10: Obey the general contract when overriding equals.

        +

        Example

        +

         public class Foo {
        +    public int equals(Object o) {
        +      // oops, this probably was supposed to be boolean equals
        +    }
        +    public boolean equals(String s) {
        +      // oops, this probably was supposed to be equals(Object)
        +    }
        +    public boolean equals(Object o1, Object o2) {
        +      // oops, this probably was supposed to be equals(Object)
        +    }
        + }

        +

        Alternative rule: java:S1201

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + SuspiciousHashcodeMethodName + Suspicious hashcode method name + category/java/errorprone.xml/SuspiciousHashcodeMethodName + MAJOR + Title of issues: The method name and return type are suspiciously close to hashCode() +

        The method name and return type are suspiciously close to hashCode(), which may denote an intention +to override the hashCode() method.

        +

        Example

        +

         public class Foo {
        +     public int hashcode() { // oops, this probably was supposed to be 'hashCode'
        +     }
        + }

        +

        Alternative rule: java:S1221

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + SuspiciousOctalEscape + Suspicious octal escape + category/java/errorprone.xml/SuspiciousOctalEscape + MAJOR + Title of issues: Suspicious decimal characters following octal escape in string literal: {0} +

        A suspicious octal escape sequence was found inside a String literal. +The Java language specification (section 3.10.6) says an octal +escape sequence inside a literal String shall consist of a backslash +followed by:

        +

        OctalDigit | OctalDigit OctalDigit | ZeroToThree OctalDigit OctalDigit

        +

        Any octal escape sequence followed by non-octal digits can be confusing, +e.g. "\038" is interpreted as the octal escape sequence "\03" followed by +the literal character "8".

        +

        Example

        +

         public void foo() {
        +   // interpreted as octal 12, followed by character '8'
        +   System.out.println("suspicious: \128");
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone + + violationSuppressRegex + + + STRING + +
        + + SwitchDensity + Switch density + category/java/design.xml/SwitchDensity + MAJOR + Title of issues: A high ratio of statements to labels in a switch statement. Consider refactoring. +

        A high ratio of statements to labels in a switch statement implies that the switch statement +is overloaded. Consider moving the statements into new methods or creating subclasses based +on the switch variable.

        +

        Example

        +

         public class Foo {
        +   public void bar(int x) {
        +     switch (x) {
        +       case 1: {
        +         // lots of statements
        +         break;
        +       } case 2: {
        +         // lots of statements
        +         break;
        +       }
        +     }
        +   }
        + }

        +

        Alternative rule: java:S1151

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + minimum + + 10 + INTEGER + +
        + + SystemPrintln + System println + category/java/bestpractices.xml/SystemPrintln + CRITICAL + Title of issues: Usage of System.out/err +

        References to System.(out|err).print are usually intended for debugging purposes and can remain in +the codebase even in production code. By using a logger one can enable/disable this behaviour at +will (and by priority) and avoid clogging the Standard out log.

        +

        Example

        +

         class Foo{
        +     Logger log = Logger.getLogger(Foo.class.getName());
        +     public void testA () {
        +         System.out.println("Entering test");
        +         // Better use this
        +         log.fine("Entering test");
        +     }
        + }

        +

        Alternative rule: java:S106

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative +
        + + TestClassWithoutTestCases + Test class without test cases + category/java/errorprone.xml/TestClassWithoutTestCases + MAJOR + Title of issues: The class '{0}' might be a test class, but it contains no test cases. +

        Test classes typically end with the suffix "Test", "Tests" or "TestCase". Having a non-test class with that name +is not a good practice, since most people will assume it is a test case. Test classes have test methods +named "testXXX" (JUnit3) or use annotations (e.g. @Test).

        +

        The suffix can be configured using the property testClassPattern. To disable the detection of possible test classes +by name, set this property to an empty string.

        +

        Example

        +

         //Consider changing the name of the class if it is not a test
        + //Consider adding test methods if it is a test
        + public class CarTest {
        +    public static void main(String[] args) {
        +     // do something
        +    }
        +    // code
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone + + testClassPattern + + ^(?:.*\.)?Test[^\.]*$|^(?:.*\.)?.*Tests?$|^(?:.*\.)?.*TestCase$ + STRING + + + violationSuppressRegex + + + STRING + +
        + + TooFewBranchesForSwitch + Too few branches for switch + category/java/performance.xml/TooFewBranchesForSwitch + MAJOR + Title of issues: A switch with less than three branches is inefficient, use a 'if statement' instead. +

        Switch statements are intended to be used to support complex branching behaviour. Using a switch for only a few +cases is ill-advised, since switches are not as easy to understand as if-else statements. In these cases use the +if-else statement to increase code readability.

        +

        Note: This rule was named TooFewBranchesForASwitchStatement before PMD 7.7.0.

        +

        Example

        +

         // With a minimumNumberCaseForASwitch of 3
        + public class Foo {
        +     public void bar(int condition) {
        +         switch (condition) {
        +             case 1:
        +                 instruction;
        +                 break;
        +             default:
        +                 break; // not enough for a 'switch' stmt, a simple 'if' stmt would have been more appropriate
        +         }
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + performance + + minimumNumberCaseForASwitch + + 3 + INTEGER + +
        + + TooManyFields + Too many fields + category/java/design.xml/TooManyFields + MAJOR + Title of issues: Too many fields +

        Classes that have too many fields can become unwieldy and could be redesigned to have fewer fields, +possibly through grouping related fields in new objects. For example, a class with individual +city/state/zip fields could park them within a single Address field.

        +

        Example

        +

         public class Person {   // too many separate fields
        +    int birthYear;
        +    int birthMonth;
        +    int birthDate;
        +    float height;
        +    float weight;
        + }
        + 
        + public class Person {   // this is more manageable
        +    Date birthDate;
        +    BodyMeasurements measurements;
        + }

        +

        Full documentation

        ]]>
        + pmd + design + + maxfields + + 15 + INTEGER + +
        + + TooManyMethods + Too many methods + category/java/design.xml/TooManyMethods + MAJOR + Title of issues: This class has too many methods, consider refactoring it. +

        A class with too many methods is probably a good suspect for refactoring, in order to reduce its +complexity and find a way to have more fine grained objects.

        +

        Alternative rule: java:S1448

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + maxmethods + + 10 + INTEGER + +
        + + TooManyStaticImports + Too many static imports + category/java/codestyle.xml/TooManyStaticImports + MINOR + Title of issues: Too many static imports may lead to messy code +

        If you overuse the static import feature, it can make your program unreadable and +unmaintainable, polluting its namespace with all the static members you import. +Readers of your code (including you, a few months after you wrote it) will not know +which class a static member comes from (Sun 1.5 Language Guide).

        +

        Example

        +

         import static Lennon;
        + import static Ringo;
        + import static George;
        + import static Paul;
        + import static Yoko; // Too much !

        +

        Full documentation

        ]]>
        + pmd + codestyle + + maximumStaticImports + + 4 + INTEGER + +
        + + TypeParameterNamingConventions + Type parameter naming conventions + category/java/codestyle.xml/TypeParameterNamingConventions + MINOR + Title of issues: The {0} name '{1}' doesn't match '{2}' +

        Configurable naming conventions for type parameters in generic types and methods. + This rule reports type parameter declarations which do not match the configured regex. + Type parameters can appear on classes, interfaces, enums, records, and methods.

        +

        By default, this rule uses the standard Java naming convention (single uppercase letter).

        +

        Example

        +

         // Generic types - valid
        + public interface Repository<T> { }
        + public class Cache<K, V> { }
        + 
        + // Generic types - invalid
        + public interface Repository<type> { }      // lowercase
        + public class Cache<KEY, VALUE> { }         // multiple letters
        + 
        + // Generic methods - valid
        + public class Util {
        +     public static <T> T identity(T value) { return value; }
        +     public <T, R> R transform(T input, Function<T, R> mapper) { }
        + }
        + 
        + // Generic methods - invalid
        + public class Util {
        +     public static <element> element get(element value) { }  // lowercase
        +     public <INPUT, OUTPUT> OUTPUT convert(INPUT in) { }     // multiple letters
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + typeParameterNamePattern + + [A-Z] + STRING + + + violationSuppressRegex + + + STRING + +
        + + UncommentedEmptyConstructor + Uncommented empty constructor + category/java/documentation.xml/UncommentedEmptyConstructor + MAJOR + Title of issues: Document empty constructor +

        Uncommented Empty Constructor finds instances where a constructor does not +contain statements, but there is no comment. By explicitly commenting empty +constructors it is easier to distinguish between intentional (commented) +and unintentional empty constructors.

        +

        Example

        +

         public Foo() {
        +   // This constructor is intentionally empty. Nothing special is needed here.
        + }

        +

        Alternative rule: java:S2094

        +

        Full documentation

        ]]>
        + pmd + documentation + has-sonar-alternative + + ignoreExplicitConstructorInvocation + + false + BOOLEAN + +
        + + UncommentedEmptyMethodBody + Uncommented empty method body + category/java/documentation.xml/UncommentedEmptyMethodBody + MAJOR + Title of issues: Document empty method body +

        Uncommented Empty Method Body finds instances where a method body does not contain +statements, but there is no comment. By explicitly commenting empty method bodies +it is easier to distinguish between intentional (commented) and unintentional +empty methods.

        +

        Example

        +

         public void doSomething() {
        + }

        +

        Alternative rule: java:S1186

        +

        Full documentation

        ]]>
        + pmd + documentation + has-sonar-alternative +
        + + UnconditionalIfStatement + Unconditional if statement + category/java/errorprone.xml/UnconditionalIfStatement + MAJOR + Title of issues: Do not use 'if' statements that are always true or always false +

        Do not use "if" statements whose conditionals are always true or always false.

        +

        Example

        +

         public class Foo {
        +     public void close() {
        +         if (true) {        // fixed conditional, not recommended
        +             // ...
        +         }
        +     }
        + }

        +

        Alternative rule: java:S2583

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + UnitTestAssertionsShouldIncludeMessage + Unit test assertions should include message + category/java/bestpractices.xml/UnitTestAssertionsShouldIncludeMessage + MAJOR + Title of issues: Unit test assertions should include a message +

        Unit assertions should include an informative message - i.e., use the three-argument version of +assertEquals(), not the two-argument version.

        +

        This rule supports tests using JUnit (3, 4 and 5) and TestNG.

        +

        Note: This rule was named JUnitAssertionsShouldIncludeMessage before PMD 7.7.0.

        +

        Example

        +

         public class Foo {
        +     @Test
        +     public void testSomething() {
        +         assertEquals("foo", "bar");
        +         // Use the form:
        +         // assertEquals("Foo does not equals bar", "foo", "bar");
        +         // instead
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + UnitTestContainsTooManyAsserts + Unit test contains too many asserts + category/java/bestpractices.xml/UnitTestContainsTooManyAsserts + MAJOR + Title of issues: Unit tests should not contain more than ${maximumAsserts} assert(s). +

        Unit tests should not contain too many asserts. Many asserts are indicative of a complex test, for which + it is harder to verify correctness. Consider breaking the test scenario into multiple, shorter test scenarios. + Customize the maximum number of assertions used by this Rule to suit your needs.

        +

        This rule checks for JUnit (3, 4 and 5) and TestNG Tests.

        +

        Note: This rule was named JUnitTestContainsTooManyAsserts before PMD 7.7.0.

        +

        Example

        +

         public class MyTestCase {
        +     // Ok
        +     @Test
        +     public void testMyCaseWithOneAssert() {
        +         boolean myVar = false;
        +         assertFalse("should be false", myVar);
        +     }
        + 
        +     // Bad, too many asserts (assuming max=1)
        +     @Test
        +     public void testMyCaseWithMoreAsserts() {
        +         boolean myVar = false;
        +         assertFalse("myVar should be false", myVar);
        +         assertEquals("should equals false", false, myVar);
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + maximumAsserts + + 1 + INTEGER + + + extraAssertMethodNames + + + STRING + +
        + + UnitTestShouldIncludeAssert + Unit test should include assert + category/java/bestpractices.xml/UnitTestShouldIncludeAssert + MAJOR + Title of issues: This unit test should include assert() or fail() +

        Unit tests should include at least one assertion. This makes the tests more robust, and using assert + with messages provide the developer a clearer idea of what the test does.

        +

        This rule checks for JUnit (3, 4 and 5) and TestNG Tests.

        +

        Note: This rule was named JUnitTestsShouldIncludeAssert before PMD 7.7.0.

        +

        Example

        +

         public class Foo {
        +    @Test
        +    public void testSomething() {
        +       Bar b = findBar();
        +       // This is better than having a NullPointerException
        +       // assertNotNull("bar not found", b);
        +       b.work();
        +    }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + extraAssertMethodNames + + + STRING + +
        + + UnitTestShouldUseAfterAnnotation + Unit test should use after annotation + category/java/bestpractices.xml/UnitTestShouldUseAfterAnnotation + MAJOR + Title of issues: Apply the correct annotation if this method is used to clean up the tests +

        This rule detects methods called tearDown() that are not properly annotated as a cleanup method. +This is primarily intended to assist in upgrading from JUnit 3, where tear down methods were required to be called tearDown(). +To a lesser extent, this may help detect omissions even under newer JUnit versions or under TestNG, +as long as you are following this convention to name the methods.

        +
        • JUnit 4 will only execute methods annotated with @After after running each test.
        • JUnit 5 introduced @AfterEach and @AfterAll annotations to execute methods after each test or after all tests in the class, respectively.
        • TestNG provides the annotations @AfterMethod and @AfterClass to execute methods after each test or after tests in the class, respectively.
        +

        Note: This rule was named JUnit4TestShouldUseAfterAnnotation before PMD 7.7.0.

        +

        Example

        +

         public class MyTest {
        +     public void tearDown() {
        +         bad();
        +     }
        + }
        + public class MyTest2 {
        +     @After public void tearDown() {
        +         good();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + UnitTestShouldUseBeforeAnnotation + Unit test should use before annotation + category/java/bestpractices.xml/UnitTestShouldUseBeforeAnnotation + MAJOR + Title of issues: Apply the correct annotation if this method is used to set up the tests +

        This rule detects methods called setUp() that are not properly annotated as a setup method. +This is primarily intended to assist in upgrading from JUnit 3, where setup methods were required to be called setUp(). +To a lesser extent, this may help detect omissions even under newer JUnit versions or under TestNG, +as long as you are following this convention to name the methods.

        +
        • JUnit 4 will only execute methods annotated with @Before before all tests.
        • JUnit 5 introduced @BeforeEach and @BeforeAll annotations to execute methods before each test or before all tests in the class, respectively.
        • TestNG provides the annotations @BeforeMethod and @BeforeClass to execute methods before each test or before tests in the class, respectively.
        +

        Note: This rule was named JUnit4TestShouldUseBeforeAnnotation before PMD 7.7.0.

        +

        Example

        +

         public class MyTest {
        +     public void setUp() {
        +         bad();
        +     }
        + }
        + public class MyTest2 {
        +     @Before public void setUp() {
        +         good();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + UnitTestShouldUseTestAnnotation + Unit test should use test annotation + category/java/bestpractices.xml/UnitTestShouldUseTestAnnotation + MAJOR + Title of issues: Unit tests should use the @Test annotation or won't be run. In case of JUnit 5, test methods might use @RepeatedTest, @TestFactory, @TestTemplate or @ParameterizedTest annotations instead. +

        The rule will detect any test method starting with "test" that is not properly annotated, and will therefore not be run.

        +

        In JUnit 4, only methods annotated with the @Test annotation are executed. + In JUnit 5, one of the following annotations should be used for tests: @Test, @RepeatedTest, @TestFactory, @TestTemplate or @ParameterizedTest. + In TestNG, only methods annotated with the @Test annotation are executed.

        +

        Note: This rule was named JUnit4TestShouldUseTestAnnotation before PMD 7.7.0.

        +

        Example

        +

         public class MyTest {
        +     public void testBad() {
        +         doSomething();
        +     }
        + 
        +     @Test
        +     public void testGood() {
        +         doSomething();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + testClassPattern + + Test + STRING + +
        + + UnnecessaryAnnotationValueElement + Unnecessary annotation value element + category/java/codestyle.xml/UnnecessaryAnnotationValueElement + MINOR + Title of issues: Avoid the use of value in annotations when it's the only element +

        Avoid the use of value in annotations when it's the only element.

        +

        Example

        +

         @TestClassAnnotation(value = "TEST")
        + public class Foo {
        + 
        +     @TestMemberAnnotation(value = "TEST")
        +     private String y;
        + 
        +     @TestMethodAnnotation(value = "TEST")
        +     public void bar() {
        +         int x = 42;
        +         return;
        +     }
        + }
        + 
        + // should be
        + 
        + @TestClassAnnotation("TEST")
        + public class Foo {
        + 
        +     @TestMemberAnnotation("TEST")
        +     private String y;
        + 
        +     @TestMethodAnnotation("TEST")
        +     public void bar() {
        +         int x = 42;
        +         return;
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + java7Compatibility + + false + BOOLEAN + +
        + + UnnecessaryBooleanAssertion + Unnecessary boolean assertion + category/java/errorprone.xml/UnnecessaryBooleanAssertion + MAJOR + Title of issues: assertTrue(true) or similar statements are unnecessary +

        A JUnit test assertion with a boolean literal is unnecessary since it always will evaluate to the same thing. +Consider using flow control (in case of assertTrue(false) or similar) or simply removing +statements like assertTrue(true) and assertFalse(false). If you just want a test to halt after finding +an error, use the fail() method and provide an indication message of why it did.

        +

        Example

        +

         public class SimpleTest extends TestCase {
        +     public void testX() {
        +         assertTrue(true);            // serves no real purpose - remove it
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + UnnecessaryBoxing + Unnecessary boxing + category/java/codestyle.xml/UnnecessaryBoxing + MINOR + Title of issues: Unnecessary {0} +

        Reports explicit boxing and unboxing conversions that may safely be removed, + either because they would be inserted by the compiler automatically, + or because they're semantically a noop (eg unboxing a value to rebox it immediately).

        +

        Note that this only handles boxing and unboxing conversions occurring through + calls to valueOf or one of the intValue, byteValue, etc. methods. Casts + that command a conversion are reported by {% rule UnnecessaryCast %} instead.

        +

        Example

        +

         {
        +         // Instead of
        +         Integer integer = Integer.valueOf(2);
        +         // you may just write
        +         Integer integer = 2;
        + 
        +         int i = integer.intValue(); // similarly for unboxing
        + 
        +         // Instead of
        +         int x = Integer.valueOf("42");
        +         // you may just write
        +         int x = Integer.parseInt("42");
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + violationSuppressRegex + + + STRING + +
        + + UnnecessaryCaseChange + Unnecessary case change + category/java/errorprone.xml/UnnecessaryCaseChange + MAJOR + Title of issues: Using equalsIgnoreCase() is cleaner than using toUpperCase/toLowerCase().equals(). +

        Using equalsIgnoreCase() is faster than using toUpperCase/toLowerCase().equals()

        +

        Example

        +

         boolean answer1 = buz.toUpperCase().equals("BAZ");              // should be buz.equalsIgnoreCase("BAZ")
        + 
        + boolean answer2 = buz.toUpperCase().equalsIgnoreCase("BAZ");    // another unnecessary toUpperCase()

        +

        Alternative rule: java:S1157

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + UnnecessaryCast + Unnecessary cast + category/java/codestyle.xml/UnnecessaryCast + MINOR + Title of issues: Unnecessary cast ({0}) +

        Detects casts which could be removed as the operand of the cast is already suitable +for the context type. For instance, in the following: +

         Object context = (Comparable) "o";
        +The cast is unnecessary. This is because String already is a subtype of both +Comparable and Object.

        +

        This will also flag casts that can be avoided because of the autoboxing feature of Java 5. +

         Integer integer = (Integer) 1;
        +The literal would be autoboxed to Integer anyway.

        +

        Examples

        +

        Example 1

        +

         import java.util.function.Function;
        + class SomeClass {
        +    static {
        +       Object o; long l; int i; Integer boxedInt;
        + 
        +       // reference conversions
        + 
        +       o = (Object) new SomeClass();      // unnecessary
        +       o = (SomeClass) o;                 // necessary (narrowing cast)
        +       o = (Comparable<String>) "string"; // unnecessary
        + 
        +       // primitive conversions
        + 
        +       l = (long) 2;   // unnecessary
        +       l = (long) 2.0; // necessary (narrowing cast)
        +       l = (byte) i;   // necessary (narrowing cast)
        + 
        +       // boxing/unboxing casts (since java 5)
        + 
        +       o = (Integer) 3;    // unnecessary (autoboxing would apply)
        +       o = (long) 3;       // necessary (would be boxed to Long)
        +       l = (int) boxedInt; // necessary (cannot cast Integer to long)
        + 
        +       // casts that give a target type to a lambda/ method ref are necessary
        + 
        +       o = (Function<Integer, String>) Integer::toString; // necessary (no target type)
        +    }
        + }

        +

        Example 2

        +

         import java.util.*;
        + class SomeClass {
        +    static {
        +        /* Casts involving access to collections were common before Java 5, because collections
        +         * were not generic. This rule may hence be useful when converting from using a raw
        +         * type like `List` to a parameterized type like `List<String>`.
        +         */
        +        List<String> stringList = Arrays.asList("a", "b");
        +        String element = (String) stringList.get(0); // this cast is unnecessary
        +    }
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + violationSuppressRegex + + + STRING + +
        + + UnnecessaryConstructor + Unnecessary constructor + category/java/codestyle.xml/UnnecessaryConstructor + MINOR + Title of issues: Avoid unnecessary constructors - the compiler will generate these for you +

        This rule detects when a constructor is not necessary; i.e., when there is only one constructor and the +constructor is identical to the default constructor. The default constructor should has same access +modifier as the declaring class. In an enum type, the default constructor is implicitly private.

        +

        Example

        +

         public class Foo {
        +   public Foo() {}
        + }

        +

        Alternative rule: java:S1186

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + ignoredAnnotations + + javax.inject.Inject,com.google.inject.Inject,org.springframework.beans.factory.annotation.Autowired + STRING + +
        + + UnnecessaryConversionTemporary + Unnecessary conversion temporary + category/java/errorprone.xml/UnnecessaryConversionTemporary + MAJOR + Title of issues: Avoid unnecessary temporaries when converting primitives to Strings +

        Avoid the use temporary objects when converting primitives to Strings. Use the static conversion methods +on the wrapper classes instead.

        +

        Example

        +

         public String convert(int x) {
        +     String foo = new Integer(x).toString(); // this wastes an object
        + 
        +     return Integer.toString(x);             // preferred approach
        + }

        +

        Alternative rule: java:S1158

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + UnnecessaryFullyQualifiedName + Unnecessary fully qualified name + category/java/codestyle.xml/UnnecessaryFullyQualifiedName + MINOR + Title of issues: Unnecessary qualifier '{0}': '{1}' is already in scope{2} +

        Import statements allow the use of non-fully qualified names. The use of a fully qualified name +which is covered by an import statement is redundant. Consider using the non-fully qualified name.

        +

        Example

        +

         import java.util.List;
        + 
        + public class Foo {
        +     private java.util.List list1;   // Unnecessary FQN
        +     private List list2;             // More appropriate given import of 'java.util.List'
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + reportStaticMethods + + true + BOOLEAN + + + reportStaticFields + + true + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + UnnecessaryImport + Unnecessary import + category/java/codestyle.xml/UnnecessaryImport + MINOR + Title of issues: Unnecessary import '{0}' +

        Reports import statements that can be removed. They are either unused, + duplicated, or the members they import are already implicitly in scope, + because they're in java.lang, or the current package.

        +

        If some imports cannot be resolved, for instance because you run PMD with + an incomplete auxiliary classpath, some imports may be conservatively marked + as used even if they're not to avoid false positives.

        +

        Example

        +

         import java.io.File;            // not used, can be removed
        +             import java.util.Collections;   // used below
        +             import java.util.*;             // so this one is not used
        + 
        +             import java.lang.Object;        // imports from java.lang, unnecessary
        +             import java.lang.Object;        // duplicate, unnecessary
        + 
        +             public class Foo {
        +                 static Object emptyList() {
        +                     return Collections.emptyList();
        +                 }
        +             }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + violationSuppressRegex + + + STRING + +
        + + UnnecessaryLocalBeforeReturn + Unnecessary local before return + category/java/codestyle.xml/UnnecessaryLocalBeforeReturn + MINOR + Title of issues: Consider simply returning the value vs storing it in local variable '{0}' +

        Avoid the creation of unnecessary local variables.

        +

        This rule has been deprecated since 7.17.0. Use the new rule +{%rule VariableCanBeInlined %} instead, which additionally covers throw statements.

        +

        Example

        +

         public class Foo {
        +    public int foo() {
        +      int x = doSomething();
        +      return x;  // instead, just 'return doSomething();'
        +    }
        + }

        +

        Alternative rule: java:S1488

        +

        Full documentation

        ]]>
        + DEPRECATED + pmd + codestyle + has-sonar-alternative + + statementOrderMatters + + true + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + UnnecessaryModifier + Unnecessary modifier + category/java/codestyle.xml/UnnecessaryModifier + MINOR + Title of issues: Unnecessary modifier{0} on {1} '{2}'{3} +

        Fields in interfaces and annotations are automatically public static final, and methods are public abstract. +Classes, interfaces or annotations nested in an interface or annotation are automatically public static +(all nested interfaces and annotations are automatically static). +Nested enums are automatically static. +For historical reasons, modifiers which are implied by the context are accepted by the compiler, but are superfluous.

        +

        Example

        +

         public @interface Annotation {
        +     public abstract void bar();     // both abstract and public are ignored by the compiler
        +     public static final int X = 0;  // public, static, and final all ignored
        +     public static class Bar {}      // public, static ignored
        +     public static interface Baz {}  // ditto
        + }
        + public interface Foo {
        +     public abstract void bar();     // both abstract and public are ignored by the compiler
        +     public static final int X = 0;  // public, static, and final all ignored
        +     public static class Bar {}      // public, static ignored
        +     public static interface Baz {}  // ditto
        + }
        + public class Bar {
        +     public static interface Baz {}  // static ignored
        +     public static enum FooBar {    // static ignored
        +         FOO;
        +     }
        + }
        + public class FooClass {
        +     static record BarRecord() {}     // static ignored
        + }
        + public interface FooInterface {
        +     static record BarRecord() {}     // static ignored
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + violationSuppressRegex + + + STRING + +
        + + UnnecessaryReturn + Unnecessary return + category/java/codestyle.xml/UnnecessaryReturn + MINOR + Title of issues: Unnecessary return statement +

        Avoid the use of unnecessary return statements. A return is unnecessary when no +instructions follow anyway.

        +

        Example

        +

         public class Foo {
        +     public void bar() {
        +         int x = 42;
        +         return;
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + UnnecessarySemicolon + Unnecessary semicolon + category/java/codestyle.xml/UnnecessarySemicolon + MINOR + Title of issues: Unnecessary semicolon +

        Reports unnecessary semicolons (so called "empty statements" and "empty declarations"). + These can be removed without changing the program. The Java grammar + allows them for historical reasons, but they should be avoided.

        +

        This rule will not report empty statements that are syntactically + required, for instance, because they are the body of a control statement.

        +

        This rule replaces EmptyStatementNotInLoop.

        +

        Example

        +

         class Foo {
        +     {
        +         toString();; // one of these semicolons is unnecessary
        +         if (true); // this semicolon is not unnecessary, but it could be an empty block instead (not reported)
        +     }
        + }; // this semicolon is unnecessary

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + UnnecessaryVarargsArrayCreation + Unnecessary varargs array creation + category/java/bestpractices.xml/UnnecessaryVarargsArrayCreation + MAJOR + Title of issues: Unnecessary explicit array creation for varargs method call +

        Reports explicit array creation when a varargs is expected. + For instance: +

         Arrays.asList(new String[] { "foo", "bar", });
        + can be replaced by: +
         Arrays.asList("foo", "bar");

        +

        Example

        +

         import java.util.Arrays;
        + 
        + class C {
        +     static {
        +         Arrays.asList(new String[]{"foo", "bar",});
        +         // should be
        +         Arrays.asList("foo", "bar");
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + UnnecessaryWarningSuppression + Unnecessary warning suppression + category/java/bestpractices.xml/UnnecessaryWarningSuppression + MAJOR + Title of issues: Unused suppression {0}. +

        This rule reports suppression comments and annotations that did not suppress any PMD violation. + Note that violations of this rule cannot be suppressed.

        +

        Please note:

        +
        • The rule will report those suppressions comments/annotations that did not suppress a violation _during the current run_. That means you cannot run this rule separately from other rules, it must
        • The rule for now only reports annotations specific to PMD, like @SuppressWarnings("PMD"). For instance @SuppressWarnings("all") is never reported as we cannot know if another tool is producing a
        +

        Example

        +

         public class Something {
        +                 // Unless some rule triggered on the following line, this rule will report the comment:
        +                 private void foo() {} // NOPMD
        +             }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + violationSuppressRegex + + + STRING + +
        + + UnsynchronizedStaticFormatter + Unsynchronized static formatter + category/java/multithreading.xml/UnsynchronizedStaticFormatter + MAJOR + Title of issues: Static Formatter objects should be accessed in a synchronized manner +

        Instances of java.text.Format are generally not synchronized. +Sun recommends using separate format instances for each thread. +If multiple threads must access a static formatter, the formatter must be +synchronized on block level.

        +

        Example

        +

         public class Foo {
        +     private static final SimpleDateFormat sdf = new SimpleDateFormat();
        +     void bar() {
        +         sdf.format(); // poor, no thread-safety
        +     }
        +     void foo() {
        +         synchronized (sdf) { // preferred
        +             sdf.format();
        +         }
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + multithreading + + allowMethodLevelSynchronization + + false + BOOLEAN + +
        + + UnusedAssignment + Unused assignment + category/java/bestpractices.xml/UnusedAssignment + MAJOR + Title of issues: The value assigned to this variable is never used or always overwritten +

        Reports assignments to variables that are never used before the variable is overwritten, + or goes out of scope. Unused assignments are those for which + 1. The variable is never read after the assignment, or + 2. The assigned value is always overwritten by other assignments before the next read of + the variable.

        +

        The rule tracks assignments to fields of this, and static fields of the current class. + This may cause some false positives in timing-sensitive concurrent code, which the rule cannot detect.

        +

        The rule may be suppressed with the standard @SuppressWarnings("unused") tag.

        +

        The rule subsumes UnusedLocalVariable, and UnusedFormalParameter. + Those violations are filtered + out by default, in case you already have enabled those rules, but may be enabled with the property + reportUnusedVariables. Variables whose name starts with ignored or unused are filtered out, as + is standard practice for exceptions.

        +

        Limitations:

        +
        • The rule currently cannot know which method calls throw exceptions, or which exceptions they throw. In the body of a try block, every method or constructor call is assumed to throw. This may cause false-negatives.
        • The rule cannot resolve assignments across constructors, when they're called with the special this(...) syntax. This may cause false-negatives.
        +

        Both of those limitations may be partly relaxed in PMD 7.

        +

        Examples

        +

        Example 1

        +

         class A {
        +                 // this field initializer is redundant,
        +                 // it is always overwritten in the constructor
        +                 int f = 1;
        + 
        +                 A(int f) {
        +                     this.f = f;
        +                 }
        +             }

        +

        Example 2

        +

         class B {
        + 
        +     int method(int i, int j) {
        +         // this initializer is redundant,
        +         // it is overwritten in all branches of the `if`
        +         int k = 0;
        + 
        +         // Both the assignments to k are unused, because k is
        +         // not read after the if/else
        +         // This may hide a bug: the programmer probably wanted to return k
        +         if (i < j)
        +             k = i;
        +         else
        +             k = j;
        + 
        +         return j;
        +     }
        + 
        + }

        +

        Example 3

        +

         class C {
        + 
        +     int method() {
        +         int i = 0;
        + 
        +         checkSomething(++i);
        +         checkSomething(++i);
        +         checkSomething(++i);
        +         checkSomething(++i);
        + 
        +         // That last increment is not reported unless
        +         // the property `checkUnusedPrefixIncrement` is
        +         // set to `true`
        +         // Technically it could be written (i+1), but it
        +         // is not very important
        +     }
        + 
        + }

        +

        Example 4

        +

         class C {
        + 
        +     // variables that are truly unused (at most assigned to, but never accessed)
        +     // are only reported if property `reportUnusedVariables` is true
        + 
        +     void method(int param) { } // for example this method parameter
        + 
        +     // even then, you can suppress the violation with an annotation:
        + 
        +     void method(@SuppressWarning("unused") int param) { } // no violation, even if `reportUnusedVariables` is true
        + 
        +     // For catch parameters, or for resources which don't need to be used explicitly,
        +     // you can give a name that starts with "ignored" to ignore such warnings
        + 
        +     {
        +         try (Something ignored = Something.create()) {
        +             // even if ignored is unused, it won't be flagged
        +             // its purpose might be to side-effect in the create/close routines
        + 
        +         } catch (Exception e) { // this is unused and will cause a warning if `reportUnusedVariables` is true
        +             // you should choose a name that starts with "ignored"
        +             return;
        +         }
        +     }
        + 
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + checkUnusedPrefixIncrement + + false + BOOLEAN + + + reportUnusedVariables + + false + BOOLEAN + +
        + + UnusedFormalParameter + Unused formal parameter + category/java/bestpractices.xml/UnusedFormalParameter + MAJOR + Title of issues: Avoid unused {0} parameters such as '{1}'. +

        Reports parameters of methods and constructors that are not referenced them in the method body. +Parameters whose name starts with ignored or unused are filtered out.

        +

        Removing unused formal parameters from public methods could cause a ripple effect through the code base. +Hence, by default, this rule only considers private methods. To include non-private methods, set the +checkAll property to true. The same applies to public constructors.

        +

        Example

        +

         public class Foo {
        +     private void bar(String howdy) {
        +         // howdy is not used
        +     }
        + }

        +

        Alternative rule: java:S1172

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative + + checkAll + + false + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + UnusedLocalVariable + Unused local variable + category/java/bestpractices.xml/UnusedLocalVariable + MAJOR + Title of issues: Avoid unused local variables such as '{0}'. +

        Detects when a local variable is declared and/or assigned, but not used. +Variables whose name starts with ignored or unused are filtered out.

        +

        Example

        +

         public class Foo {
        +     public void doSomething() {
        +         int i = 5; // Unused
        +     }
        + }

        +

        Alternative rule: java:S1481

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative + + violationSuppressRegex + + + STRING + +
        + + UnusedNullCheckInEquals + Unused null check in equals + category/java/errorprone.xml/UnusedNullCheckInEquals + MAJOR + Title of issues: Invoke equals() on the object you've already ensured is not null +

        After checking an object reference for null, you should invoke equals() on that object rather than passing +it to another object's equals() method.

        +

        Example

        +

         public class Test {
        + 
        +     public String method1() { return "ok";}
        +     public String method2() { return null;}
        + 
        +     public void method(String a) {
        +         String b;
        +         // I don't know it method1() can be "null"
        +         // but I know "a" is not null..
        +         // I'd better write a.equals(method1())
        + 
        +         if (a!=null && method1().equals(a)) { // will trigger the rule
        +             //whatever
        +         }
        + 
        +         if (method1().equals(a) && a != null) { // won't trigger the rule
        +             //whatever
        +         }
        + 
        +         if (a!=null && method1().equals(b)) { // won't trigger the rule
        +             //whatever
        +         }
        + 
        +         if (a!=null && "LITERAL".equals(a)) { // won't trigger the rule
        +             //whatever
        +         }
        + 
        +         if (a!=null && !a.equals("go")) { // won't trigger the rule
        +             a=method2();
        +             if (method1().equals(a)) {
        +                 //whatever
        +             }
        +         }
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + UnusedPrivateField + Unused private field + category/java/bestpractices.xml/UnusedPrivateField + MAJOR + Title of issues: Avoid unused private fields such as '{0}'. +

        Detects when a private field is declared and/or assigned a value, but not used.

        +

        Since PMD 6.50.0 private fields are ignored, if the fields are annotated with any annotation or the +enclosing class has any annotation. Annotations often enable a framework (such as dependency injection, mocking +or e.g. Lombok) which use the fields by reflection or other means. This usage can't be detected by static code analysis. +Previously these frameworks where explicitly allowed by listing their annotations in the property +"ignoredAnnotations", but that turned out to be prone of false positive for any not explicitly considered framework.

        +

        Example

        +

         public class Something {
        +     private static int FOO = 2; // Unused
        +     private int i = 5; // Unused
        +     private int j = 6;
        +     public int addOne() {
        +         return j++;
        +     }
        + }

        +

        Alternative rule: java:S1068

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative + + ignoredFieldNames + + serialVersionUID,serialPersistentFields + STRING + + + reportForAnnotations + + + STRING + + + violationSuppressRegex + + + STRING + +
        + + UnusedPrivateMethod + Unused private method + category/java/bestpractices.xml/UnusedPrivateMethod + MAJOR + Title of issues: Avoid unused private methods such as '{0}'. +

        Unused Private Method detects when a private method is declared but is unused.

        +

        Example

        +

         public class Something {
        +     private void foo() {} // unused
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + ignoredAnnotations + + java.lang.Deprecated,jakarta.annotation.PostConstruct,jakarta.annotation.PreDestroy,lombok.EqualsAndHashCode.Include + STRING + + + violationSuppressRegex + + + STRING + +
        + + UseArrayListInsteadOfVector + Use Arrays.asList + category/java/performance.xml/UseArrayListInsteadOfVector + MAJOR + Title of issues: Use ArrayList instead of Vector +

        ArrayList is a much better Collection implementation than Vector if thread-safe operation is not required.

        +

        Example

        +

         import java.util.*;
        + public class SimpleTest extends TestCase {
        +     public void testX() {
        +     Collection c1 = new Vector();
        +     Collection c2 = new ArrayList();    // achieves the same with much better performance
        +     }
        + }

        +

        Alternative rule: java:S1149

        +

        Full documentation

        ]]>
        + pmd + performance + has-sonar-alternative +
        + + UseArraysAsList + Use arrays as List + category/java/performance.xml/UseArraysAsList + MAJOR + Title of issues: Use asList instead of tight loops +

        The java.util.Arrays class has a asList() method that should be used when you want to create a new List from +an array of objects. It is faster than executing a loop to copy all the elements of the array one by one.

        +

        Note that the result of Arrays.asList() is backed by the specified array, +changes in the returned list will result in the array to be modified. +For that reason, it is not possible to add new elements to the returned list of Arrays.asList() +(UnsupportedOperationException). +You must use new ArrayList<>(Arrays.asList(...)) if that is inconvenient for you (e.g. because of concurrent access).

        +

        Example

        +

         public class Test {
        +     public void foo(Integer[] ints) {
        +         // could just use Arrays.asList(ints)
        +         List<Integer> l = new ArrayList<>(100);
        +         for (int i = 0; i < ints.length; i++) {
        +             l.add(ints[i]);
        +         }
        + 
        +         List<Integer> anotherList = new ArrayList<>();
        +         for (int i = 0; i < ints.length; i++) {
        +             anotherList.add(ints[i].toString()); // won't trigger the rule
        +         }
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + UseCollectionIsEmpty + Use Collection.isEmpty + category/java/bestpractices.xml/UseCollectionIsEmpty + MAJOR + Title of issues: Substitute calls to size() == 0 (or size() != 0, size() > 0, size() < 1) with calls to isEmpty() +

        The isEmpty() method on java.util.Collection is provided to determine if a collection has any elements. +Comparing the value of size() to 0 does not convey intent as well as the isEmpty() method.

        +

        Example

        +

         public class Foo {
        +     void good() {
        +         List foo = getList();
        +         if (foo.isEmpty()) {
        +             // blah
        +         }
        +     }
        + 
        +     void bad() {
        +         List foo = getList();
        +         if (foo.size() == 0) {
        +             // blah
        +         }
        +     }
        + }

        +

        Alternative rule: java:S1155

        +

        Full documentation

        ]]>
        + pmd + bestpractices + has-sonar-alternative +
        + + UseConcurrentHashMap + Use ConcurrentHashMap + category/java/multithreading.xml/UseConcurrentHashMap + MAJOR + Title of issues: If you run in Java5 or newer and have concurrent access, you should use the ConcurrentHashMap implementation +

        Since Java5 brought a new implementation of the Map designed for multi-threaded access, you can +perform efficient map reads without blocking other threads.

        +

        Example

        +

         public class ConcurrentApp {
        +   public void getMyInstance() {
        +     Map map1 = new HashMap();           // fine for single-threaded access
        +     Map map2 = new ConcurrentHashMap(); // preferred for use with multiple threads
        + 
        +     // the following case will be ignored by this rule
        +     Map map3 = someModule.methodThatReturnMap(); // might be OK, if the returned map is already thread-safe
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + multithreading +
        + + UseCorrectExceptionLogging + Use correct exception logging + category/java/errorprone.xml/UseCorrectExceptionLogging + MAJOR + Title of issues: Use the correct logging statement for logging exceptions +

        To make sure the full stacktrace is printed out, use the logging statement with two arguments: a String and a Throwable.

        +

        This rule only applies to Apache Commons Logging.

        +

        Example

        +

         public class Main {
        +     private static final Log _LOG = LogFactory.getLog( Main.class );
        +     void bar() {
        +         try {
        +         } catch( Exception e ) {
        +             _LOG.error( e ); //Wrong!
        +         } catch( OtherException oe ) {
        +             _LOG.error( oe.getMessage(), oe ); //Correct
        +         }
        +     }
        + }

        +

        Alternative rule: java:S1166

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + UseDiamondOperator + Use diamond operator + category/java/codestyle.xml/UseDiamondOperator + MINOR + Title of issues: Explicit type arguments can be replaced by a diamond: {0} +

        In some cases, explicit type arguments in a constructor call for a generic type +may be replaced by diamond type arguments (<>), and be inferred by the compiler. +This rule recommends that you use diamond type arguments anywhere possible, since +it avoids duplication of the type arguments, and makes the code more concise and readable.

        +

        This rule is useful when upgrading a codebase to Java 1.7, Java 1.8, or Java 9. +The diamond syntax was first introduced in Java 1.7. In Java 8, improvements in Java's +type inference made more type arguments redundant. In Java 9, type arguments inference +was made possible for anonymous class constructors.

        +

        Example

        +

         import java.util.*;
        +             class Foo {
        +                 static {
        +                     List<String> strings;
        +                     strings = new ArrayList<String>(); // unnecessary duplication of type parameters
        +                     strings = new ArrayList<>();       // using diamond type arguments is more concise
        + 
        +                     strings = new ArrayList(); // accidental use of a raw type, you can use ArrayList<> instead
        + 
        +                     strings = new ArrayList<>() {
        +                         // for anonymous classes, this is possible since Java 9 only
        +                     };
        +                 }
        +             }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + violationSuppressRegex + + + STRING + +
        + + UseEnumCollections + Use enum collections + category/java/bestpractices.xml/UseEnumCollections + MAJOR + Title of issues: This collection could be an {0} +

        Wherever possible, use EnumSet or EnumMap instead of HashSet and HashMap when the keys + are of an enum type. The specialized enum collections are more space- and time-efficient. + This rule reports constructor expressions for hash sets or maps whose key + type is an enum type.

        +

        Example

        +

         import java.util.EnumMap;
        +             import java.util.HashSet;
        + 
        +             enum Example {
        +                 A, B, C;
        + 
        +                 public static Set<Example> newSet() {
        +                     return new HashSet<>(); // Could be EnumSet.noneOf(Example.class)
        +                 }
        + 
        +                 public static <V> Map<Example, V> newMap() {
        +                     return new HashMap<>(); // Could be new EnumMap<>(Example.class)
        +                 }
        +             }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + violationSuppressRegex + + + STRING + +
        + + UseEqualsToCompareStrings + Use equals to compare strings + category/java/errorprone.xml/UseEqualsToCompareStrings + MAJOR + Title of issues: Use equals() to compare strings instead of '==' or '!=' +

        Using '==' or '!=' to compare strings is only reliable if the interned string (String#intern()) +is used on both sides.

        +

        Use the equals() method instead.

        +

        Example

        +

         public boolean test(String s) {
        +     if (s == "one") return true;        // unreliable
        +     if ("two".equals(s)) return true;   // better
        +     return false;
        + }

        +

        Alternative rule: java:S1698

        +

        Full documentation

        ]]>
        + pmd + errorprone + has-sonar-alternative +
        + + UseExplicitTypes + Use explicit types + category/java/codestyle.xml/UseExplicitTypes + MINOR + Title of issues: Use Explicit Types +

        Java 10 introduced the var keyword. This reduces the amount of code written because java can infer the type +from the initializer of the variable declaration.

        +

        This is essentially a trade-off: On the one hand, it can make code more readable by eliminating redundant +information. On the other hand, it can make code less readable by eliding useful information. There is no +blanket rule for when var should be used or shouldn't.

        +

        It may make sense to use var when the type is inherently clear upon reading the statement +(ie: assignment to either a literal value or a constructor call). Those use cases +can be enabled through properties.

        +

        Notice that lambda parameters are allowed, as they are already inferred by default (the var keyword +is completely optional).

        +

        See also Local Variable Type Inference Style Guidelines.

        +

        Full documentation

        ]]>
        + pmd + codestyle + + allowLiterals + + false + BOOLEAN + + + allowCtors + + false + BOOLEAN + + + allowCasts + + false + BOOLEAN + + + allowLoopVariable + + false + BOOLEAN + +
        + + UseIOStreamsWithApacheCommonsFileItem + Use IOStreams with apache commons FileItem + category/java/performance.xml/UseIOStreamsWithApacheCommonsFileItem + MAJOR + Title of issues: Avoid memory intensive FileItem.get() or FileItem.getString() +

        Problem: Use of FileItem.get() +and FileItem.getString() +could exhaust memory since they load the entire file into memory.

        +

        Solution: Use FileItem.getInputStream() +and buffering.

        +

        Example

        +

         import org.apache.commons.fileupload.FileItem;
        + 
        + public class FileStuff {
        +    private String bad(FileItem fileItem) {
        +         return fileItem.getString();
        +    }
        + 
        +    private InputStream good(FileItem fileItem) {
        +         return fileItem.getInputStream();
        +    }
        + }

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + UseIndexOfChar + Use index of char + category/java/performance.xml/UseIndexOfChar + MAJOR + Title of issues: String.indexOf(char) is faster than String.indexOf(String). +

        Use String.indexOf(char) when checking for the index of a single character; it executes faster.

        +

        Example

        +

         String s = "hello world";
        + // avoid this
        + if (s.indexOf("d") {}
        + // instead do this
        + if (s.indexOf('d') {}

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + UseLocaleWithCaseConversions + Use Locale with case conversions + category/java/errorprone.xml/UseLocaleWithCaseConversions + MAJOR + Title of issues: When doing a String.toLowerCase()/toUpperCase() call, use a Locale +

        When doing String::toLowerCase()/toUpperCase() conversions, use an explicit locale argument to specify the case +transformation rules.

        +

        Using String::toLowerCase() without arguments implicitly uses Locale::getDefault(). +The problem is that the default locale depends on the current JVM setup (and usually on the system in which +it is running). Using the system default may be exactly what you want (e.g. if you are manipulating strings +you got through standard input), but it may as well not be the case (e.g. if you are getting the string over +the network or a file, and the encoding is well-defined and independent of the environment). In the latter case, +using the default locale makes the case transformation brittle, as it may yield unexpected results on a machine +whose locale has other case translation rules. For example, in Turkish, the uppercase form of i is İ (U+0130, +not ASCII) and not I (U+0049) as in English.

        +

        The rule is intended to force developers to think about locales when dealing with strings. By taking a +conscious decision about the choice of locale at the time of writing, you reduce the risk of surprising +behaviour down the line, and communicate your intent to future readers.

        +

        Example

        +

         // violation - implicitly system-dependent conversion
        + if (x.toLowerCase().equals("list")) {}
        + 
        + // The above will not match "LIST" on a system with a Turkish locale.
        + // It could be replaced with
        + if (x.toLowerCase(Locale.US).equals("list")) { }
        + // or simply
        + if (x.equalsIgnoreCase("list")) { }
        + 
        + // ok - system independent conversion
        + String z = a.toLowerCase(Locale.ROOT);
        + 
        + // ok - explicit system-dependent conversion
        + String z2 = a.toLowerCase(Locale.getDefault());

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + UseNotifyAllInsteadOfNotify + Use notifyAll instead of notify + category/java/multithreading.xml/UseNotifyAllInsteadOfNotify + MAJOR + Title of issues: Call Thread.notifyAll() rather than Thread.notify() +

        Thread.notify() awakens a thread monitoring the object. If more than one thread is monitoring, then only +one is chosen. The thread chosen is arbitrary; thus it's usually safer to call notifyAll() instead.

        +

        Example

        +

         void bar() {
        +     x.notify();
        +     // If many threads are monitoring x, only one (and you won't know which) will be notified.
        +     // use instead:
        +     x.notifyAll();
        +   }

        +

        Alternative rule: java:S2446

        +

        Full documentation

        ]]>
        + pmd + multithreading + has-sonar-alternative +
        + + UseObjectForClearerAPI + Use object for clearer API + category/java/design.xml/UseObjectForClearerAPI + MAJOR + Title of issues: Rather than using a lot of String arguments, consider using a container object for those values. +

        When you write a public method, you should be thinking in terms of an API. If your method is public, it means other class +will use it, therefore, you want (or need) to offer a comprehensive and evolutive API. If you pass a lot of information +as a simple series of Strings, you may think of using an Object to represent all those information. You'll get a simpler +API (such as doWork(Workload workload), rather than a tedious series of Strings) and more importantly, if you need at some +point to pass extra data, you'll be able to do so by simply modifying or extending Workload without any modification to +your API.

        +

        Example

        +

         public class MyClass {
        +     public void connect(String username,
        +         String pssd,
        +         String databaseName,
        +         String databaseAddress)
        +         // Instead of those parameters object
        +         // would ensure a cleaner API and permit
        +         // to add extra data transparently (no code change):
        +         // void connect(UserData data);
        +     {
        + 
        +     }
        + }

        +

        Alternative rule: java:S107

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + UseProperClassLoader + Use proper ClassLoader + category/java/errorprone.xml/UseProperClassLoader + MAJOR + Title of issues: In J2EE, getClassLoader() might not work as expected. Use Thread.currentThread().getContextClassLoader() instead. +

        In J2EE, the getClassLoader() method might not work as expected. Use +Thread.currentThread().getContextClassLoader() instead.

        +

        Example

        +

         public class Foo {
        +     ClassLoader cl = Bar.class.getClassLoader();
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        + + UseShortArrayInitializer + Use short Array initializer + category/java/codestyle.xml/UseShortArrayInitializer + MINOR + Title of issues: Array initialization can be written shorter +

        When declaring and initializing array fields or variables, it is not necessary to explicitly create a new array +using new. Instead one can simply define the initial content of the array as a expression in curly braces.

        +

        E.g. int[] x = new int[] { 1, 2, 3 }; can be written as int[] x = { 1, 2, 3 };.

        +

        Example

        +

         Foo[] x = new Foo[] { ... }; // Overly verbose
        + Foo[] x = { ... }; //Equivalent to above line

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + UseStandardCharsets + Use standard Charsets + category/java/bestpractices.xml/UseStandardCharsets + MAJOR + Title of issues: Please use StandardCharsets constants +

        Starting with Java 7, StandardCharsets provides constants for common Charset objects, such as UTF-8. +Using the constants is less error prone, and can provide a small performance advantage compared to Charset.forName(...) +since no scan across the internal Charset caches is needed.

        +

        Example

        +

         public class UseStandardCharsets {
        +     public void run() {
        + 
        +         // looking up the charset dynamically
        +         try (OutputStreamWriter osw = new OutputStreamWriter(out, Charset.forName("UTF-8"))) {
        +             osw.write("test");
        +         }
        + 
        +         // best to use StandardCharsets
        +         try (OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
        +             osw.write("test");
        +         }
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + UseStringBufferForStringAppends + Use StringBuffer for string appends + category/java/performance.xml/UseStringBufferForStringAppends + MAJOR + Title of issues: Prefer StringBuilder (non-synchronized) or StringBuffer (synchronized) over += for concatenating strings +

        The use of the '+=' operator for appending strings causes the JVM to create and use an internal StringBuffer. +If a non-trivial number of these concatenations are being used then the explicit use of a StringBuilder or +threadsafe StringBuffer is recommended to avoid this.

        +

        Example

        +

         public class Foo {
        +     String inefficientConcatenation() {
        +         String result = "";
        +         for (int i = 0; i < 10; i++) {
        +             // warning: this concatenation will create one new StringBuilder per iteration
        +             result += getStringFromSomeWhere(i);
        +         }
        +         return result;
        +     }
        + 
        +     String efficientConcatenation() {
        +         // better would be to use one StringBuilder for the entire loop
        +         StringBuilder result = new StringBuilder();
        +         for (int i = 0; i < 10; i++) {
        +             result.append(getStringFromSomeWhere(i));
        +         }
        +         return result.toString();
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + UseStringBufferLength + Use StringBuffer length + category/java/performance.xml/UseStringBufferLength + MAJOR + Title of issues: This is an inefficient use of CharSequence.toString; call CharSequence.length instead. +

        Use StringBuffer.length() to determine StringBuffer length rather than using StringBuffer.toString().equals("") +or StringBuffer.toString().length() == ...

        +

        Example

        +

         StringBuffer sb = new StringBuffer();
        + 
        + if (sb.toString().equals("")) {}        // inefficient
        + 
        + if (sb.length() == 0) {}                // preferred

        +

        Full documentation

        ]]>
        + pmd + performance +
        + + UseTryWithResources + Use try with resources + category/java/bestpractices.xml/UseTryWithResources + MAJOR + Title of issues: Consider using a try-with-resources statement instead of explicitly closing the resource +

        Java 7 introduced the try-with-resources statement. This statement ensures that each resource is closed at the end +of the statement. It avoids the need of explicitly closing the resources in a finally block. Additionally exceptions +are better handled: If an exception occurred both in the try block and finally block, then the exception from +the try block was suppressed. With the try-with-resources statement, the exception thrown from the try-block is +preserved.

        +

        Example

        +

         public class TryWithResources {
        +     public void run() {
        +         InputStream in = null;
        +         try {
        +             in = openInputStream();
        +             int i = in.read();
        +         } catch (IOException e) {
        +             e.printStackTrace();
        +         } finally {
        +             try {
        +                 if (in != null) in.close();
        +             } catch (IOException ignored) {
        +                 // ignored
        +             }
        +         }
        + 
        +         // better use try-with-resources
        +         try (InputStream in2 = openInputStream()) {
        +             int i = in2.read();
        +         }
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices + + closeMethods + + close,closeQuietly + STRING + +
        + + UseUnderscoresInNumericLiterals + Use underscores in numeric literals + category/java/codestyle.xml/UseUnderscoresInNumericLiterals + MINOR + Title of issues: Number {0} should separate every third digit with an underscore +

        Since Java 1.7, numeric literals can use underscores to separate digits. This rule enforces that + numeric literals above a certain length use these underscores to increase readability.

        +

        The rule only supports decimal (base 10) literals for now. The acceptable length under which literals + are not required to have underscores is configurable via a property. Even under that length, underscores + that are misplaced (not making groups of 3 digits) are reported.

        +

        Example

        +

         public class Foo {
        +     private int num = 1000000; // should be 1_000_000
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + acceptableDecimalLength + + 4 + INTEGER + + + violationSuppressRegex + + + STRING + +
        + + UseUtilityClass + Use utility class + category/java/design.xml/UseUtilityClass + MAJOR + Title of issues: All methods are static. Consider adding a private no-args constructor to prevent instantiation. +

        For classes that only have static methods, consider making them utility classes. +Note that this doesn't apply to abstract classes, since their subclasses may +well include non-static methods. Also, if you want this class to be a utility class, +remember to add a private constructor to prevent instantiation. +(Note, that this use was known before PMD 5.1.0 as UseSingleton).

        +

        Example

        +

         public class MaybeAUtility {
        +   public static void foo() {}
        +   public static void bar() {}
        + }

        +

        Alternative rule: java:S1118

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative +
        + + UseVarargs + Use varargs + category/java/bestpractices.xml/UseVarargs + MINOR + Title of issues: Consider using varargs for methods or constructors which take an array the last parameter. +

        Java 5 introduced the varargs parameter declaration for methods and constructors. This syntactic +sugar provides flexibility for users of these methods and constructors, allowing them to avoid +having to deal with the creation of an array.

        +

        Byte arrays in any method and String arrays in public static void main(String[]) methods are ignored.

        +

        Example

        +

         public class Foo {
        +     public void foo(String s, Object[] args) {
        +         // Do something here...
        +     }
        + 
        +     public void bar(String s, Object... args) {
        +         // Ahh, varargs tastes much better...
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + UselessOperationOnImmutable + Useless operation on immutable + category/java/errorprone.xml/UselessOperationOnImmutable + MAJOR + Title of issues: The result of an operation on an immutable object is ignored +

        An operation on an immutable object will not change the object itself since the result of the operation is a new object. +Therefore, ignoring the result of such an operation is likely a mistake. The operation can probably be removed.

        +

        This rule recognizes the types String, BigDecimal, BigInteger or any type from java.time.* as immutable.

        +

        Deprecated: This rule is deprecated since PMD 7.17.0 and will be removed with PMD 8.0.0. +This rule has been replaced by {% rule UselessPureMethodCall %}.

        +

        Example

        +

         import java.math.*;
        + 
        + class Test {
        +     void method1() {
        +         BigDecimal bd=new BigDecimal(10);
        +         bd.add(new BigDecimal(5));      // this will trigger the rule
        +     }
        +     void method2() {
        +         BigDecimal bd=new BigDecimal(10);
        +         bd = bd.add(new BigDecimal(5)); // this won't trigger the rule
        +     }
        + }

        +

        Full documentation

        ]]>
        + DEPRECATED + pmd + errorprone +
        + + UselessOverridingMethod + Useless overriding method + category/java/design.xml/UselessOverridingMethod + MAJOR + Title of issues: Overriding method merely calls super +

        The overriding method merely calls the same method defined in a superclass.

        +

        Example

        +

         public void foo(String bar) {
        +     super.foo(bar);      // why bother overriding?
        + }
        + 
        + public String foo() {
        +     return super.foo();  // why bother overriding?
        + }
        + 
        + @Id
        + public Long getId() {
        +     return super.getId();  // OK if 'ignoreAnnotations' is false, which is the default behavior
        + }

        +

        Alternative rule: java:S1185

        +

        Full documentation

        ]]>
        + pmd + design + has-sonar-alternative + + ignoreAnnotations + + false + BOOLEAN + +
        + + UselessParentheses + Useless parentheses + category/java/codestyle.xml/UselessParentheses + MINOR + Title of issues: Useless parentheses. +

        Parenthesized expressions are used to override the default operator precedence + rules. Parentheses whose removal would not change the relative nesting of operators + are unnecessary, because they don't change the semantics of the enclosing expression.

        +

        Some parentheses that strictly speaking are unnecessary, may still be considered useful for readability. This rule allows to ignore violations on two kinds of unnecessary parentheses:

        +
        • "Clarifying" parentheses, which separate operators of difference precedence. While unnecessary, they make precedence rules explicit, which may be useful for rarely used
        +
        • "Balancing" parentheses, which are unnecessary but visually balance out another pair of parentheses around an equality operator. For example, those two expressions are equivalent:
           (a == null) != (b == null)
          +                 a == null != (b == null)
          The parentheses on the right are required, and the parentheses on the left are just more visually pleasing. Unset the property ignoreBalancing to report them.
        +

        Example

        +

         public class Foo {
        +     {
        +         int n = 0;
        +         n = (n);         // here
        +         n = (n * 2) * 3; // and here
        +         n = n * (2 * 3); // and here
        +     }
        + }

        +

        Alternative rule: java:S1110

        +

        Full documentation

        ]]>
        + pmd + codestyle + has-sonar-alternative + + ignoreClarifying + + true + BOOLEAN + + + ignoreBalancing + + true + BOOLEAN + +
        + + UselessPureMethodCall + Useless pure method call + category/java/errorprone.xml/UselessPureMethodCall + MAJOR + Title of issues: Do not call pure method {0} if the result is not used. +

        This rule detects method calls of pure methods whose result is unused. A pure method is a method without +side effects. Therefore, ignoring the result of such a method call is likely a mistake.

        +

        Either the method call can be removed or the result should be used.

        +

        Example

        +

         public class Something {
        +     public void foo() {
        +         List.of("foo").size(); // result unused
        +         Stream.of("bar").map(item -> System.out.format("%s", item)); // result unused
        +         Stream.of("bar").forEach(item -> System.out.format("%s", item)); // better
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone + + violationSuppressRegex + + + STRING + +
        + + UselessQualifiedThis + Useless qualified this + category/java/codestyle.xml/UselessQualifiedThis + MINOR + Title of issues: Useless qualified this usage in the same class. +

        Reports qualified this usages in the same class.

        +

        Example

        +

         public class Foo {
        +     final Foo otherFoo = Foo.this;  // use "this" directly
        + 
        +     public void doSomething() {
        +          final Foo anotherFoo = Foo.this;  // use "this" directly
        +     }
        + 
        +     private ActionListener returnListener() {
        +         return new ActionListener() {
        +             @Override
        +             public void actionPerformed(ActionEvent e) {
        +                 doSomethingWithQualifiedThis(Foo.this);  // This is fine
        +             }
        +         };
        +     }
        + 
        +     private class Foo3 {
        +         final Foo myFoo = Foo.this;  // This is fine
        +     }
        + 
        +     private class Foo2 {
        +         final Foo2 myFoo2 = Foo2.this;  // Use "this" directly
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + codestyle +
        + + UselessStringValueOf + Useless String.valueOf + category/java/performance.xml/UselessStringValueOf + MAJOR + Title of issues: No need to call String.valueOf to append to a string. +

        No need to call String.valueOf to append to a string; just use the valueOf() argument directly.

        +

        Example

        +

         public String convert(int i) {
        +     String s;
        +     s = "a" + String.valueOf(i);    // not required
        +     s = "a" + i;                    // preferred approach
        +     return s;
        + }

        +

        Alternative rule: java:S1153

        +

        Full documentation

        ]]>
        + pmd + performance + has-sonar-alternative +
        + + VariableCanBeInlined + Variable can be inlined + category/java/codestyle.xml/VariableCanBeInlined + MINOR + Title of issues: Consider simply using the value vs. storing it in local variable '{0}'. +

        Local variables should not be declared and then immediately returned or thrown. Such + variable declarations add unnecessary complexity and make the code harder to read. + It is often simpler and cleaner to return or throw the value directly.

        +

        This rule implements SonarSource rule S1488.

        +

        Example

        +

         class Foo {
        +                     Object foo() {
        +                         var foo = "foo";
        +                         return foo;  // instead, just 'return "foo";'
        +                     }
        + 
        +                     Object bar() {
        +                         var ex = getIllegalArgumentException();
        +                         throw ex; // instead, just 'throw getIllegalArgumentException();'
        +                     }
        + 
        +                     Object baz() {
        +                         var baz = switch (foo()) {
        +                             case "foo" -> {
        +                                 var foo = foo();
        +                                 yield foo;  // Can be simplified to 'yield foo();'
        +                             }
        +                             case "bar" -> {
        +                                 var bar = bar();
        +                                 yield bar;  // Can be simplified to 'yield bar();'
        +                             }
        +                             default -> bar("baz");
        +                         };
        +                         return baz; // instead, just 'return switch (foo()) {...'
        +                     }
        +                 }

        +

        Full documentation

        ]]>
        + pmd + codestyle + + statementOrderMatters + + true + BOOLEAN + + + violationSuppressRegex + + + STRING + +
        + + WhileLoopWithLiteralBoolean + While loop with literal boolean + category/java/bestpractices.xml/WhileLoopWithLiteralBoolean + MAJOR + Title of issues: The loop can be simplified. +

        do {} while (true); requires reading the end of the statement before it is +apparent that it loops forever, whereas while (true) {} is easier to understand.

        +

        do {} while (false); is redundant, and if an inner variable scope is required, +a block {} is sufficient.

        +

        while (false) {} will never execute the block and can be removed in its entirety.

        +

        Example

        +

         public class Example {
        +   {
        +     while (true) { } // allowed
        +     while (false) { } // disallowed
        +     do { } while (true); // disallowed
        +     do { } while (false); // disallowed
        +     do { } while (false | false); // disallowed
        +     do { } while (false || false); // disallowed
        +   }
        + }

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + XPathRule + PMD XPath Template Rule + MAJOR + net.sourceforge.pmd.lang.rule.xpath.XPathRule + MULTIPLE + + + The PMD 7 compatible XPath expression for Java. + + + + The message for issues created by this rule. + + PMD provides a powerful method for creating custom rules by writing an XPath query. When the XPath query finds a match, a violation is created.

        +

        Let's take a simple example: assume we have a Factory class that must be always declared final. +We'd like to report a violation each time a declaration of Factory is not declared final. Consider the following class:

        +
        
        +import io.factories.Factory;
        +
        +public class Foo {
        +  Factory f1;
        +
        +  void myMethod() {
        +    Factory f2;
        +    int a;
        +  }
        +}
        +
        +

        The following expression does the magic we need:

        +
        
        +//(FieldDeclaration|LocalVariableDeclaration)[
        +      not (pmd-java:modifiers() = 'final')
        +   ]/ClassType[pmd-java:typeIs('io.factories.Factory')]
        +
        +

        See the XPath rule tutorial for more information.

        +

        Tip: use the PMD Designer application to create the XPath expressions.

        +]]>
        + pmd + xpath +
        +
        \ No newline at end of file diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-kotlin.xml b/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-kotlin.xml new file mode 100644 index 00000000..4707d073 --- /dev/null +++ b/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-kotlin.xml @@ -0,0 +1,51 @@ + + + + + FunctionNameTooShort + Function name too short + category/kotlin/bestpractices.xml/FunctionNameTooShort + MAJOR + Title of issues: Function names should have non-cryptic and clear names. +

        Function names should be easy to understand and describe the intention. Makes developers happy.

        +

        Example

        +

         fun cl() {} // violation, no unavailable attribute added to the function declaration
        + 
        + fun calculateLayout() // no violation

        +

        Full documentation

        ]]>
        + pmd + bestpractices +
        + + OverrideBothEqualsAndHashcode + Override both equals and hashcode + category/kotlin/errorprone.xml/OverrideBothEqualsAndHashcode + MAJOR + Title of issues: Ensure you override both equals() and hashCode() +

        Override both public boolean Object.equals(Object other), and public int Object.hashCode(), or override neither. Even if you are inheriting a hashCode() from a parent class, consider implementing hashCode and explicitly delegating to your superclass.

        +

        Example

        +

         class Bar {        // poor, missing a hashCode() method
        +     override fun equals(o: Any?): Boolean {
        +       // do some comparison
        +     }
        + }
        + 
        + class Baz {        // poor, missing an equals() method
        +     override fun hashCode(): Int {
        +       // return some hash value
        +     }
        + }
        + 
        + class Foo {        // perfect, both methods provided
        +     override fun equals(other: Any?): Boolean {
        +       // do some comparison
        +     }
        +     override fun hashCode(): Int {
        +       // return some hash value
        +     }
        + }

        +

        Full documentation

        ]]>
        + pmd + errorprone +
        +
        \ No newline at end of file diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-unit-tests.xml b/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-unit-tests.xml deleted file mode 100644 index 620eba3c..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules-unit-tests.xml +++ /dev/null @@ -1,75 +0,0 @@ - - - MAJOR - - - - MAJOR - - - - MINOR - - DEPRECATED - - - MAJOR - - - - MAJOR - - - - MINOR - - - - MINOR - - - - MINOR - - - - MINOR - - - - MINOR - - - - MINOR - - - - MAJOR - - - 1 - - - - - MAJOR - - - - MAJOR - - - - MAJOR - - - - MAJOR - - - - MAJOR - - - diff --git a/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules.xml b/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules.xml deleted file mode 100644 index 4c0451c3..00000000 --- a/sonar-pmd-plugin/src/main/resources/org/sonar/plugins/pmd/rules.xml +++ /dev/null @@ -1,1783 +0,0 @@ - - - - MAJOR - category/java/multithreading.xml/DontCallThreadRun - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/GuardLogStatement - - - - MAJOR - naming - category/java/codestyle.xml/GenericsNaming - DEPRECATED - - - - MAJOR - error-handling - category/java/design.xml/AvoidCatchingGenericException - DEPRECATED - - - - MAJOR - error-handling - category/java/errorprone.xml/AvoidLosingExceptionInformation - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/AvoidLiteralsInIfCondition - DEPRECATED - - - - MAJOR - multithreading - category/java/multithreading.xml/UseConcurrentHashMap - - - - MAJOR - category/java/errorprone.xml/DoNotHardCodeSDCard - - - - MAJOR - error-handling - category/java/design.xml/AvoidThrowingNewInstanceOfSameException - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/CallSuperFirst - - - - MAJOR - category/java/errorprone.xml/CallSuperLast - - - - MAJOR - category/java/errorprone.xml/EmptyInitializer - DEPRECATED - - - - MAJOR - size - category/java/design.xml/CyclomaticComplexity - - 80 - - - 10 - - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/AvoidStringBufferField - DEPRECATED - - - - MAJOR - error-handling - category/java/errorprone.xml/DoNotThrowExceptionInFinally - DEPRECATED - - - - MAJOR - size - category/java/design.xml/TooManyMethods - - 10 - - DEPRECATED - - - - MINOR - category/java/errorprone.xml/ReturnEmptyArrayRatherThanNull - DEPRECATED - - - - MINOR - category/java/performance.xml/TooFewBranchesForASwitchStatement - - 3 - - DEPRECATED - - - - MAJOR - category/java/design.xml/AbstractClassWithoutAnyMethod - DEPRECATED - - - - CRITICAL - category/java/errorprone.xml/DoNotCallGarbageCollectionExplicitly - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/AvoidMultipleUnaryOperators - DEPRECATED - - - - MAJOR - multithreading - category/java/multithreading.xml/DoubleCheckedLocking - - - - MAJOR - size - category/java/design.xml/NPathComplexity - - 200 - - - - - MINOR - category/java/design.xml/SimplifyBooleanReturns - DEPRECATED - - - - MAJOR - category/java/design.xml/SimplifyBooleanExpressions - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/SwitchStmtsShouldHaveDefault - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/DefaultLabelNotLastInSwitchStmt - DEPRECATED - - - - MAJOR - category/java/design.xml/ClassWithOnlyPrivateConstructorsShouldBeFinal - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/AvoidFinalLocalVariable - - - - MINOR - category/java/codestyle.xml/UselessParentheses - DEPRECATED - - - - BLOCKER - bug - category/java/errorprone.xml/OverrideBothEqualsAndHashcode - DEPRECATED - - - - INFO - category/java/bestpractices.xml/UnusedImports - DEPRECATED - - - - MINOR - category/java/codestyle.xml/LocalVariableCouldBeFinal - - - - MAJOR - naming - category/java/codestyle.xml/AbstractNaming - - true - - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/NoPackage - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/PackageCase - DEPRECATED - - - - MAJOR - category/java/performance.xml/ByteInstantiation - - - - MAJOR - category/java/performance.xml/ShortInstantiation - - - - MAJOR - category/java/performance.xml/LongInstantiation - - - - CRITICAL - category/java/errorprone.xml/ProperCloneImplementation - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/EmptyFinalizer - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/FinalizeOnlyCallsSuperFinalize - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/FinalizeOverloaded - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/FinalizeDoesNotCallSuperFinalize - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/FinalizeShouldBeProtected - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/AvoidCallingFinalize - DEPRECATED - - - - MAJOR - unused-code - category/java/bestpractices.xml/UnusedPrivateField - DEPRECATED - - - - MAJOR - unused-code - category/java/bestpractices.xml/UnusedLocalVariable - DEPRECATED - - - - MAJOR - unused-code - category/java/bestpractices.xml/UnusedPrivateMethod - DEPRECATED - - - - MAJOR - unused-code - category/java/bestpractices.xml/UnusedFormalParameter - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/UnnecessaryConstructor - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/NullAssignment - - - - MINOR - category/java/codestyle.xml/OnlyOneReturn - DEPRECATED - - - - INFO - category/java/codestyle.xml/UnnecessaryModifier - - - - MAJOR - category/java/errorprone.xml/AssignmentInOperand - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/AtLeastOneConstructor - DEPRECATED - - - - MINOR - category/java/errorprone.xml/DontImportSun - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/SuspiciousOctalEscape - - - - MINOR - category/java/codestyle.xml/CallSuperInConstructor - - - - MINOR - category/java/design.xml/SingularField - - - - MINOR - category/java/codestyle.xml/DefaultPackage - - - - MAJOR - category/java/errorprone.xml/DataflowAnomalyAnalysis - - 100 - - - 1000 - - - - - MAJOR - category/java/design.xml/CouplingBetweenObjects - - 20 - - DEPRECATED - - - - MAJOR - category/java/design.xml/ExcessiveImports - - 30 - - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/LooseCoupling - DEPRECATED - - - - MINOR - category/java/codestyle.xml/MethodArgumentCouldBeFinal - DEPRECATED - - - - MINOR - category/java/performance.xml/AvoidInstantiatingObjectsInLoops - - - - MAJOR - category/java/performance.xml/UseArrayListInsteadOfVector - DEPRECATED - - - - MINOR - category/java/performance.xml/SimplifyStartsWith - - - - MAJOR - category/java/performance.xml/UseStringBufferForStringAppends - - - - MAJOR - category/java/performance.xml/UseArraysAsList - - - - MAJOR - category/java/performance.xml/AvoidArrayLoops - - - - MAJOR - category/java/performance.xml/UnnecessaryWrapperObjectCreation - DEPRECATED - - - - CRITICAL - category/java/errorprone.xml/UseProperClassLoader - - - - CRITICAL - error-handling - category/java/errorprone.xml/EmptyCatchBlock - - false - - DEPRECATED - - - - CRITICAL - category/java/errorprone.xml/EmptyIfStmt - DEPRECATED - - - - CRITICAL - category/java/errorprone.xml/EmptyWhileStmt - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/EmptyTryBlock - DEPRECATED - - - - CRITICAL - error-handling - category/java/errorprone.xml/EmptyFinallyBlock - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/EmptySwitchStatements - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/JumbledIncrementer - DEPRECATED - - - - MINOR - category/java/codestyle.xml/ForLoopShouldBeWhileLoop - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/UnnecessaryConversionTemporary - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/ReturnFromFinallyBlock - DEPRECATED - - - - CRITICAL - category/java/errorprone.xml/EmptySynchronizedBlock - DEPRECATED - - - - MINOR - category/java/codestyle.xml/UnnecessaryReturn - - - - MAJOR - category/java/errorprone.xml/EmptyInitializer - DEPRECATED - - - - CRITICAL - category/java/errorprone.xml/UnconditionalIfStatement - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/EmptyStatementNotInLoop - DEPRECATED - - - - MAJOR - category/java/performance.xml/BooleanInstantiation - - - - INFO - category/java/codestyle.xml/UnnecessaryModifier - - - - MINOR - category/java/design.xml/CollapsibleIfStatements - DEPRECATED - - - - MAJOR - category/java/design.xml/UselessOverridingMethod - - false - - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/ClassCastExceptionWithToArray - - - - MAJOR - category/java/errorprone.xml/AvoidDecimalLiteralsInBigDecimalConstructor - DEPRECATED - - - - CRITICAL - category/java/errorprone.xml/UselessOperationOnImmutable - - - - CRITICAL - category/java/errorprone.xml/MisplacedNullCheck - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/UnusedNullCheckInEquals - - - - CRITICAL - multithreading - category/java/multithreading.xml/AvoidThreadGroup - - - - CRITICAL - category/java/errorprone.xml/BrokenNullCheck - DEPRECATED - - - - MAJOR - category/java/performance.xml/BigIntegerInstantiation - - - - MAJOR - category/java/errorprone.xml/AvoidUsingOctalValues - DEPRECATED - - - - MAJOR - category/java/design.xml/UseUtilityClass - DEPRECATED - - - - MAJOR - category/java/design.xml/AvoidDeeplyNestedIfStmts - - 3 - - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/AvoidReassigningParameters - DEPRECATED - - - - MAJOR - category/java/design.xml/SwitchDensity - - 10 - - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/ConstructorCallsOverridableMethod - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/AccessorClassGeneration - - - - MINOR - category/java/design.xml/FinalFieldCouldBeStatic - DEPRECATED - - - - CRITICAL - bug - category/java/errorprone.xml/CloseResource - - Connection,Statement,ResultSet - - - close - - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/NonStaticInitializer - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/NonCaseLabelInSwitchStatement - DEPRECATED - - - - MAJOR - category/java/performance.xml/OptimizableToArrayCall - - - - MAJOR - category/java/errorprone.xml/BadComparison - - - - CRITICAL - bug - category/java/errorprone.xml/EqualsNull - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/ConfusingTernary - - - - MAJOR - category/java/errorprone.xml/InstantiationToGetClass - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/IdempotentOperations - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/SimpleDateFormatNeedsLocale - - - - MAJOR - category/java/design.xml/ImmutableField - - - - MAJOR - category/java/errorprone.xml/UseLocaleWithCaseConversions - - - - MAJOR - category/java/codestyle.xml/AvoidProtectedFieldInFinalClass - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/AssignmentToNonFinalStatic - - - - MAJOR - category/java/errorprone.xml/MissingStaticMethodInNonInstantiatableClass - - - - MAJOR - multithreading - category/java/multithreading.xml/AvoidSynchronizedAtMethodLevel - - - - CRITICAL - category/java/errorprone.xml/MissingBreakInSwitch - DEPRECATED - - - - MAJOR - category/java/multithreading.xml/UseNotifyAllInsteadOfNotify - DEPRECATED - - - - MINOR - category/java/errorprone.xml/AvoidInstanceofChecksInCatchClause - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/AbstractClassWithoutAbstractMethod - DEPRECATED - - - - MAJOR - category/java/design.xml/SimplifyConditional - - - - MAJOR - category/java/errorprone.xml/CompareObjectsWithEquals - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/PositionLiteralsFirstInComparisons - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/UnnecessaryLocalBeforeReturn - DEPRECATED - - - - MAJOR - multithreading - category/java/multithreading.xml/NonThreadSafeSingleton - - true - - - false - - DEPRECATED - - - - MAJOR - comment - category/java/documentation.xml/UncommentedEmptyMethodBody - DEPRECATED - - - - MAJOR - comment - category/java/documentation.xml/UncommentedEmptyConstructor - - false - - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/ConstantsInInterface - DEPRECATED - - - - MAJOR - multithreading - category/java/multithreading.xml/UnsynchronizedStaticDateFormatter - DEPRECATED - - - - MAJOR - error-handling - category/java/bestpractices.xml/PreserveStackTrace - DEPRECATED - - - - MINOR - category/java/bestpractices.xml/UseCollectionIsEmpty - DEPRECATED - - - - CRITICAL - security - category/java/bestpractices.xml/MethodReturnsInternalArray - DEPRECATED - - - - CRITICAL - security - category/java/bestpractices.xml/ArrayIsStoredDirectly - DEPRECATED - - - - CRITICAL - error-handling - category/java/errorprone.xml/AvoidCatchingThrowable - DEPRECATED - - - - MAJOR - error-handling - category/java/design.xml/SignatureDeclareThrowsException - DEPRECATED - - - - MAJOR - category/java/design.xml/ExceptionAsFlowControl - DEPRECATED - - - - MAJOR - error-handling - category/java/errorprone.xml/AvoidCatchingNPE - DEPRECATED - - - - MAJOR - error-handling - category/java/design.xml/AvoidThrowingRawExceptionTypes - DEPRECATED - - - - MAJOR - error-handling - category/java/design.xml/AvoidThrowingNullPointerException - DEPRECATED - - - - MAJOR - error-handling - category/java/design.xml/AvoidRethrowingException - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/BeanMembersShouldSerialize - - - - - - - MAJOR - category/java/errorprone.xml/MissingSerialVersionUID - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/CloneMethodMustImplementCloneable - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/AvoidDuplicateLiterals - - 4 - - - false - - - - - - , - - - - - - 3 - - DEPRECATED - - - - MAJOR - category/java/performance.xml/StringInstantiation - - - - MAJOR - category/java/performance.xml/StringToString - DEPRECATED - - - - MAJOR - category/java/performance.xml/InefficientStringBuffering - - - - MINOR - category/java/errorprone.xml/UnnecessaryCaseChange - DEPRECATED - - - - MINOR - category/java/performance.xml/UseStringBufferLength - - - - MINOR - category/java/performance.xml/AppendCharacterWithChar - - - - MINOR - category/java/performance.xml/ConsecutiveLiteralAppends - - 1 - - - - - MAJOR - category/java/performance.xml/UseIndexOfChar - - - - MAJOR - category/java/performance.xml/InefficientEmptyStringCheck - - - - MAJOR - category/java/performance.xml/InsufficientStringBufferDeclaration - - - - MINOR - category/java/performance.xml/UselessStringValueOf - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/StringBufferInstantiationWithChar - DEPRECATED - - - - MAJOR - size - category/java/design.xml/ExcessiveMethodLength - - 100 - - DEPRECATED - - - - MAJOR - size - category/java/design.xml/ExcessiveParameterList - - 10 - - DEPRECATED - - - - MAJOR - size - category/java/design.xml/ExcessiveClassLength - - 1000 - - DEPRECATED - - - - MAJOR - size - category/java/design.xml/ExcessivePublicCount - - 45 - - DEPRECATED - - - - MAJOR - size - category/java/design.xml/TooManyFields - - 15 - - - - - MAJOR - size - category/java/design.xml/NcssMethodCount - - 100 - - DEPRECATED - - - - MAJOR - size - category/java/design.xml/NcssTypeCount - - 1500 - - DEPRECATED - - - - MAJOR - size - category/java/design.xml/NcssConstructorCount - - 100 - - DEPRECATED - - - - MINOR - category/java/codestyle.xml/DuplicateImports - DEPRECATED - - - - MINOR - category/java/codestyle.xml/DontImportJavaLang - DEPRECATED - - - - MINOR - category/java/errorprone.xml/ImportFromSamePackage - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/CloneThrowsCloneNotSupportedException - DEPRECATED - - - - MAJOR - error-handling - category/java/errorprone.xml/UseCorrectExceptionLogging - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/ProperLogger - - LOG - - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/ShortVariable - - 3 - - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/LongVariable - - 17 - - DEPRECATED - - - - MAJOR - convention - category/java/codestyle.xml/ShortMethodName - - 3 - - DEPRECATED - - - - MAJOR - naming - category/java/codestyle.xml/VariableNamingConventions - - - - - - - - - - - - - DEPRECATED - - - - MAJOR - naming - category/java/codestyle.xml/MethodNamingConventions - DEPRECATED - - - - MAJOR - naming - category/java/codestyle.xml/ClassNamingConventions - DEPRECATED - - - - MINOR - category/java/codestyle.xml/AvoidDollarSigns - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/MethodWithSameNameAsEnclosingClass - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/SuspiciousHashcodeMethodName - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/SuspiciousConstantFieldName - DEPRECATED - - - - CRITICAL - category/java/errorprone.xml/SuspiciousEqualsMethodName - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/AvoidFieldNameMatchingTypeName - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/AvoidFieldNameMatchingMethodName - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/MIsLeadingVariableName - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/ReplaceVectorWithList - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/ReplaceHashtableWithMap - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/ReplaceEnumerationWithIterator - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/AvoidEnumAsIdentifier - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/AvoidAssertAsIdentifier - DEPRECATED - - - - MAJOR - category/java/performance.xml/IntegerInstantiation - - - - MAJOR - category/java/errorprone.xml/MoreThanOneLogger - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/LoggerIsNotStaticFinal - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/SystemPrintln - DEPRECATED - - - - MAJOR - error-handling - category/java/bestpractices.xml/AvoidPrintStackTrace - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/IfStmtsMustUseBraces - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/WhileLoopsMustUseBraces - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/IfElseStmtsMustUseBraces - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/ForLoopsMustUseBraces - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/AvoidUsingHardCodedIP - - IPv4|IPv6|IPv4 mapped IPv6 - - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/CheckResultSet - - - - MAJOR - category/java/performance.xml/AvoidUsingShortType - - - - MAJOR - category/java/multithreading.xml/AvoidUsingVolatile - - - - MAJOR - category/java/codestyle.xml/AvoidUsingNativeCode - - - - MAJOR - category/java/errorprone.xml/AvoidAccessibilityAlteration - - - - MAJOR - category/java/codestyle.xml/EmptyMethodInAbstractClassShouldBeAbstract - - - - MAJOR - category/java/codestyle.xml/TooManyStaticImports - - 4 - - - - - MAJOR - category/java/errorprone.xml/DoNotCallSystemExit - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/StaticEJBFieldShouldBeFinal - - - - MAJOR - multithreading - category/java/multithreading.xml/DoNotUseThreads - - - - MAJOR - category/java/codestyle.xml/MDBAndSessionBeanNamingConvention - - - - MAJOR - category/java/codestyle.xml/RemoteSessionInterfaceNamingConvention - - - - MAJOR - category/java/codestyle.xml/LocalInterfaceSessionNamingConvention - - - - MAJOR - category/java/codestyle.xml/LocalHomeNamingConvention - - - - MAJOR - category/java/codestyle.xml/RemoteInterfaceNamingConvention - - - - MAJOR - category/java/errorprone.xml/UseEqualsToCompareStrings - DEPRECATED - - - - MAJOR - category/java/design.xml/DoNotExtendJavaLangError - DEPRECATED - - - - MAJOR - category/java/performance.xml/AddEmptyString - - - - MAJOR - category/java/codestyle.xml/BooleanGetMethodName - - false - - - - - MAJOR - category/java/errorprone.xml/AvoidBranchingStatementAsLastInLoop - - - - MINOR - category/java/errorprone.xml/CheckSkipResult - DEPRECATED - - - - MAJOR - category/java/errorprone.xml/DontUseFloatTypeForLoopIndices - - - - MINOR - category/java/codestyle.xml/ExtendsObject - DEPRECATED - - - - MINOR - category/java/documentation.xml/CommentContent - - - - MINOR - category/java/documentation.xml/CommentRequired - - - - - - - MINOR - category/java/documentation.xml/CommentSize - - - - - - - - 6 - - - 80 - - - - - MAJOR - category/java/codestyle.xml/AvoidPrefixingMethodParameters - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/OneDeclarationPerLine - DEPRECATED - - - - MINOR - category/java/design.xml/UseObjectForClearerAPI - DEPRECATED - - - - MAJOR - category/java/design.xml/LawOfDemeter - - - - MAJOR - category/java/design.xml/LoosePackageCoupling - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/AvoidProtectedMethodInFinalClassNotExtending - DEPRECATED - - - - MINOR - category/java/codestyle.xml/FieldDeclarationsShouldBeAtStartOfClass - - true - - - true - - DEPRECATED - - - - MAJOR - category/java/design.xml/GodClass - - - - MINOR - category/java/design.xml/LogicInversion - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/PositionLiteralsFirstInCaseInsensitiveComparisons - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/UseVarargs - - - - MAJOR - category/java/errorprone.xml/EmptyStatementBlock - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/UnnecessaryFullyQualifiedName - - - - MAJOR - category/java/bestpractices.xml/GuardLogStatement - - - - MAJOR - category/java/bestpractices.xml/GuardLogStatement - - - - MINOR - category/java/codestyle.xml/ShortClassName - - 5 - - DEPRECATED - - - - MAJOR - category/java/codestyle.xml/PrematureDeclaration - DEPRECATED - - - - MAJOR - category/java/performance.xml/RedundantFieldInitializer - - - - MAJOR - category/java/performance.xml/ConsecutiveAppendsShouldReuse - - - - MAJOR - category/java/errorprone.xml/CloneMethodMustImplementCloneable - DEPRECATED - - - - MAJOR - category/java/bestpractices.xml/LooseCoupling - DEPRECATED - - - - MAJOR - category/java/design.xml/SignatureDeclareThrowsException - - false - - DEPRECATED - - - - INFO - category/java/bestpractices.xml/UnusedImports - DEPRECATED - - - - INFO - category/java/codestyle.xml/UselessParentheses - DEPRECATED - - - - MAJOR - size - category/java/design.xml/StdCyclomaticComplexity - - 10 - - - true - - - true - - DEPRECATED - - - - MAJOR - size - category/java/design.xml/ModifiedCyclomaticComplexity - - 10 - - - true - - - true - - DEPRECATED - - - - MAJOR - net.sourceforge.pmd.lang.rule.XPathRule - MULTIPLE - - - - - - - DEPRECATED - - - - MAJOR - category/java/design.xml/SimplifiedTernary - - - - MAJOR - category/java/errorprone.xml/CloneMethodMustBePublic - - - - MAJOR - category/java/errorprone.xml/CloneMethodReturnTypeMustMatchClassName - - - - MAJOR - category/java/codestyle.xml/CommentDefaultAccessModifier - - - - - - - - - - - - - MAJOR - category/java/errorprone.xml/SingletonClassReturningNewInstance - - - - - - - - - - CRITICAL - category/java/errorprone.xml/SingleMethodSingleton - - - - - - - - - - MAJOR - category/java/codestyle.xml/UselessQualifiedThis - - - diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/AbstractPmdExecutorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/AbstractPmdExecutorTest.java new file mode 100644 index 00000000..275ae91d --- /dev/null +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/AbstractPmdExecutorTest.java @@ -0,0 +1,116 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import net.sourceforge.pmd.lang.rule.RuleSetLoadException; +import net.sourceforge.pmd.reporting.Report; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.sonar.api.batch.fs.InputFile.Type; +import org.sonar.api.batch.fs.internal.DefaultFileSystem; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.fs.internal.TestInputFileBuilder; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.rule.RuleScope; + +import java.io.File; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Abstract base class for PMD executor tests with common test functionality. + */ +public abstract class AbstractPmdExecutorTest { + + protected final DefaultFileSystem fileSystem = new DefaultFileSystem(new File(".")); + protected final ActiveRules activeRules = mock(ActiveRules.class); + protected final PmdConfiguration pmdConfiguration = mock(PmdConfiguration.class); + protected final PmdTemplate pmdTemplate = mock(PmdTemplate.class); + protected final MapSettings settings = new MapSettings(); + + protected AbstractPmdExecutor pmdExecutor; + + protected static DefaultInputFile fileJava(String path, Type type) { + return TestInputFileBuilder.create("sonar-pmd-test", path) + .setType(type) + .setLanguage(PmdConstants.LANGUAGE_JAVA_KEY) + .build(); + } + + protected static DefaultInputFile fileKotlin(String path, Type type) { + return TestInputFileBuilder.create("", path) + .setType(type) + .setLanguage(PmdConstants.LANGUAGE_KOTLIN_KEY) + .build(); + } + + @BeforeEach + void setUpAbstractTest() { + fileSystem.setEncoding(StandardCharsets.UTF_8); + settings.setProperty(PmdConstants.JAVA_SOURCE_VERSION, "1.8"); + + // The concrete test class must initialize pmdExecutor in its own @BeforeEach method + } + + @Test + void whenNoFilesToAnalyzeThenExecutionSucceedsWithBlankReport() { + // when + final Report result = pmdExecutor.execute(); + + // then + assertThat(result).isNotNull(); + assertThat(result.getViolations()).isEmpty(); + assertThat(result.getProcessingErrors()).isEmpty(); + } + + @Test + void unknown_pmd_ruleset() { + when(pmdConfiguration.dumpXmlRuleSet(anyString(), anyString(), ArgumentMatchers.any(RuleScope.class))).thenReturn(new File("unknown")); + + DefaultInputFile srcFile = getAppropriateInputFileForTest(); + fileSystem.add(srcFile); + + final Throwable thrown = catchThrowable(() -> pmdExecutor.execute()); + + assertThat(thrown) + .isInstanceOf(IllegalStateException.class) + .hasCauseInstanceOf(RuleSetLoadException.class); + } + + /** + * Get an appropriate input file for the specific executor being tested + */ + protected abstract DefaultInputFile getAppropriateInputFileForTest(); + + protected void setupPmdRuleSet(String repositoryKey, String profileFileName) { + final Path sourcePath = Paths.get("src/test/resources/org/sonar/plugins/pmd/").resolve(profileFileName); + when(pmdConfiguration.dumpXmlRuleSet(eq(repositoryKey), anyString(), ArgumentMatchers.any(RuleScope.class))).thenReturn(sourcePath.toFile()); + } +} \ No newline at end of file diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConfigurationTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConfigurationTest.java index b5e7f964..03278198 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConfigurationTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConfigurationTest.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,29 +19,29 @@ */ package org.sonar.plugins.pmd; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.List; - -import net.sourceforge.pmd.Report; +import net.sourceforge.pmd.reporting.Report; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.rule.RuleScope; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.regex.Pattern; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; class PmdConfigurationTest { + private static final Pattern PMD_XML_PATTERN = Pattern.compile("^<\\?xml version=\"1\\.0\" encoding=\"UTF-8\"\\?>$"); private static final File WORK_DIR = new File("test-work-dir"); private final FileSystem fs = mock(FileSystem.class); @@ -76,9 +76,9 @@ void setUpPmdConfiguration() { void should_dump_xml_rule_set() throws IOException { when(fs.workDir()).thenReturn(WORK_DIR); - File rulesFile = configuration.dumpXmlRuleSet("pmd", ""); + File rulesFile = configuration.dumpXmlRuleSet("pmd", "", RuleScope.TEST); - assertThat(rulesFile).isEqualTo(new File(WORK_DIR, "pmd.xml")); + assertThat(rulesFile).isEqualTo(new File(WORK_DIR, "pmd-test.xml")); assertThat(Files.readAllLines(rulesFile.toPath(), StandardCharsets.UTF_8)).containsExactly(""); } @@ -86,7 +86,7 @@ void should_dump_xml_rule_set() throws IOException { void should_fail_to_dump_xml_rule_set() { when(fs.workDir()).thenReturn(new File("xxx")); - final Throwable thrown = catchThrowable(() -> configuration.dumpXmlRuleSet("pmd", "")); + final Throwable thrown = catchThrowable(() -> configuration.dumpXmlRuleSet("pmd", "", RuleScope.MAIN)); assertThat(thrown) .isInstanceOf(IllegalStateException.class) @@ -98,12 +98,13 @@ void should_dump_xml_report() throws IOException { when(fs.workDir()).thenReturn(WORK_DIR); settings.setProperty(PmdConfiguration.PROPERTY_GENERATE_XML, true); - Path reportFile = configuration.dumpXmlReport(new Report()); + Path reportFile = configuration.dumpXmlReport(Report.buildReport(v -> {})); assertThat(reportFile.toFile()).isEqualTo(new File(WORK_DIR, "pmd-result.xml")); - List writtenLines = Files.readAllLines(reportFile, StandardCharsets.UTF_8); - assertThat(writtenLines).hasSize(6); - assertThat(writtenLines.get(1)).contains(" configuration.dumpXmlReport(new Report())); + final Throwable thrown = catchThrowable(() -> configuration.dumpXmlReport(Report.buildReport(v -> {}))); assertThat(thrown) .isInstanceOf(IllegalStateException.class) @@ -121,7 +122,7 @@ void should_fail_to_dump_xml_report() { @Test void should_ignore_xml_report_when_property_is_not_set() { - Path reportFile = configuration.dumpXmlReport(new Report()); + Path reportFile = configuration.dumpXmlReport(Report.buildReport(v -> {})); assertThat(reportFile).isNull(); verifyNoMoreInteractions(fs); diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConstantsTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConstantsTest.java index 3fa51ac5..c80ab21b 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConstantsTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdConstantsTest.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -29,15 +29,14 @@ class PmdConstantsTest { void checkDefinedKeys() { assertThat(PmdConstants.PLUGIN_NAME).isEqualTo("PMD"); assertThat(PmdConstants.PLUGIN_KEY).isEqualTo("pmd"); - assertThat(PmdConstants.REPOSITORY_KEY).isEqualTo("pmd"); + assertThat(PmdConstants.MAIN_JAVA_REPOSITORY_KEY).isEqualTo("pmd"); + assertThat(PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY).isEqualTo("pmd-kotlin"); assertThat(PmdConstants.REPOSITORY_NAME).isEqualTo("PMD"); - assertThat(PmdConstants.TEST_REPOSITORY_KEY).isEqualTo("pmd-unit-tests"); - assertThat(PmdConstants.TEST_REPOSITORY_NAME).isEqualTo("PMD Unit Tests"); - assertThat(PmdConstants.XPATH_CLASS).isEqualTo("net.sourceforge.pmd.lang.rule.XPathRule"); + assertThat(PmdConstants.XPATH_CLASS).isEqualTo("net.sourceforge.pmd.lang.rule.xpath.XPathRule"); assertThat(PmdConstants.XPATH_EXPRESSION_PARAM).isEqualTo("xpath"); assertThat(PmdConstants.XPATH_MESSAGE_PARAM).isEqualTo("message"); assertThat(PmdConstants.JAVA_SOURCE_VERSION).isEqualTo("sonar.java.source"); - assertThat(PmdConstants.JAVA_SOURCE_VERSION_DEFAULT_VALUE).isEqualTo("1.6"); - assertThat(PmdConstants.LANGUAGE_KEY).isEqualTo("java"); + assertThat(PmdConstants.JAVA_SOURCE_VERSION_DEFAULT_VALUE).isEqualTo("25"); + assertThat(PmdConstants.LANGUAGE_JAVA_KEY).isEqualTo("java"); } } diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java deleted file mode 100644 index dc1c3c51..00000000 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.pmd; - -import java.io.File; -import java.net.URI; -import java.net.URL; -import java.net.URLClassLoader; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.nio.file.Paths; - -import com.google.common.collect.ImmutableList; -import net.sourceforge.pmd.Report; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleSetNotFoundException; -import net.sourceforge.pmd.RuleSets; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import org.mockito.Mockito; -import org.sonar.api.batch.fs.InputFile.Type; -import org.sonar.api.batch.fs.internal.DefaultFileSystem; -import org.sonar.api.batch.fs.internal.DefaultInputFile; -import org.sonar.api.batch.fs.internal.TestInputFileBuilder; -import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.config.internal.MapSettings; -import org.sonar.plugins.java.api.JavaResourceLocator; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; - -class PmdExecutorTest { - - private final DefaultFileSystem fileSystem = new DefaultFileSystem(new File(".")); - private final ActiveRules activeRules = mock(ActiveRules.class); - private final PmdConfiguration pmdConfiguration = mock(PmdConfiguration.class); - private final PmdTemplate pmdTemplate = mock(PmdTemplate.class); - private final JavaResourceLocator javaResourceLocator = mock(JavaResourceLocator.class); - private final MapSettings settings = new MapSettings(); - private final PmdExecutor realPmdExecutor = new PmdExecutor( - fileSystem, - activeRules, - pmdConfiguration, - javaResourceLocator, - settings.asConfig() - ); - - private PmdExecutor pmdExecutor; - - private static DefaultInputFile file(String path, Type type) { - return TestInputFileBuilder.create("sonar-pmd-test", path) - .setType(type) - .setLanguage(PmdConstants.LANGUAGE_KEY) - .build(); - } - - @BeforeEach - void setUp() { - pmdExecutor = Mockito.spy(realPmdExecutor); - fileSystem.setEncoding(StandardCharsets.UTF_8); - settings.setProperty(PmdConstants.JAVA_SOURCE_VERSION, "1.7"); - } - - @Test - void whenNoFilesToAnalyzeThenExecutionSucceedsWithBlankReport() { - - // when - final Report result = pmdExecutor.execute(); - - // then - assertThat(result).isNotNull(); - assertThat(result.isEmpty()).isTrue(); - } - - @Test - void should_execute_pmd_on_source_files_and_test_files() { - DefaultInputFile srcFile = file("src/Class.java", Type.MAIN); - DefaultInputFile tstFile = file("test/ClassTest.java", Type.TEST); - setupPmdRuleSet(PmdConstants.REPOSITORY_KEY, "simple.xml"); - setupPmdRuleSet(PmdConstants.TEST_REPOSITORY_KEY, "junit.xml"); - fileSystem.add(srcFile); - fileSystem.add(tstFile); - - Report report = pmdExecutor.execute(); - - assertThat(report).isNotNull(); - verify(pmdConfiguration).dumpXmlReport(report); - - // setting java source version to the default value - settings.removeProperty(PmdConstants.JAVA_SOURCE_VERSION); - report = pmdExecutor.execute(); - - assertThat(report).isNotNull(); - verify(pmdConfiguration).dumpXmlReport(report); - } - - @Test - void should_ignore_empty_test_dir() { - DefaultInputFile srcFile = file("src/Class.java", Type.MAIN); - doReturn(pmdTemplate).when(pmdExecutor).createPmdTemplate(any(URLClassLoader.class)); - setupPmdRuleSet(PmdConstants.REPOSITORY_KEY, "simple.xml"); - fileSystem.add(srcFile); - - pmdExecutor.execute(); - - verify(pmdTemplate).process(eq(srcFile), any(RuleSets.class), any(RuleContext.class)); - verifyNoMoreInteractions(pmdTemplate); - } - - @Test - void should_build_project_classloader_from_javaresourcelocator() throws Exception { - File file = new File("x"); - when(javaResourceLocator.classpath()).thenReturn(ImmutableList.of(file)); - pmdExecutor.execute(); - ArgumentCaptor classLoaderArgument = ArgumentCaptor.forClass(URLClassLoader.class); - verify(pmdExecutor).createPmdTemplate(classLoaderArgument.capture()); - URLClassLoader classLoader = classLoaderArgument.getValue(); - URL[] urls = classLoader.getURLs(); - assertThat(urls).containsOnly(file.toURI().toURL()); - } - - @Test - void invalid_classpath_element() { - File invalidFile = mock(File.class); - when(invalidFile.toURI()).thenReturn(URI.create("x://xxx")); - when(javaResourceLocator.classpath()).thenReturn(ImmutableList.of(invalidFile)); - - final Throwable thrown = catchThrowable(() -> pmdExecutor.execute()); - - assertThat(thrown) - .isInstanceOf(IllegalStateException.class) - .hasMessageContaining("Classpath"); - } - - @Test - void unknown_pmd_ruleset() { - when(pmdConfiguration.dumpXmlRuleSet(eq(PmdConstants.REPOSITORY_KEY), anyString())).thenReturn(new File("unknown")); - - DefaultInputFile srcFile = file("src/Class.java", Type.MAIN); - fileSystem.add(srcFile); - - final Throwable thrown = catchThrowable(() -> pmdExecutor.execute()); - - assertThat(thrown) - .isInstanceOf(IllegalStateException.class) - .hasCauseInstanceOf(RuleSetNotFoundException.class); - } - - private void setupPmdRuleSet(String repositoryKey, String profileFileName) { - final Path sourcePath = Paths.get("src/test/resources/org/sonar/plugins/pmd/").resolve(profileFileName); - when(pmdConfiguration.dumpXmlRuleSet(eq(repositoryKey), anyString())).thenReturn(sourcePath.toFile()); - } -} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdJavaExecutorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdJavaExecutorTest.java new file mode 100644 index 00000000..d7da7f66 --- /dev/null +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdJavaExecutorTest.java @@ -0,0 +1,123 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import net.sourceforge.pmd.lang.rule.RuleSet; +import net.sourceforge.pmd.reporting.Report; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.sonar.api.batch.fs.InputFile.Type; +import org.sonar.api.batch.fs.internal.DefaultInputFile; + +import java.io.File; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyIterable; +import static org.mockito.Mockito.*; + +class PmdJavaExecutorTest extends AbstractPmdExecutorTest { + + private final ClasspathProvider classpathProvider = mock(ClasspathProvider.class); + private PmdJavaExecutor realPmdExecutor; + + @BeforeEach + void setUp() { + realPmdExecutor = new PmdJavaExecutor( + fileSystem, + activeRules, + pmdConfiguration, + classpathProvider, + settings.asConfig() + ); + pmdExecutor = Mockito.spy(realPmdExecutor); + } + + @Override + protected DefaultInputFile getAppropriateInputFileForTest() { + return fileJava("src/Class.java", Type.MAIN); + } + + @Test + void should_execute_pmd_on_main_files_and_test_files() { + DefaultInputFile srcFile = fileJava("src/Class.java", Type.MAIN); + DefaultInputFile tstFile = fileJava("test/ClassTest.java", Type.TEST); + setupPmdRuleSet(PmdConstants.MAIN_JAVA_REPOSITORY_KEY, "simple.xml"); + fileSystem.add(srcFile); + fileSystem.add(tstFile); + + Report report = pmdExecutor.execute(); + + assertThat(report).isNotNull(); + verify(pmdConfiguration).dumpXmlReport(report); + + // setting java source version to the default value + settings.removeProperty(PmdConstants.JAVA_SOURCE_VERSION); + report = pmdExecutor.execute(); + + assertThat(report).isNotNull(); + verify(pmdConfiguration).dumpXmlReport(report); + } + + @Test + void should_ignore_empty_test_dir() { + DefaultInputFile srcFile = fileJava("src/Class.java", Type.MAIN); + doReturn(pmdTemplate).when(pmdExecutor).createPmdTemplate(any(URLClassLoader.class)); + setupPmdRuleSet(PmdConstants.MAIN_JAVA_REPOSITORY_KEY, "simple.xml"); + fileSystem.add(srcFile); + + pmdExecutor.execute(); + verify(pmdTemplate).process(anyIterable(), any(RuleSet.class)); + verifyNoMoreInteractions(pmdTemplate); + } + + @Test + void should_build_project_classloader_from_classpathprovider() throws Exception { + File file = new File("x"); + when(classpathProvider.classpath()).thenReturn(List.of(file)); + pmdExecutor.execute(); + ArgumentCaptor classLoaderArgument = ArgumentCaptor.forClass(URLClassLoader.class); + verify(pmdExecutor).createPmdTemplate(classLoaderArgument.capture()); + URLClassLoader classLoader = classLoaderArgument.getValue(); + URL[] urls = classLoader.getURLs(); + assertThat(urls).containsOnly(file.toURI().toURL()); + } + + @Test + void invalid_classpath_element() { + File invalidFile = mock(File.class); + when(invalidFile.toURI()).thenReturn(URI.create("x://xxx")); + when(classpathProvider.classpath()).thenReturn(List.of(invalidFile)); + + final Throwable thrown = catchThrowable(() -> pmdExecutor.execute()); + + assertThat(thrown) + .isInstanceOf(IllegalStateException.class) + .hasMessageContaining("Classpath"); + } + +} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdKotlinExecutorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdKotlinExecutorTest.java new file mode 100644 index 00000000..a62011e2 --- /dev/null +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdKotlinExecutorTest.java @@ -0,0 +1,115 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import net.sourceforge.pmd.lang.rule.RuleSet; +import net.sourceforge.pmd.reporting.Report; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.sonar.api.batch.fs.InputFile.Type; +import org.sonar.api.batch.fs.internal.DefaultInputFile; + +import java.net.URLClassLoader; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyIterable; +import static org.mockito.Mockito.*; + +class PmdKotlinExecutorTest extends AbstractPmdExecutorTest { + + private PmdKotlinExecutor realPmdExecutor; + + @BeforeEach + void setUp() { + realPmdExecutor = new PmdKotlinExecutor( + fileSystem, + activeRules, + pmdConfiguration, + settings.asConfig() + ); + pmdExecutor = Mockito.spy(realPmdExecutor); + } + + @Override + protected DefaultInputFile getAppropriateInputFileForTest() { + return fileKotlin("src/test/kotlin/TestKotlin.kt", Type.MAIN); + } + + @Test + void should_execute_pmd_on_kotlin_source_files() { + // Given + DefaultInputFile srcFile = fileKotlin("src/test/kotlin/TestKotlin.kt", Type.MAIN); + setupPmdRuleSet(PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY, "simple-kotlin.xml"); + fileSystem.add(srcFile); + + // When + Report report = pmdExecutor.execute(); + + // Then + assertThat(report).isNotNull(); + assertThat(report.getViolations()).hasSize(1); + assertThat(report.getProcessingErrors()).isEmpty(); + verify(pmdConfiguration).dumpXmlReport(report); + } + + @Test + void should_execute_pmd_on_kotlin_test_files() { + // Given + DefaultInputFile testFile = fileKotlin("src/test/kotlin/TestKotlinTest.kt", Type.TEST); + setupPmdRuleSet(PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY, "simple-kotlin.xml"); + fileSystem.add(testFile); + + // When + Report report = pmdExecutor.execute(); + + // Then + assertThat(report).isNotNull(); + verify(pmdConfiguration).dumpXmlReport(report); + } + + @Test + void should_ignore_empty_kotlin_test_dir() { + // Given + DefaultInputFile srcFile = fileKotlin("src/test/kotlin/TestKotlin.kt", Type.MAIN); + doReturn(pmdTemplate).when(pmdExecutor).createPmdTemplate(any(URLClassLoader.class)); + setupPmdRuleSet(PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY, "simple-kotlin.xml"); + fileSystem.add(srcFile); + + // When + pmdExecutor.execute(); + + // Then + verify(pmdTemplate).process(anyIterable(), any(RuleSet.class)); + verifyNoMoreInteractions(pmdTemplate); + } + + @Test + void should_create_empty_classloader() throws Exception { + // When + pmdExecutor.execute(); + + // Then + // Verify that createPmdTemplate is called with a URLClassLoader that has no URLs + verify(pmdExecutor).createPmdTemplate(argThat(classLoader -> + classLoader instanceof URLClassLoader && ((URLClassLoader) classLoader).getURLs().length == 0)); + } +} \ No newline at end of file diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdKotlinRulesDefinitionTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdKotlinRulesDefinitionTest.java new file mode 100644 index 00000000..719dbba2 --- /dev/null +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdKotlinRulesDefinitionTest.java @@ -0,0 +1,74 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import org.junit.jupiter.api.Test; +import org.sonar.api.server.rule.RulesDefinition; +import org.sonar.api.server.rule.RulesDefinition.Param; +import org.sonar.api.server.rule.RulesDefinition.Rule; +import org.sonar.plugins.pmd.rule.PmdKotlinRulesDefinition; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +class PmdKotlinRulesDefinitionTest { + + @Test + void test() { + PmdKotlinRulesDefinition definition = new PmdKotlinRulesDefinition(); + RulesDefinition.Context context = new RulesDefinition.Context(); + definition.define(context); + RulesDefinition.Repository repository = context.repository(PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY); + + assertThat(repository).withFailMessage("repository is null, does key exist").isNotNull(); + assertThat(repository.name()).isEqualTo(PmdConstants.REPOSITORY_KOTLIN_NAME); + assertThat(repository.language()).isEqualTo(PmdConstants.LANGUAGE_KOTLIN_KEY); + + List rules = repository.rules(); + assertThat(rules).isNotEmpty(); + + for (Rule rule : rules) { + assertThat(rule.key()).isNotNull(); + assertThat(rule.internalKey()).isNotNull(); + assertThat(rule.name()).isNotNull(); + assertThat(rule.htmlDescription()).isNotNull(); + assertThat(rule.severity()).isNotNull(); + + for (Param param : rule.params()) { + assertThat(param.name()).isNotNull(); + // Allow missing param descriptions in Kotlin rules as some params may not have explicit descriptions + } + } + } + + @Test + void should_exclude_java_rules() { + PmdKotlinRulesDefinition definition = new PmdKotlinRulesDefinition(); + RulesDefinition.Context context = new RulesDefinition.Context(); + definition.define(context); + RulesDefinition.Repository repository = context.repository(PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY); + + for (Rule rule : repository.rules()) { + assertThat(rule.key()).doesNotContain("AbstractClassWithoutAbstractMethod"); + } + } + +} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdLevelUtilsTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdLevelUtilsTest.java deleted file mode 100644 index 3fdfb207..00000000 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdLevelUtilsTest.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.pmd; - -import java.lang.reflect.Constructor; - -import org.junit.jupiter.api.Test; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.sonar.api.rules.RulePriority.BLOCKER; -import static org.sonar.api.rules.RulePriority.CRITICAL; -import static org.sonar.api.rules.RulePriority.INFO; -import static org.sonar.api.rules.RulePriority.MAJOR; -import static org.sonar.api.rules.RulePriority.MINOR; - -class PmdLevelUtilsTest { - @Test - void should_get_priority_from_level() { - assertThat(PmdLevelUtils.fromLevel(1)).isSameAs(BLOCKER); - assertThat(PmdLevelUtils.fromLevel(2)).isSameAs(CRITICAL); - assertThat(PmdLevelUtils.fromLevel(3)).isSameAs(MAJOR); - assertThat(PmdLevelUtils.fromLevel(4)).isSameAs(MINOR); - assertThat(PmdLevelUtils.fromLevel(5)).isSameAs(INFO); - assertThat(PmdLevelUtils.fromLevel(-1)).isNull(); - assertThat(PmdLevelUtils.fromLevel(null)).isNull(); - } - - @Test - void should_get_level_from_priority() { - assertThat(PmdLevelUtils.toLevel(BLOCKER)).isEqualTo(1); - assertThat(PmdLevelUtils.toLevel(CRITICAL)).isEqualTo(2); - assertThat(PmdLevelUtils.toLevel(MAJOR)).isEqualTo(3); - assertThat(PmdLevelUtils.toLevel(MINOR)).isEqualTo(4); - assertThat(PmdLevelUtils.toLevel(INFO)).isEqualTo(5); - } - - @Test - void private_constructor() throws Exception { - Constructor constructor = PmdLevelUtils.class.getDeclaredConstructor(); - assertThat(constructor.isAccessible()).isFalse(); - constructor.setAccessible(true); - constructor.newInstance(); - } -} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdPluginTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdPluginTest.java index 841ffb9b..f8d21b4e 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdPluginTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdPluginTest.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,18 +19,17 @@ */ package org.sonar.plugins.pmd; -import java.util.List; - import org.junit.jupiter.api.Test; import org.sonar.api.Plugin; +import org.sonar.api.SonarEdition; import org.sonar.api.SonarQubeSide; import org.sonar.api.SonarRuntime; import org.sonar.api.internal.SonarRuntimeImpl; import org.sonar.api.utils.Version; -import org.sonar.plugins.pmd.profile.PmdProfileExporter; -import org.sonar.plugins.pmd.profile.PmdProfileImporter; +import org.sonar.plugins.pmd.rule.PmdKotlinRulesDefinition; import org.sonar.plugins.pmd.rule.PmdRulesDefinition; -import org.sonar.plugins.pmd.rule.PmdUnitTestsRulesDefinition; + +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; @@ -42,22 +41,27 @@ class PmdPluginTest { @SuppressWarnings("unchecked") @Test void testPluginConfiguration() { - final SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.create(7, 3), SonarQubeSide.SCANNER); + // given + final SonarRuntime runtime = SonarRuntimeImpl.forSonarQube(Version.create(7, 3), SonarQubeSide.SCANNER, SonarEdition.COMMUNITY); final Plugin.Context context = new Plugin.Context(runtime); + // when subject.define(context); + + // then final List extensions = context.getExtensions(); - assertThat(extensions).hasSize(9); - assertThat(extensions).contains( - PmdSensor.class, - PmdConfiguration.class, - PmdExecutor.class, - PmdRulesDefinition.class, - PmdUnitTestsRulesDefinition.class, - PmdProfileExporter.class, - PmdProfileImporter.class, - PmdViolationRecorder.class - ); + assertThat(extensions) + .hasSize(9) + .contains( + PmdSensor.class, + PmdConfiguration.class, + PmdJavaExecutor.class, + PmdKotlinExecutor.class, + PmdRulesDefinition.class, + PmdKotlinRulesDefinition.class, + PmdViolationRecorder.class, + DefaultClasspathProvider.class + ); } // TODO Compare expected classes with all classes annotated with ScannerSide annotation. diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdPrioritiesTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdPrioritiesTest.java new file mode 100644 index 00000000..53c40c43 --- /dev/null +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdPrioritiesTest.java @@ -0,0 +1,73 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import org.junit.jupiter.api.Test; +import org.sonar.api.rule.Severity; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.api.rules.RulePriority.BLOCKER; +import static org.sonar.api.rules.RulePriority.CRITICAL; +import static org.sonar.api.rules.RulePriority.INFO; +import static org.sonar.api.rules.RulePriority.MAJOR; +import static org.sonar.api.rules.RulePriority.MINOR; + +class PmdPrioritiesTest { + + @Test + void should_get_priority_from_level() { + assertThat(PmdPriorities.toSonarPrio(1)).isSameAs(BLOCKER); + assertThat(PmdPriorities.toSonarPrio(2)).isSameAs(CRITICAL); + assertThat(PmdPriorities.toSonarPrio(3)).isSameAs(MAJOR); + assertThat(PmdPriorities.toSonarPrio(4)).isSameAs(MINOR); + assertThat(PmdPriorities.toSonarPrio(5)).isSameAs(INFO); + assertThat(PmdPriorities.toSonarPrio(-1)).isNull(); + assertThat(PmdPriorities.toSonarPrio(null)).isNull(); + } + + @Test + void should_get_priority_from_level_severity() { + assertThat(PmdPriorities.toSonarSeverity(1)).isSameAs(Severity.BLOCKER); + assertThat(PmdPriorities.toSonarSeverity(2)).isSameAs(Severity.CRITICAL); + assertThat(PmdPriorities.toSonarSeverity(3)).isSameAs(Severity.MAJOR); + assertThat(PmdPriorities.toSonarSeverity(4)).isSameAs(Severity.MINOR); + assertThat(PmdPriorities.toSonarSeverity(5)).isSameAs(Severity.INFO); + assertThat(PmdPriorities.toSonarSeverity(-1)).isNull(); + assertThat(PmdPriorities.toSonarSeverity(null)).isNull(); + } + + @Test + void should_get_level_from_priority() { + assertThat(PmdPriorities.fromSonarPrio(BLOCKER)).isEqualTo(1); + assertThat(PmdPriorities.fromSonarPrio(CRITICAL)).isEqualTo(2); + assertThat(PmdPriorities.fromSonarPrio(MAJOR)).isEqualTo(3); + assertThat(PmdPriorities.fromSonarPrio(MINOR)).isEqualTo(4); + assertThat(PmdPriorities.fromSonarPrio(INFO)).isEqualTo(5); + } + + @Test + void should_get_level_from_priority_severity() { + assertThat(PmdPriorities.fromSonarSeverity(Severity.BLOCKER)).isEqualTo(1); + assertThat(PmdPriorities.fromSonarSeverity(Severity.CRITICAL)).isEqualTo(2); + assertThat(PmdPriorities.fromSonarSeverity(Severity.MAJOR)).isEqualTo(3); + assertThat(PmdPriorities.fromSonarSeverity(Severity.MINOR)).isEqualTo(4); + assertThat(PmdPriorities.fromSonarSeverity(Severity.INFO)).isEqualTo(5); + } +} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdRulesDefinitionTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdRulesDefinitionTest.java index 024ae7ff..ae284ad4 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdRulesDefinitionTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdRulesDefinitionTest.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,16 +19,14 @@ */ package org.sonar.plugins.pmd; -import java.util.List; - -import com.google.common.collect.Iterables; import org.junit.jupiter.api.Test; -import org.sonar.api.PropertyType; import org.sonar.api.server.rule.RulesDefinition; import org.sonar.api.server.rule.RulesDefinition.Param; import org.sonar.api.server.rule.RulesDefinition.Rule; import org.sonar.plugins.pmd.rule.PmdRulesDefinition; +import java.util.List; + import static org.assertj.core.api.Assertions.assertThat; class PmdRulesDefinitionTest { @@ -38,13 +36,14 @@ void test() { PmdRulesDefinition definition = new PmdRulesDefinition(); RulesDefinition.Context context = new RulesDefinition.Context(); definition.define(context); - RulesDefinition.Repository repository = context.repository(PmdConstants.REPOSITORY_KEY); + RulesDefinition.Repository repository = context.repository(PmdConstants.MAIN_JAVA_REPOSITORY_KEY); assertThat(repository.name()).isEqualTo(PmdConstants.REPOSITORY_NAME); - assertThat(repository.language()).isEqualTo(PmdConstants.LANGUAGE_KEY); + assertThat(repository.language()).isEqualTo(PmdConstants.LANGUAGE_JAVA_KEY); List rules = repository.rules(); - assertThat(rules).hasSize(268); + + assertThat(rules).hasSize(292); for (Rule rule : rules) { assertThat(rule.key()).isNotNull(); @@ -53,6 +52,12 @@ void test() { assertThat(rule.htmlDescription()).isNotNull(); assertThat(rule.severity()).isNotNull(); + // Verify code blocks don't contain paragraph tags + String description = rule.htmlDescription(); + if (description.contains("

        "); + } + for (Param param : rule.params()) { assertThat(param.name()).isNotNull(); assertThat(param.description()) @@ -62,27 +67,4 @@ void test() { } } - @Test - void should_exclude_junit_rules() { - PmdRulesDefinition definition = new PmdRulesDefinition(); - RulesDefinition.Context context = new RulesDefinition.Context(); - definition.define(context); - RulesDefinition.Repository repository = context.repository(PmdConstants.REPOSITORY_KEY); - - for (Rule rule : repository.rules()) { - assertThat(rule.key()).doesNotContain("JUnitStaticSuite"); - } - } - - @Test - void should_use_text_parameter_for_xpath_rule() { - PmdRulesDefinition definition = new PmdRulesDefinition(); - RulesDefinition.Context context = new RulesDefinition.Context(); - definition.define(context); - RulesDefinition.Repository repository = context.repository(PmdConstants.REPOSITORY_KEY); - - Rule xpathRule = Iterables.find(repository.rules(), rule -> rule.key().equals("XPathRule")); - - assertThat(xpathRule.param("xpath").type().type()).isEqualTo(PropertyType.TEXT.name()); - } } diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java index 1e9ac431..cebfd4a3 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,12 +19,9 @@ */ package org.sonar.plugins.pmd; -import java.io.File; -import java.util.Iterator; - -import com.google.common.collect.Iterators; -import net.sourceforge.pmd.Report; -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.reporting.FileAnalysisListener; +import net.sourceforge.pmd.reporting.Report; +import net.sourceforge.pmd.reporting.RuleViolation; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.sonar.api.batch.fs.InputFile.Type; @@ -34,43 +31,28 @@ import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorDescriptor; +import java.io.File; +import java.util.function.Consumer; + import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.RETURNS_DEEP_STUBS; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.*; class PmdSensorTest { private final ActiveRules profile = mock(ActiveRules.class, RETURNS_DEEP_STUBS); - private final PmdExecutor executor = mock(PmdExecutor.class); + private final PmdJavaExecutor javaExecutor = mock(PmdJavaExecutor.class); + private final PmdKotlinExecutor kotlinExecutor = mock(PmdKotlinExecutor.class); private final PmdViolationRecorder pmdViolationRecorder = mock(PmdViolationRecorder.class); private final SensorContext sensorContext = mock(SensorContext.class); private final DefaultFileSystem fs = new DefaultFileSystem(new File(".")); private PmdSensor pmdSensor; - private static RuleViolation violation() { - return mock(RuleViolation.class); - } - - private static Report report(RuleViolation... violations) { - Report report = mock(Report.class); - when(report.iterator()).thenReturn(Iterators.forArray(violations)); - return report; - } - @BeforeEach void setUpPmdSensor() { - pmdSensor = new PmdSensor(profile, executor, pmdViolationRecorder, fs); - when(executor.execute()).thenReturn(mock(Report.class)); + pmdSensor = new PmdSensor(profile, javaExecutor, kotlinExecutor, pmdViolationRecorder, fs); } @Test @@ -83,7 +65,7 @@ void should_execute_on_project_without_main_files() { pmdSensor.execute(sensorContext); // then - verify(executor, atLeastOnce()).execute(); + verify(javaExecutor, atLeastOnce()).execute(); } @Test @@ -96,7 +78,33 @@ void should_execute_on_project_without_test_files() { pmdSensor.execute(sensorContext); // then - verify(executor, atLeastOnce()).execute(); + verify(javaExecutor, atLeastOnce()).execute(); + } + + @Test + void should_execute_kotlin_executor_on_project_with_kotlin_main_files() { + + // given + addOneKotlinFile(Type.MAIN); + + // when + pmdSensor.execute(sensorContext); + + // then + verify(kotlinExecutor, atLeastOnce()).execute(); + } + + @Test + void should_execute_kotlin_executor_on_project_with_kotlin_test_files() { + + // given + addOneKotlinFile(Type.TEST); + + // when + pmdSensor.execute(sensorContext); + + // then + verify(kotlinExecutor, atLeastOnce()).execute(); } @Test @@ -109,7 +117,8 @@ void should_not_execute_on_project_without_any_files() { pmdSensor.execute(sensorContext); // then - verify(executor, never()).execute(); + verify(javaExecutor, never()).execute(); + verify(kotlinExecutor, never()).execute(); } @Test @@ -118,15 +127,18 @@ void should_not_execute_on_project_without_active_rules() { // given addOneJavaFile(Type.MAIN); addOneJavaFile(Type.TEST); + addOneKotlinFile(Type.MAIN); + addOneKotlinFile(Type.TEST); - when(profile.findByRepository(PmdConstants.REPOSITORY_KEY).isEmpty()).thenReturn(true); - when(profile.findByRepository(PmdConstants.TEST_REPOSITORY_KEY).isEmpty()).thenReturn(true); + when(profile.findByRepository(PmdConstants.MAIN_JAVA_REPOSITORY_KEY).isEmpty()).thenReturn(true); + when(profile.findByRepository(PmdConstants.MAIN_KOTLIN_REPOSITORY_KEY).isEmpty()).thenReturn(true); // when pmdSensor.execute(sensorContext); // then - verify(executor, never()).execute(); + verify(javaExecutor, never()).execute(); + verify(kotlinExecutor, never()).execute(); } @Test @@ -135,8 +147,22 @@ void should_report_violations() { // given addOneJavaFile(Type.MAIN); final RuleViolation pmdViolation = violation(); - final Report report = report(pmdViolation); - when(executor.execute()).thenReturn(report); + mockExecutorResult(pmdViolation); + + // when + pmdSensor.execute(sensorContext); + + // then + verify(pmdViolationRecorder).saveViolation(pmdViolation, sensorContext); + } + + @Test + void should_report_kotlin_violations() { + + // given + addOneKotlinFile(Type.MAIN); + final RuleViolation pmdViolation = violation(); + mockKotlinExecutorResult(pmdViolation); // when pmdSensor.execute(sensorContext); @@ -149,8 +175,22 @@ void should_report_violations() { void should_not_report_zero_violation() { // given - final Report report = report(); - when(executor.execute()).thenReturn(report); + mockExecutorResult(); + + // when + pmdSensor.execute(sensorContext); + + // then + verify(pmdViolationRecorder, never()).saveViolation(any(RuleViolation.class), eq(sensorContext)); + verifyNoMoreInteractions(sensorContext); + } + + @Test + void should_not_report_zero_kotlin_violation() { + + // given + mockKotlinExecutorResult(); + addOneKotlinFile(Type.MAIN); // when pmdSensor.execute(sensorContext); @@ -164,10 +204,22 @@ void should_not_report_zero_violation() { void should_not_report_invalid_violation() { // given - final RuleViolation pmdViolation = violation(); - final Report report = report(pmdViolation); - when(executor.execute()).thenReturn(report); - when(report.iterator()).thenReturn(Iterators.forArray(pmdViolation)); + mockExecutorResult(violation()); + + // when + pmdSensor.execute(sensorContext); + + // then + verify(pmdViolationRecorder, never()).saveViolation(any(RuleViolation.class), eq(sensorContext)); + verifyNoMoreInteractions(sensorContext); + } + + @Test + void should_not_report_invalid_kotlin_violation() { + + // given + mockKotlinExecutorResult(violation()); + addOneKotlinFile(Type.MAIN); // when pmdSensor.execute(sensorContext); @@ -184,7 +236,25 @@ void pmdSensorShouldNotRethrowOtherExceptions() { addOneJavaFile(Type.MAIN); final RuntimeException expectedException = new RuntimeException(); - when(executor.execute()).thenThrow(expectedException); + when(javaExecutor.execute()).thenThrow(expectedException); + + // when + final Throwable thrown = catchThrowable(() -> pmdSensor.execute(sensorContext)); + + // then + assertThat(thrown) + .isInstanceOf(RuntimeException.class) + .isEqualTo(expectedException); + } + + @Test + void pmdSensorShouldNotRethrowKotlinExecutorExceptions() { + + // given + addOneKotlinFile(Type.MAIN); + + final RuntimeException expectedException = new RuntimeException(); + when(kotlinExecutor.execute()).thenThrow(expectedException); // when final Throwable thrown = catchThrowable(() -> pmdSensor.execute(sensorContext)); @@ -206,29 +276,42 @@ void whenDescribeCalledThenSensorDescriptionIsWritten() { // given final SensorDescriptor mockDescriptor = mock(SensorDescriptor.class); - when(mockDescriptor.onlyOnLanguage(anyString())).thenReturn(mockDescriptor); + when(mockDescriptor.onlyOnLanguages(anyString(), anyString())).thenReturn(mockDescriptor); // when pmdSensor.describe(mockDescriptor); // then - verify(mockDescriptor).onlyOnLanguage(PmdConstants.LANGUAGE_KEY); + verify(mockDescriptor).onlyOnLanguages(PmdConstants.LANGUAGE_JAVA_KEY, PmdConstants.LANGUAGE_KOTLIN_KEY); verify(mockDescriptor).name("PmdSensor"); } - @SuppressWarnings("unchecked") - private void mockEmptyReport() { - final Report mockReport = mock(Report.class); - final Iterator iterator = mock(Iterator.class); + private static RuleViolation violation() { + return mock(RuleViolation.class); + } + + private void mockExecutorResult(RuleViolation... violations) { + when(javaExecutor.execute()) + .thenReturn(createReport(violations)); + } + + private void mockKotlinExecutorResult(RuleViolation... violations) { + when(kotlinExecutor.execute()) + .thenReturn(createReport(violations)); + } - when(mockReport.iterator()).thenReturn(iterator); - when(iterator.hasNext()).thenReturn(false); + private Report createReport(RuleViolation... violations) { + Consumer fileAnalysisListenerConsumer = fal -> { + for (RuleViolation violation : violations) { + fal.onRuleViolation(violation); + } + }; - when(executor.execute()).thenReturn(mockReport); + return Report.buildReport(fileAnalysisListenerConsumer); } private void addOneJavaFile(Type type) { - mockEmptyReport(); + mockExecutorResult(); File file = new File("x"); fs.add( TestInputFileBuilder.create( @@ -240,4 +323,18 @@ private void addOneJavaFile(Type type) { .build() ); } + + private void addOneKotlinFile(Type type) { + mockKotlinExecutorResult(); + File file = new File("x.kt"); + fs.add( + TestInputFileBuilder.create( + "sonar-pmd-test", + file.getName() + ) + .setLanguage("kotlin") + .setType(type) + .build() + ); + } } diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTemplateTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTemplateTest.java index 9bdc2215..02bdebc1 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTemplateTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTemplateTest.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,134 +19,51 @@ */ package org.sonar.plugins.pmd; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.List; -import java.util.stream.Collectors; - -import net.sourceforge.pmd.PMDConfiguration; -import net.sourceforge.pmd.PMDException; -import net.sourceforge.pmd.RuleContext; -import net.sourceforge.pmd.RuleSets; -import net.sourceforge.pmd.SourceCodeProcessor; -import net.sourceforge.pmd.lang.java.JavaLanguageHandler; +import net.sourceforge.pmd.lang.Language; import org.junit.jupiter.api.Test; -import org.mockito.stubbing.Answer; -import org.sonar.api.batch.fs.InputFile; -import org.sonar.api.batch.fs.internal.TestInputFileBuilder; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.nio.charset.StandardCharsets; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; class PmdTemplateTest { - private final RuleSets rulesets = mock(RuleSets.class); - private final RuleContext ruleContext = mock(RuleContext.class); - private final PMDConfiguration configuration = mock(PMDConfiguration.class); - private final SourceCodeProcessor processor = mock(SourceCodeProcessor.class); - private final InputFile inputFile = TestInputFileBuilder.create( - "src", - "test/resources/org/sonar/plugins/pmd/source.txt" - ).build(); - - @Test - void should_process_input_file() throws Exception { - doAnswer((Answer) invocation -> { - final InputStream inputStreamArg = (InputStream) invocation.getArguments()[0]; - final List inputStreamLines = - new BufferedReader(new InputStreamReader(inputStreamArg)) - .lines() - .collect(Collectors.toList()); - assertThat(inputStreamLines).containsExactly("Example source"); - return null; - }).when(processor).processSourceCode(any(InputStream.class), eq(rulesets), eq(ruleContext)); - - new PmdTemplate(configuration, processor).process(inputFile, rulesets, ruleContext); - - verify(ruleContext).setSourceCodeFilename(inputFile.uri().toString()); - verify(processor).processSourceCode(any(InputStream.class), eq(rulesets), eq(ruleContext)); - } - - @Test - void should_ignore_PMD_error() throws PMDException { - doThrow(new PMDException("BUG")) - .when(processor).processSourceCode(any(InputStream.class), any(RuleSets.class), any(RuleContext.class)); - - new PmdTemplate(configuration, processor).process(inputFile, rulesets, ruleContext); - } - - @Test - void java12_version() { - assertThat(PmdTemplate.languageVersion("1.2").getLanguageVersionHandler()).isInstanceOf(JavaLanguageHandler.class); - } - - @Test - void java5_version() { - assertThat(PmdTemplate.languageVersion("5").getLanguageVersionHandler()).isInstanceOf(JavaLanguageHandler.class); - } - - @Test - void java6_version() { - assertThat(PmdTemplate.languageVersion("6").getLanguageVersionHandler()).isInstanceOf(JavaLanguageHandler.class); - } - - @Test - void java7_version() { - assertThat(PmdTemplate.languageVersion("7").getLanguageVersionHandler()).isInstanceOf(JavaLanguageHandler.class); - } - - @Test - void java8_version() { - assertThat(PmdTemplate.languageVersion("8").getLanguageVersionHandler()).isInstanceOf(JavaLanguageHandler.class); - } - - @Test - void java9_version() { - assertThat(PmdTemplate.languageVersion("9").getLanguageVersionHandler()).isInstanceOf(JavaLanguageHandler.class); - } + @ParameterizedTest + @ValueSource(strings = { + "6", "7", "8", "9", "1.9", "10", "1.10", "11", "1.11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23" + }) + void verifyCanHandleJavaLanguageVersion(String javaVersion) { + final Language language = PmdTemplate + .languageVersion(javaVersion) + .getLanguage(); - @Test - void java9_version_with_outdated_versioning_scheme() { - assertThat(PmdTemplate.languageVersion("1.9").getLanguageVersionHandler()).isInstanceOf(JavaLanguageHandler.class); + assertThat(language).isNotNull(); } @Test - void java10_version() { - assertThat(PmdTemplate.languageVersion("10").getLanguageVersionHandler()).isInstanceOf(JavaLanguageHandler.class); - } + void should_fail_on_invalid_java_version() { - @Test - void java10_version_with_outdated_versioning_scheme() { - assertThat(PmdTemplate.languageVersion("1.10").getLanguageVersionHandler()).isInstanceOf(JavaLanguageHandler.class); - } + // when + final Throwable thrown = catchThrowable(() -> PmdTemplate.create("12.2", mock(ClassLoader.class), StandardCharsets.UTF_8)); - @Test - void java11_version() { - assertThat(PmdTemplate.languageVersion("11").getLanguageVersionHandler()).isInstanceOf(JavaLanguageHandler.class); + // then + assertThat(thrown) + .isInstanceOf(IllegalArgumentException.class); } @Test - void java11_version_with_outdated_versioning_scheme() { - assertThat(PmdTemplate.languageVersion("1.11").getLanguageVersionHandler()).isInstanceOf(JavaLanguageHandler.class); - } + void shouldnt_fail_on_valid_java_version() { - @Test - void should_fail_on_invalid_java_version() { - final Throwable thrown = catchThrowable(() -> PmdTemplate.create("12.2", mock(ClassLoader.class), StandardCharsets.UTF_8)); - assertThat(thrown).isInstanceOf(IllegalArgumentException.class); - } + // when + PmdTemplate result = PmdTemplate.create("6", mock(ClassLoader.class), StandardCharsets.UTF_8); - @Test - void shouldnt_fail_on_valid_java_version() { - PmdTemplate.create("6", mock(ClassLoader.class), StandardCharsets.UTF_8); + // then + assertThat(result) + .isNotNull(); } /** diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTestUtils.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTestUtils.java index ed084639..d58c32e4 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTestUtils.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdTestUtils.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdUnitTestsRulesDefinitionTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdUnitTestsRulesDefinitionTest.java deleted file mode 100644 index 694adf97..00000000 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdUnitTestsRulesDefinitionTest.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.pmd; - -import java.util.List; - -import org.junit.jupiter.api.Test; -import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.api.server.rule.RulesDefinition.Param; -import org.sonar.api.server.rule.RulesDefinition.Rule; -import org.sonar.plugins.pmd.rule.PmdUnitTestsRulesDefinition; - -import static org.assertj.core.api.Assertions.assertThat; - -class PmdUnitTestsRulesDefinitionTest { - - @Test - void test() { - - PmdUnitTestsRulesDefinition definition = new PmdUnitTestsRulesDefinition(); - RulesDefinition.Context context = new RulesDefinition.Context(); - definition.define(context); - RulesDefinition.Repository repository = context.repository(PmdConstants.TEST_REPOSITORY_KEY); - - assertThat(repository) - .isNotNull() - .hasFieldOrPropertyWithValue("name", PmdConstants.TEST_REPOSITORY_NAME) - .hasFieldOrPropertyWithValue("language", PmdConstants.LANGUAGE_KEY); - - List rules = repository.rules(); - assertThat(rules).hasSize(17); - - for (Rule rule : rules) { - assertThat(rule.key()).isNotNull(); - assertThat(rule.key()).isIn( - "JUnitStaticSuite", - "JUnitSpelling", - "JUnitAssertionsShouldIncludeMessage", - "JUnitTestsShouldIncludeAssert", - "TestClassWithoutTestCases", - "UnnecessaryBooleanAssertion", - "UseAssertEqualsInsteadOfAssertTrue", - "UseAssertSameInsteadOfAssertTrue", - "UseAssertNullInsteadOfAssertTrue", - "SimplifyBooleanAssertion", - "UseAssertTrueInsteadOfAssertEquals", - "JUnitTestContainsTooManyAsserts", - "JUnit4SuitesShouldUseSuiteAnnotation", - "JUnit4TestShouldUseAfterAnnotation", - "JUnit4TestShouldUseBeforeAnnotation", - "JUnit4TestShouldUseTestAnnotation", - "JUnitUseExpected"); - assertThat(rule.internalKey()).isNotNull(); - assertThat(rule.name()).isNotNull(); - assertThat(rule.htmlDescription()).isNotNull(); - assertThat(rule.severity()).isNotNull(); - - for (Param param : rule.params()) { - assertThat(param.name()).isNotNull(); - assertThat(param.description()) - .overridingErrorMessage("Description is not set for parameter '" + param.name() + "' of rule '" + rule.key()) - .isNotNull(); - } - } - } -} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdViolationRecorderTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdViolationRecorderTest.java index 00f7f405..288a4313 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdViolationRecorderTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdViolationRecorderTest.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,9 @@ */ package org.sonar.plugins.pmd; -import java.io.File; - -import net.sourceforge.pmd.Rule; -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.lang.document.FileId; +import net.sourceforge.pmd.lang.rule.Rule; +import net.sourceforge.pmd.reporting.RuleViolation; import org.junit.jupiter.api.Test; import org.sonar.api.batch.fs.FilePredicate; import org.sonar.api.batch.fs.TextRange; @@ -36,12 +35,10 @@ import org.sonar.api.batch.sensor.issue.NewIssueLocation; import org.sonar.api.rule.RuleKey; +import java.io.File; + import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.verifyNoMoreInteractions; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; class PmdViolationRecorderTest { @@ -49,7 +46,7 @@ class PmdViolationRecorderTest { private final ActiveRules mockActiveRules = mock(ActiveRules.class); private final SensorContext mockContext = mock(SensorContext.class); - private final PmdViolationRecorder pmdViolationRecorder = new PmdViolationRecorder(spiedFs, mockActiveRules); + private final PmdViolationRecorder subject = new PmdViolationRecorder(spiedFs, mockActiveRules); @Test void should_convert_pmd_violation_to_sonar_violation() { @@ -71,7 +68,7 @@ void should_convert_pmd_violation_to_sonar_violation() { when(issueLocation.at(any(TextRange.class))).thenReturn(issueLocation); // when - pmdViolationRecorder.saveViolation(pmdViolation, mockContext); + subject.saveViolation(pmdViolation, mockContext); // then verify(mockContext).newIssue(); @@ -86,7 +83,7 @@ void should_ignore_violation_on_unknown_resource() { final RuleViolation pmdViolation = createPmdViolation(unknownFile, "RULE"); // when - pmdViolationRecorder.saveViolation(pmdViolation, mockContext); + subject.saveViolation(pmdViolation, mockContext); // then verifyNoMoreInteractions(mockActiveRules); @@ -102,11 +99,11 @@ void should_ignore_violation_on_unknown_rule() { addToFileSystem(file1); final String ruleName = "UNKNOWN"; final RuleViolation pmdViolation = createPmdViolation(file1, ruleName); - final RuleKey expectedRuleKey1 = RuleKey.of(PmdConstants.REPOSITORY_KEY, ruleName); - final RuleKey expectedRuleKey2 = RuleKey.of(PmdConstants.REPOSITORY_KEY, ruleName); + final RuleKey expectedRuleKey1 = RuleKey.of(PmdConstants.MAIN_JAVA_REPOSITORY_KEY, ruleName); + final RuleKey expectedRuleKey2 = RuleKey.of(PmdConstants.MAIN_JAVA_REPOSITORY_KEY, ruleName); // when - pmdViolationRecorder.saveViolation(pmdViolation, mockContext); + subject.saveViolation(pmdViolation, mockContext); // then verify(spiedFs).inputFile(any(FilePredicate.class)); @@ -137,7 +134,7 @@ private RuleViolation createPmdViolation(File file, String ruleName) { final RuleViolation pmdViolation = mock(RuleViolation.class); when(rule.getName()).thenReturn(ruleName); - when(pmdViolation.getFilename()).thenReturn(file.toURI().toString()); + when(pmdViolation.getFileId()).thenReturn(FileId.fromPath(file.toPath())); when(pmdViolation.getBeginLine()).thenReturn(2); when(pmdViolation.getDescription()).thenReturn("Description"); when(pmdViolation.getRule()).thenReturn(rule); diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/RuleSetLoaderLoggingTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/RuleSetLoaderLoggingTest.java new file mode 100644 index 00000000..7f7f6caf --- /dev/null +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/RuleSetLoaderLoggingTest.java @@ -0,0 +1,108 @@ +/* + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.plugins.pmd; + +import net.sourceforge.pmd.lang.rule.RuleSetLoadException; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.fs.internal.TestInputFileBuilder; +import org.sonar.api.config.internal.MapSettings; +import org.sonar.api.rule.RuleScope; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.catchThrowable; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +/** + * Verifies that the extra information provided by PMD's RuleSetLoader (via PmdReporter) + * is visible in logging (stderr) when ruleset loading fails. + */ +class RuleSetLoaderLoggingTest { + + private final MapSettings settings = new MapSettings(); + private PmdJavaExecutor executor; + + private final ByteArrayOutputStream errContent = new ByteArrayOutputStream(); + private PrintStream originalErr; + + @BeforeEach + void setUp() { + // Minimal file system with one Java file to trigger execution + var fs = new org.sonar.api.batch.fs.internal.DefaultFileSystem(new File(".")); + fs.setEncoding(StandardCharsets.UTF_8); + DefaultInputFile src = TestInputFileBuilder.create("sonar-pmd-test", "src/Class.java") + .setLanguage(PmdConstants.LANGUAGE_JAVA_KEY) + .setType(InputFile.Type.MAIN) + .build(); + fs.add(src); + + var activeRules = org.mockito.Mockito.mock(org.sonar.api.batch.rule.ActiveRules.class); + var pmdConfig = org.mockito.Mockito.mock(PmdConfiguration.class); + var classpathProvider = org.mockito.Mockito.mock(ClasspathProvider.class); + + // Point the dumped ruleset to our intentionally invalid ruleset file + Path invalid = Paths.get("src/test/resources/org/sonar/plugins/pmd/invalid-ref.xml"); + when(pmdConfig.dumpXmlRuleSet(eq(PmdConstants.MAIN_JAVA_REPOSITORY_KEY), anyString(), eq(RuleScope.MAIN))) + .thenReturn(invalid.toFile()); + when(pmdConfig.dumpXmlRuleSet(eq(PmdConstants.MAIN_JAVA_REPOSITORY_KEY), anyString(), eq(RuleScope.TEST))) + .thenReturn(invalid.toFile()); + + executor = Mockito.spy(new PmdJavaExecutor(fs, activeRules, pmdConfig, classpathProvider, settings.asConfig())); + + // Capture stderr where AbstractPmdExecutor writes reporter output + originalErr = System.err; + System.setErr(new PrintStream(errContent, true, StandardCharsets.UTF_8)); + } + + @AfterEach + void tearDown() { + System.setErr(originalErr); + } + + @Test + void should_log_rule_set_loader_details_to_stderr() { + Throwable thrown = catchThrowable(() -> executor.execute()); + + // We still expect the wrapped RuleSetLoadException as before + assertThat(thrown) + .isInstanceOf(IllegalStateException.class) + .hasCauseInstanceOf(RuleSetLoadException.class); + + // And now verify that additional details were printed to stderr by the reporter + String stderr = errContent.toString(StandardCharsets.UTF_8); + // Robust check: must contain our bogus rule id, which should be echoed by PMD's diagnostics + assertThat(stderr) + .isNotBlank() + .contains("ThisRuleDoesNotExist"); + } +} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/TextRangeCalculatorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/TextRangeCalculatorTest.java index ee217bdb..c4b2ea15 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/TextRangeCalculatorTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/TextRangeCalculatorTest.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,7 @@ */ package org.sonar.plugins.pmd; -import net.sourceforge.pmd.RuleViolation; +import net.sourceforge.pmd.reporting.RuleViolation; import org.junit.jupiter.api.Test; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.TextRange; diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileExporterTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileExporterTest.java deleted file mode 100644 index f079ef91..00000000 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileExporterTest.java +++ /dev/null @@ -1,265 +0,0 @@ -/* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.pmd.profile; - -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; - -import com.google.common.base.CharMatcher; -import org.assertj.core.api.Condition; -import org.junit.jupiter.api.Test; -import org.mockito.stubbing.Answer; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RuleFinder; -import org.sonar.api.rules.RuleQuery; -import org.sonar.api.server.rule.RulesDefinition; -import org.sonar.api.server.rule.RulesDefinition.Param; -import org.sonar.api.utils.ValidationMessages; -import org.sonar.plugins.pmd.PmdConstants; -import org.sonar.plugins.pmd.PmdTestUtils; -import org.sonar.plugins.pmd.rule.PmdRulesDefinition; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.catchThrowable; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class PmdProfileExporterTest { - - private static final CharMatcher EOLS = CharMatcher.anyOf("\n\r"); - - private final PmdProfileExporter exporter = new PmdProfileExporter(); - - private static RulesProfile importProfile(String configuration) { - PmdRulesDefinition definition = new PmdRulesDefinition(); - RulesDefinition.Context context = new RulesDefinition.Context(); - definition.define(context); - RulesDefinition.Repository repository = context.repository(PmdConstants.REPOSITORY_KEY); - RuleFinder ruleFinder = createRuleFinder(repository.rules()); - PmdProfileImporter importer = new PmdProfileImporter(ruleFinder); - - return importer.importProfile(new StringReader(configuration), ValidationMessages.create()); - } - - private static RuleFinder createRuleFinder(final List rules) { - RuleFinder ruleFinder = mock(RuleFinder.class); - final List convertedRules = convert(rules); - - when(ruleFinder.find(any(RuleQuery.class))).then((Answer) invocation -> { - RuleQuery query = (RuleQuery) invocation.getArguments()[0]; - for (Rule rule : convertedRules) { - if (query.getConfigKey().equals(rule.getConfigKey())) { - return rule; - } - } - return null; - }); - return ruleFinder; - } - - private static List convert(List rules) { - List results = new ArrayList<>(rules.size()); - for (RulesDefinition.Rule rule : rules) { - Rule newRule = Rule.create(rule.repository().key(), rule.key(), rule.name()) - .setDescription(rule.htmlDescription()) - .setRepositoryKey(rule.repository().key()) - .setConfigKey(rule.internalKey()); - if (!rule.params().isEmpty()) { - for (Param param : rule.params()) { - newRule.createParameter(param.name()).setDefaultValue(param.defaultValue()); - } - } - results.add(newRule); - } - return results; - } - - private static Condition equalsIgnoreEOL(String text) { - final String strippedText = EOLS.removeFrom(text); - - return new Condition() { - @Override - public boolean matches(String value) { - return EOLS.removeFrom(value).equals(strippedText); - } - }.as("equal to " + strippedText); - } - - @Test - void should_export_pmd_profile_on_writer() { - String importedXml = PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/export_simple.xml"); - - StringWriter stringWriter = new StringWriter(); - exporter.exportProfile(importProfile(importedXml), stringWriter); - - assertThat(stringWriter.toString()).satisfies(equalsIgnoreEOL(importedXml)); - } - - @Test - void should_export_pmd_profile_on_writer_exception() throws IOException { - - // given - final String importedXml = PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/export_simple.xml"); - final Writer writer = mock(Writer.class); - doThrow(new IOException("test exception")).when(writer).write(anyString()); - - // when - final Throwable thrown = catchThrowable(() -> exporter.exportProfile(importProfile(importedXml), writer)); - - // then - assertThat(thrown) - .isInstanceOf(IllegalStateException.class) - .hasMessage("An exception occurred while generating the PMD configuration file from profile: null"); - } - - /* @Test - void should_export_pmd_profile() { - String importedXml = PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/export_simple.xml"); - - String exportedXml = exporter.exportProfile(PmdConstants.REPOSITORY_KEY, importProfile(importedXml)); - - assertThat(exportedXml).satisfies(equalsIgnoreEOL(importedXml)); - }*/ - - /* @Test - void should_skip_empty_params() { - String importedXml = PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/export_rule_with_empty_param.xml"); - - String expected = "\n" + - "\n" + - " Sonar Profile: pmd\n" + - " \n" + - " 2\n" + - " \n" + - " \n" + - " \n" + - " \n" + - " \n" + - ""; - - String actual = exporter.exportProfile(PmdConstants.REPOSITORY_KEY, importProfile(importedXml)); - assertThat(actual).satisfies(equalsIgnoreEOL(expected)); - }*/ - - @Test - void should_skip_all_empty_params() { - String importedXml = PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/export_rule_with_all_params_empty.xml"); - - String expected = "\n" + - "\n" + - " Sonar Profile: pmd\n" + - " \n" + - " 2\n" + - " \n" + - ""; - - final StringWriter writer = new StringWriter(); - exporter.exportProfile(importProfile(importedXml), writer); - assertThat(writer.toString()).satisfies(equalsIgnoreEOL(expected)); - } - - @Test - void should_export_empty_configuration_as_xml() { - - final StringWriter writer = new StringWriter(); - - exporter.exportProfile(RulesProfile.create(), writer); - - assertThat(writer.toString()).satisfies(equalsIgnoreEOL("" + - " Sonar Profile: pmd")); - } - - @Test - void should_export_xPath_rule() { - Rule rule = Rule.create(PmdConstants.REPOSITORY_KEY, "MyOwnRule", "This is my own xpath rule.") - .setConfigKey(PmdConstants.XPATH_CLASS) - .setRepositoryKey(PmdConstants.REPOSITORY_KEY); - rule.createParameter(PmdConstants.XPATH_EXPRESSION_PARAM); - rule.createParameter(PmdConstants.XPATH_MESSAGE_PARAM); - - RulesProfile profile = RulesProfile.create(); - ActiveRule xpath = profile.activateRule(rule, null); - xpath.setParameter(PmdConstants.XPATH_EXPRESSION_PARAM, "//FieldDeclaration"); - xpath.setParameter(PmdConstants.XPATH_MESSAGE_PARAM, "This is bad"); - - final StringWriter writer = new StringWriter(); - exporter.exportProfile(profile, writer); - - - assertThat(writer.toString()).satisfies(equalsIgnoreEOL(PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/export_xpath_rules.xml"))); - } -/* - @Test - void should_fail_if_message_not_provided_for_xPath_rule() { - - // given - final PmdRule rule = new PmdRule(PmdConstants.XPATH_CLASS); - - rule.addProperty(new PmdProperty(PmdConstants.XPATH_EXPRESSION_PARAM, "xpathExpression")); - rule.setName("MyOwnRule"); - - // when - final Throwable thrown = catchThrowable(() -> PmdProfileExporter.processXPathRule("xpathKey", rule)); - - // then - assertThat(thrown).isInstanceOf(IllegalArgumentException.class); - }*//* - - @Test - void should_process_xPath_rule() { - PmdRule rule = new PmdRule(PmdConstants.XPATH_CLASS); - rule.setName("MyOwnRule"); - rule.addProperty(new PmdProperty(PmdConstants.XPATH_EXPRESSION_PARAM, "xpathExpression")); - rule.addProperty(new PmdProperty(PmdConstants.XPATH_MESSAGE_PARAM, "message")); - - PmdProfileExporter.processXPathRule("xpathKey", rule); - - assertThat(rule.getMessage()).isEqualTo("message"); - assertThat(rule.getRef()).isNull(); - assertThat(rule.getClazz()).isEqualTo(PmdConstants.XPATH_CLASS); - assertThat(rule.getProperty(PmdConstants.XPATH_MESSAGE_PARAM)).isNull(); - assertThat(rule.getName()).isEqualTo("xpathKey"); - assertThat(rule.getProperty(PmdConstants.XPATH_EXPRESSION_PARAM).getValue()).isEqualTo("xpathExpression"); - } -*//* - @Test - void should_fail_if_xPath_not_provided() { - - // given - final PmdRule rule = new PmdRule(PmdConstants.XPATH_CLASS); - rule.setName("MyOwnRule"); - rule.addProperty(new PmdProperty(PmdConstants.XPATH_MESSAGE_PARAM, "This is bad")); - - // when - final Throwable thrown = catchThrowable(() -> PmdProfileExporter.processXPathRule("xpathKey", rule)); - - // then - assertThat(thrown).isInstanceOf(IllegalArgumentException.class); - }*/ -} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileImporterTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileImporterTest.java deleted file mode 100644 index c87ef2ed..00000000 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileImporterTest.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -package org.sonar.plugins.pmd.profile; - -import java.io.Reader; -import java.io.StringReader; - -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.stubbing.Answer; -import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.Rule; -import org.sonar.api.rules.RuleFinder; -import org.sonar.api.rules.RulePriority; -import org.sonar.api.rules.RuleQuery; -import org.sonar.api.utils.ValidationMessages; -import org.sonar.plugins.pmd.PmdTestUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -class PmdProfileImporterTest { - - private PmdProfileImporter importer; - private ValidationMessages messages; - - private static Reader read(String path) { - return new StringReader(PmdTestUtils.getResourceContent(path)); - } - - private static RuleFinder createRuleFinder() { - RuleFinder ruleFinder = mock(RuleFinder.class); - when(ruleFinder.find(any(RuleQuery.class))).then((Answer) invocation -> { - RuleQuery query = (RuleQuery) invocation.getArguments()[0]; - String configKey = query.getConfigKey(); - String key = configKey.substring(configKey.lastIndexOf('/') + 1); - Rule rule = Rule.create(query.getRepositoryKey(), key, "").setConfigKey(configKey).setSeverity(RulePriority.BLOCKER); - if (rule.getConfigKey().equals("rulesets/java/coupling.xml/ExcessiveImports")) { - rule.createParameter("minimum"); - } - return rule; - }); - return ruleFinder; - } - - @BeforeEach - void setUpImporter() { - messages = ValidationMessages.create(); - importer = new PmdProfileImporter(createRuleFinder()); - } - - @Test - void should_import_simple_profile() { - Reader reader = read("/org/sonar/plugins/pmd/simple.xml"); - - RulesProfile profile = importer.importProfile(reader, messages); - - assertThat(profile.getActiveRules()).hasSize(3); - assertThat(profile.getActiveRuleByConfigKey("pmd", "rulesets/java/coupling.xml/ExcessiveImports")).isNotNull(); - assertThat(profile.getActiveRuleByConfigKey("pmd", "rulesets/java/design.xml/UseNotifyAllInsteadOfNotify")).isNotNull(); - assertThat(messages.hasErrors()).isFalse(); - } - - @Test - void should_import_profile_with_xpath_rule() { - Reader reader = read("/org/sonar/plugins/pmd/export_xpath_rules.xml"); - - RulesProfile profile = importer.importProfile(reader, messages); - - assertThat(profile.getActiveRules()).isEmpty(); - assertThat(messages.hasWarnings()).isTrue(); - } - - @Test - void should_import_parameter() { - Reader reader = read("/org/sonar/plugins/pmd/simple.xml"); - - RulesProfile profile = importer.importProfile(reader, messages); - ActiveRule activeRule = profile.getActiveRuleByConfigKey("pmd", "rulesets/java/coupling.xml/ExcessiveImports"); - - assertThat(activeRule.getParameter("minimum")).isEqualTo("30"); - } - - @Test - void should_import_default_priority() { - Reader reader = read("/org/sonar/plugins/pmd/simple.xml"); - - RulesProfile profile = importer.importProfile(reader, messages); - ActiveRule activeRule = profile.getActiveRuleByConfigKey("pmd", "rulesets/java/coupling.xml/ExcessiveImports"); - - assertThat(activeRule.getSeverity()).isSameAs(RulePriority.BLOCKER); - } - - @Test - void should_import_priority() { - Reader reader = read("/org/sonar/plugins/pmd/simple.xml"); - - RulesProfile profile = importer.importProfile(reader, messages); - - ActiveRule activeRule = profile.getActiveRuleByConfigKey("pmd", "rulesets/java/design.xml/UseNotifyAllInsteadOfNotify"); - assertThat(activeRule.getSeverity()).isSameAs(RulePriority.MINOR); - - activeRule = profile.getActiveRuleByConfigKey("pmd", "rulesets/java/coupling.xml/CouplingBetweenObjects"); - assertThat(activeRule.getSeverity()).isSameAs(RulePriority.CRITICAL); - } - - @Test - void should_import_pmd_configuration_with_unknown_nodes() { - Reader reader = read("/org/sonar/plugins/pmd/complex-with-unknown-nodes.xml"); - - RulesProfile profile = importer.importProfile(reader, messages); - - assertThat(profile.getActiveRules()).hasSize(3); - } - - @Test - void should_deal_with_unsupported_property() { - Reader reader = read("/org/sonar/plugins/pmd/simple.xml"); - - RulesProfile profile = importer.importProfile(reader, messages); - ActiveRule check = profile.getActiveRuleByConfigKey("pmd", "rulesets/java/coupling.xml/CouplingBetweenObjects"); - - assertThat(check.getParameter("threshold")).isNull(); - assertThat(messages.getWarnings()).hasSize(2); - } - - @Test - void should_fail_on_invalid_xml() { - Reader reader = new StringReader("not xml"); - - importer.importProfile(reader, messages); - - assertThat(messages.getErrors()).hasSize(1); - } - - @Test - void should_warn_on_unknown_rule() { - Reader reader = read("/org/sonar/plugins/pmd/simple.xml"); - - importer = new PmdProfileImporter(mock(RuleFinder.class)); - RulesProfile profile = importer.importProfile(reader, messages); - - assertThat(profile.getActiveRules()).isEmpty(); - assertThat(messages.getWarnings()).hasSize(4); - } -} diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java index a9d0f625..c28d9f5e 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java @@ -1,7 +1,7 @@ /* - * SonarQube PMD Plugin - * Copyright (C) 2012-2019 SonarSource SA - * mailto:info AT sonarsource DOT com + * SonarQube PMD7 Plugin + * Copyright (C) 2012-2021 SonarSource SA and others + * mailto:jborgers AT jpinpoint DOT com; peter.paul.bakker AT stokpop DOT nl * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -17,7 +17,6 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - package org.sonar.plugins.pmd.xml; import java.io.IOException; @@ -26,7 +25,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.sonar.api.batch.rule.ActiveRules; -import org.sonar.api.profiles.RulesProfile; import org.sonar.api.utils.ValidationMessages; import static org.assertj.core.api.Assertions.assertThat; @@ -75,18 +73,4 @@ void whenActiveRulesGivenThenRuleSetIsReturned() { .isNotNull(); } - @Test - void whenRulesProfileGivenThenRuleSetIsReturned() { - - // given - final RulesProfile mockedProfile = mock(RulesProfile.class); - final String anyRepoKey = "TEST"; - - // when - final PmdRuleSet result = PmdRuleSets.from(mockedProfile, anyRepoKey); - - // then - assertThat(result) - .isNotNull(); - } } \ No newline at end of file diff --git a/sonar-pmd-plugin/src/test/kotlin/TestKotlin.kt b/sonar-pmd-plugin/src/test/kotlin/TestKotlin.kt new file mode 100644 index 00000000..629186aa --- /dev/null +++ b/sonar-pmd-plugin/src/test/kotlin/TestKotlin.kt @@ -0,0 +1,3 @@ +fun a(): Int { return 1 } + +fun abc(): Int { return 2 } \ No newline at end of file diff --git a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_rule_with_all_params_empty.xml b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_rule_with_all_params_empty.xml index 07f8b46b..bb8d24e2 100644 --- a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_rule_with_all_params_empty.xml +++ b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_rule_with_all_params_empty.xml @@ -1,5 +1,6 @@ - + + Sonar Profile: pmd 2 diff --git a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_xpath_rules.xml b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_xpath_rules.xml index ab7cc906..c7ecd079 100644 --- a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_xpath_rules.xml +++ b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/export_xpath_rules.xml @@ -1,7 +1,7 @@ Sonar Profile: pmd - + 3 diff --git a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/invalid-ref.xml b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/invalid-ref.xml new file mode 100644 index 00000000..66d731b5 --- /dev/null +++ b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/invalid-ref.xml @@ -0,0 +1,5 @@ + + + Intentional invalid rule reference to trigger RuleSetLoader logging + + diff --git a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/junit.xml b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/junit.xml deleted file mode 100644 index 09653f46..00000000 --- a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/junit.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - Sonar PMD Unit Tests rules - - 2 - - diff --git a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/simple-kotlin.xml b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/simple-kotlin.xml new file mode 100644 index 00000000..ca69da70 --- /dev/null +++ b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/simple-kotlin.xml @@ -0,0 +1,7 @@ + + + Sonar PMD kotlin rules + + 2 + + diff --git a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/simple.xml b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/simple.xml index 86acb5cf..5e72b60d 100644 --- a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/simple.xml +++ b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/simple.xml @@ -1,21 +1,21 @@ - + Sonar PMD rules - + 2 - + - - - - + - + 4 + + + - + 3 diff --git a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/source.txt b/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/source.txt deleted file mode 100644 index 365abf5c..00000000 --- a/sonar-pmd-plugin/src/test/resources/org/sonar/plugins/pmd/source.txt +++ /dev/null @@ -1 +0,0 @@ -Example source \ No newline at end of file diff --git a/travis.sh b/travis.sh deleted file mode 100755 index 98f14a30..00000000 --- a/travis.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/bin/bash - -set -eo pipefail - -case "$TEST" in - -ci) - mvn clean org.jacoco:jacoco-maven-plugin:prepare-agent install sonar:sonar verify -B -e -V -Dskip.failsafe.tests - ;; - -plugin) - - # Unset environment settings defined by Travis that will collide with our integration tests - unset SONARQUBE_SCANNER_PARAMS SONAR_TOKEN SONAR_SCANNER_HOME - - # Run integration tests - mvn verify -Dtest.sonar.version=${SQ_VERSION} -Dtest.sonar.plugin.version.java=${SJ_VERSION} -Dskip.surefire.tests -Dorchestrator.artifactory.url=https://repox.jfrog.io/repox - ;; - -javadoc) - # Create JavaDocs to check for problems with JavaDoc generation - mvn install javadoc:javadoc -DskipTests - ;; - -*) - echo "Unexpected TEST mode: $TEST" - exit 1 - ;; - -esac