diff --git a/.all-contributorsrc b/.all-contributorsrc index 3b92bf99c3..e05387dca9 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -7699,6 +7699,42 @@ "contributions": [ "bug" ] + }, + { + "login": "rbri", + "name": "RBRi", + "avatar_url": "https://avatars.githubusercontent.com/u/2544132?v=4", + "profile": "https://github.com/rbri", + "contributions": [ + "bug" + ] + }, + { + "login": "jbisotti", + "name": "Jamie Bisotti", + "avatar_url": "https://avatars.githubusercontent.com/u/899712?v=4", + "profile": "https://github.com/jbisotti", + "contributions": [ + "bug" + ] + }, + { + "login": "soloturn", + "name": "soloturn", + "avatar_url": "https://avatars.githubusercontent.com/u/825568?v=4", + "profile": "https://github.com/soloturn", + "contributions": [ + "bug" + ] + }, + { + "login": "schosin", + "name": "schosin", + "avatar_url": "https://avatars.githubusercontent.com/u/1669777?v=4", + "profile": "https://github.com/schosin", + "contributions": [ + "bug" + ] } ], "contributorsPerLine": 7, diff --git a/.github/dependabot.yml b/.github/dependabot.yml index d674a5bc29..75a3d100eb 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,13 +1,23 @@ version: 2 +# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file updates: - package-ecosystem: "maven" directory: "/" schedule: interval: "weekly" - target-branch: "master" - open-pull-requests-limit: 0 + - package-ecosystem: "bundler" + directories: + - "/" + - "/docs" + schedule: + interval: "weekly" + groups: + all-gems: + patterns: [ "*" ] - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" - target-branch: "master" + groups: + all-actions: + patterns: [ "*" ] diff --git a/Gemfile.lock b/Gemfile.lock index 858d9626a0..9a7014556a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,9 +1,8 @@ GEM remote: https://rubygems.org/ specs: - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) - base64 (0.2.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) bigdecimal (3.1.8) claide (1.1.0) claide-plugins (0.9.2) @@ -11,10 +10,10 @@ GEM nap open4 (~> 1.3) colored2 (3.1.2) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.4) cork (0.3.0) colored2 (~> 3.1) - danger (9.4.3) + danger (9.5.0) claide (~> 1.0) claide-plugins (>= 0.9.2) colored2 (~> 3.1) @@ -24,19 +23,19 @@ GEM git (~> 1.13) kramdown (~> 2.3) kramdown-parser-gfm (~> 1.0) - no_proxy_fix octokit (>= 4.0) terminal-table (>= 1, < 4) differ (0.1.2) et-orbi (1.2.11) tzinfo - faraday (2.9.0) - faraday-net_http (>= 2.0, < 3.2) + faraday (2.11.0) + faraday-net_http (>= 2.0, < 3.4) + logger faraday-http-cache (2.5.1) faraday (>= 0.8) - faraday-net_http (3.1.0) + faraday-net_http (3.3.0) net-http - fugit (1.11.0) + fugit (1.11.1) et-orbi (~> 1, >= 1.2.11) raabro (~> 1.4) git (1.19.1) @@ -46,16 +45,15 @@ GEM rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) - liquid (5.5.0) + liquid (5.5.1) + logger (1.6.0) logger-colors (1.0.0) nap (1.1.0) net-http (0.4.1) uri - no_proxy_fix (0.1.2) - nokogiri (1.16.5-x86_64-linux) + nokogiri (1.16.7-x86_64-linux) racc (~> 1.4) - octokit (8.1.0) - base64 + octokit (9.1.0) faraday (>= 1, < 3) sawyer (~> 0.9) open4 (1.3.4) @@ -66,13 +64,13 @@ GEM nokogiri (~> 1.13) rufus-scheduler (~> 3.8) slop (~> 4.9) - public_suffix (5.0.5) + public_suffix (6.0.1) raabro (1.4.0) - racc (1.8.0) + racc (1.8.1) rchardet (1.8.0) - rexml (3.2.8) - strscan (>= 3.0.9) - rouge (4.2.1) + rexml (3.3.6) + strscan + rouge (4.3.0) rufus-scheduler (3.9.1) fugit (~> 1.1, >= 1.1.6) safe_yaml (1.0.5) @@ -86,7 +84,7 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) - uri (0.13.0) + uri (0.13.1) PLATFORMS x86_64-linux diff --git a/do-release.sh b/do-release.sh index 269b2d8589..64435f8622 100755 --- a/do-release.sh +++ b/do-release.sh @@ -126,21 +126,43 @@ echo "Press enter to continue..." read -r -# calculating stats for release notes +# determine current milestone +MILESTONE_JSON=$(curl -s "https://api.github.com/repos/pmd/pmd/milestones?state=all&direction=desc&per_page=5"|jq ".[] | select(.title == \"$RELEASE_VERSION\")") +MILESTONE=$(echo "$MILESTONE_JSON" | jq .number) +# determine dependency updates +DEPENDENCIES_JSON=$(curl -s "https://api.github.com/repos/pmd/pmd/issues?labels=dependencies&state=closed&direction=asc&per_page=50&page=1&milestone=${MILESTONE}") +DEPENDENCIES_COUNT=$(echo "$DEPENDENCIES_JSON" | jq length) +DEPENDENCIES="" +if [ $DEPENDENCIES_COUNT -gt 0 ]; then + DEPENDENCIES=$( + echo "### 📦 Dependency updates" + echo "$DEPENDENCIES_JSON" | jq --raw-output '.[] | "* [#\(.number)](https://github.com/pmd/pmd/issues/\(.number)): \(.title)"' + ) +else + DEPENDENCIES=$( + echo "### 📦 Dependency updates" + echo "No dependency updates" + ) +fi + +# calculating stats for release notes (excluding dependency updates) +STATS_CLOSED_ISSUES=$(echo "$MILESTONE_JSON" | jq .closed_issues) STATS=$( echo "### 📈 Stats" echo "* $(git log pmd_releases/"${LAST_VERSION}"..HEAD --oneline --no-merges |wc -l) commits" -echo "* $(curl -s "https://api.github.com/repos/pmd/pmd/milestones?state=all&direction=desc&per_page=5"|jq ".[] | select(.title == \"$RELEASE_VERSION\") | .closed_issues") closed tickets & PRs" +echo "* $(($STATS_CLOSED_ISSUES - $DEPENDENCIES_COUNT)) closed tickets & PRs" echo "* Days since last release: $(( ( $(date +%s) - $(git log --max-count=1 --format="%at" pmd_releases/"${LAST_VERSION}") ) / 86400))" ) + TEMP_RELEASE_NOTES=$(cat docs/pages/release_notes.md) -TEMP_RELEASE_NOTES=${TEMP_RELEASE_NOTES/\{\% endtocmaker \%\}/${STATS//\&/\\\&}$'\n'$'\n'\{\% endtocmaker \%\}} +TEMP_RELEASE_NOTES=${TEMP_RELEASE_NOTES/\{\% endtocmaker \%\}/${DEPENDENCIES//\&/\\\&}$'\n'$'\n'${STATS//\&/\\\&}$'\n'$'\n'\{\% endtocmaker \%\}} echo "${TEMP_RELEASE_NOTES}" > docs/pages/release_notes.md echo -echo "Updated stats in release notes:" +echo "Updated dependencies and stats in release notes:" +echo "$DEPENDENCIES" echo "$STATS" echo echo "Please verify docs/pages/release_notes.md" diff --git a/docs/Gemfile.lock b/docs/Gemfile.lock index bd44b12521..3f44ef4782 100644 --- a/docs/Gemfile.lock +++ b/docs/Gemfile.lock @@ -1,18 +1,19 @@ GEM remote: https://rubygems.org/ specs: - activesupport (7.1.3.3) + activesupport (7.2.1) base64 bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) + concurrent-ruby (~> 1.0, >= 1.3.1) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) base64 (0.2.0) bigdecimal (3.1.8) coffee-script (2.4.1) @@ -21,10 +22,10 @@ GEM coffee-script-source (1.12.2) colorator (1.1.0) commonmarker (0.23.10) - concurrent-ruby (1.2.3) + concurrent-ruby (1.3.4) connection_pool (2.4.1) csv (3.3.0) - dnsruby (1.72.1) + dnsruby (1.72.2) simpleidn (~> 0.2.1) drb (2.2.1) em-websocket (0.5.3) @@ -34,19 +35,20 @@ GEM ffi (>= 1.15.0) eventmachine (1.2.7) execjs (2.9.1) - faraday (2.9.0) - faraday-net_http (>= 2.0, < 3.2) - faraday-net_http (3.1.0) + faraday (2.11.0) + faraday-net_http (>= 2.0, < 3.4) + logger + faraday-net_http (3.3.0) net-http - ffi (1.16.3) + ffi (1.17.0-x86_64-linux-gnu) forwardable-extended (2.6.0) gemoji (4.1.0) - github-pages (231) + github-pages (232) github-pages-health-check (= 1.18.2) - jekyll (= 3.9.5) + jekyll (= 3.10.0) jekyll-avatar (= 0.8.0) jekyll-coffeescript (= 1.2.2) - jekyll-commonmark-ghpages (= 0.4.0) + jekyll-commonmark-ghpages (= 0.5.1) jekyll-default-layout (= 0.1.5) jekyll-feed (= 0.17.0) jekyll-gist (= 1.5.0) @@ -83,9 +85,10 @@ GEM liquid (= 4.0.4) mercenary (~> 0.3) minima (= 2.5.1) - nokogiri (>= 1.13.6, < 2.0) + nokogiri (>= 1.16.2, < 2.0) rouge (= 3.30.0) terminal-table (~> 1.4) + webrick (~> 1.8) github-pages-health-check (1.18.2) addressable (~> 2.3) dnsruby (~> 1.60) @@ -98,9 +101,10 @@ GEM http_parser.rb (0.8.0) i18n (1.14.5) concurrent-ruby (~> 1.0) - jekyll (3.9.5) + jekyll (3.10.0) addressable (~> 2.4) colorator (~> 1.0) + csv (~> 3.0) em-websocket (~> 0.5) i18n (>= 0.7, < 2) jekyll-sass-converter (~> 1.0) @@ -111,6 +115,7 @@ GEM pathutil (~> 0.9) rouge (>= 1.7, < 4) safe_yaml (~> 1.0) + webrick (>= 1.0) jekyll-avatar (0.8.0) jekyll (>= 3.0, < 5.0) jekyll-coffeescript (1.2.2) @@ -118,9 +123,9 @@ GEM coffee-script-source (~> 1.12) jekyll-commonmark (1.4.0) commonmarker (~> 0.22) - jekyll-commonmark-ghpages (0.4.0) - commonmarker (~> 0.23.7) - jekyll (~> 3.9.0) + jekyll-commonmark-ghpages (0.5.1) + commonmarker (>= 0.23.7, < 1.1.0) + jekyll (>= 3.9, < 4.0) jekyll-commonmark (~> 1.4.0) rouge (>= 2.0, < 5.0) jekyll-default-layout (0.1.5) @@ -214,29 +219,29 @@ GEM listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) + logger (1.6.0) mercenary (0.3.6) minima (2.5.1) jekyll (>= 3.5, < 5.0) jekyll-feed (~> 0.9) jekyll-seo-tag (~> 2.1) - minitest (5.23.1) - mutex_m (0.2.0) + minitest (5.25.1) net-http (0.4.1) uri - nokogiri (1.16.5-x86_64-linux) + nokogiri (1.16.7-x86_64-linux) racc (~> 1.4) octokit (4.25.1) faraday (>= 1, < 3) sawyer (~> 0.9) pathutil (0.16.2) forwardable-extended (~> 2.6) - public_suffix (5.0.5) - racc (1.8.0) + public_suffix (5.1.1) + racc (1.8.1) rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) - rexml (3.2.8) - strscan (>= 3.0.9) + rexml (3.3.6) + strscan rouge (3.30.0) rubyzip (2.3.2) safe_yaml (1.0.5) @@ -248,6 +253,7 @@ GEM sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) + securerandom (0.3.1) simpleidn (0.2.3) strscan (3.1.0) terminal-table (1.8.0) @@ -257,7 +263,7 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (1.8.0) - uri (0.13.0) + uri (0.13.1) webrick (1.8.1) PLATFORMS diff --git a/docs/_config.yml b/docs/_config.yml index 3302938c99..49d9d14b24 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -1,9 +1,9 @@ repository: pmd/pmd pmd: - version: 7.4.0-SNAPSHOT - previous_version: 7.3.0 - date: 2024-07-26 + version: 7.5.0-SNAPSHOT + previous_version: 7.4.0 + date: 2024-08-30 # release types: major, minor, bugfix release_type: minor diff --git a/docs/pages/pmd/projectdocs/committers/releasing.md b/docs/pages/pmd/projectdocs/committers/releasing.md index 2a733d6a68..3bb05898df 100644 --- a/docs/pages/pmd/projectdocs/committers/releasing.md +++ b/docs/pages/pmd/projectdocs/committers/releasing.md @@ -2,7 +2,7 @@ title: Release process permalink: pmd_projectdocs_committers_releasing.html author: Romain Pelisse , Andreas Dangel -last_updated: April 2024 +last_updated: July 2024 (7.5.0) --- This page describes the current status of the release process. @@ -67,8 +67,8 @@ news posts can be changed afterward (although that's an entirely manual process) You can find the release notes here: `docs/pages/release_notes.md`. -The date (`date +%d-%B-%Y`) and the version (remove the SNAPSHOT) must be updated in `docs/_config.yml`, e.g. -in order to release version "6.34.0", the configuration should look like this: +The date (`date +%Y-%m-%d`) and the version (remove the SNAPSHOT) must be updated in `docs/_config.yml`, e.g. +in order to release version "7.2.0", the configuration should look like this: ```yaml pmd: @@ -78,7 +78,7 @@ pmd: release_type: minor ``` -The release type could be one of "bugfix" (e.g. 7.1.x), "minor" (7.x.0), or "major" (x.0.0). +The release type could be one of "bugfix" (e.g. 7.2.x), "minor" (7.x.0), or "major" (x.0.0). The release notes usually mention any new rules that have been added since the last release. @@ -95,25 +95,50 @@ not pmd-cli and pmd-dist. In case, there is no need for a new pmd-designer version, we could stick to the latest already available version. Then we can skip the release of pmd-designer and immediately start the second phase of the release. +Starting with PMD 7.5.0 we use Dependabot to update dependencies. Dependabot will create pull requests +labeled with `dependencies`. When we merge such a pull request, we should assign it to the correct +milestone. It is important, that the due date of the milestone is set correctly, otherwise the query won't find +the milestone number. +Then we can query which PRs have been merged and generate a section for the release notes: + +```shell +NEW_VERSION=7.2.0 +MILESTONE_JSON=$(curl -s "https://api.github.com/repos/pmd/pmd/milestones?state=all&direction=desc&per_page=5"|jq ".[] | select(.title == \"$NEW_VERSION\")") +MILESTONE=$(echo "$MILESTONE_JSON" | jq .number) + +# determine dependency updates +DEPENDENCIES_JSON=$(curl -s "https://api.github.com/repos/pmd/pmd/issues?labels=dependencies&state=closed&direction=asc&per_page=50&page=1&milestone=${MILESTONE}") +DEPENDENCIES_COUNT=$(echo "$DEPENDENCIES_JSON" | jq length) +if [ $DEPENDENCIES_COUNT -gt 0 ]; then + echo "### 📦 Dependency updates" + echo "$DEPENDENCIES_JSON" | jq --raw-output '.[] | "* [#\(.number)](https://github.com/pmd/pmd/issues/\(.number)): \(.title)"' +else + echo "### 📦 Dependency updates" + echo "No dependency updates" +fi +``` +This section needs to be added to the release notes at the end. + Starting with PMD 6.23.0 we'll provide small statistics for every release. This needs to be added -to the release notes as the last section. To count the closed issues and pull requests, the milestone +to the release notes as the last section (after "Dependency updates"). To count the closed issues and pull requests, the milestone on GitHub with the title of the new release is searched. It is important, that the due date of the milestone is correctly set, as the returned milestones in the API call are sorted by due date. Make sure, there is such a milestone on . The following snippet will -create the numbers, that can be attached to the release notes as a last section: +create the numbers, that can be attached to the release notes as a last section. Note: It uses part of the +above code snippet (e.g. NEW_VERSION, MILESTONE, DEPENDENCIES_COUNT): ```shell LAST_VERSION=7.1.0 -NEW_VERSION=7.2.0 NEW_VERSION_COMMITISH=HEAD +STATS_CLOSED_ISSUES=$(echo "$MILESTONE_JSON" | jq .closed_issues) echo "### Stats" echo "* $(git log pmd_releases/${LAST_VERSION}..${NEW_VERSION_COMMITISH} --oneline --no-merges |wc -l) commits" -echo "* $(curl -s "https://api.github.com/repos/pmd/pmd/milestones?state=all&direction=desc&per_page=5"|jq ".[] | select(.title == \"$NEW_VERSION\") | .closed_issues") closed tickets & PRs" +echo "* $(($STATS_CLOSED_ISSUES - $DEPENDENCIES_COUNT)) closed tickets & PRs" echo "* Days since last release: $(( ( $(date +%s) - $(git log --max-count=1 --format="%at" pmd_releases/${LAST_VERSION}) ) / 86400))" ``` -Note: this part is also integrated into `do-release.sh`. +Note: both shell snippets are also integrated into `do-release.sh`. Check in all (version) changes to branch master or any other branch, from which the release takes place: diff --git a/docs/pages/pmd/projectdocs/credits.md b/docs/pages/pmd/projectdocs/credits.md index d925bb54f8..9bf613b252 100644 --- a/docs/pages/pmd/projectdocs/credits.md +++ b/docs/pages/pmd/projectdocs/credits.md @@ -345,750 +345,756 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d JJengility
JJengility

🐛 Jake Hemmerle
Jake Hemmerle

🐛 James Harrison
James Harrison

🐛 💻 - Jan
Jan

🐛 + Jamie Bisotti
Jamie Bisotti

🐛 + Jan
Jan

🐛 Jan Aertgeerts
Jan Aertgeerts

💻 🐛 Jan Brümmer
Jan Brümmer

🐛 Jan Tříska
Jan Tříska

🐛 Jan-Lukas Else
Jan-Lukas Else

🐛 Jason Qiu
Jason Qiu

💻 📖 Jason Williams
Jason Williams

🐛 - Jean-Paul Mayer
Jean-Paul Mayer

🐛 + Jean-Paul Mayer
Jean-Paul Mayer

🐛 Jean-Simon Larochelle
Jean-Simon Larochelle

🐛 Jeff Bartolotta
Jeff Bartolotta

💻 🐛 Jeff Hube
Jeff Hube

💻 🐛 Jeff Jensen
Jeff Jensen

🐛 Jeff May
Jeff May

🐛 Jens Gerdes
Jens Gerdes

🐛 - Jeroen Borgers
Jeroen Borgers

🐛 💻 📢 + Jeroen Borgers
Jeroen Borgers

🐛 💻 📢 Jeroen Meijer
Jeroen Meijer

🐛 Jeroen van Wilgenburg
Jeroen van Wilgenburg

📖 Jerome Russ
Jerome Russ

🐛 JerritEic
JerritEic

💻 📖 🐛 Jiri Pejchal
Jiri Pejchal

🐛 Jithin Sunny
Jithin Sunny

🐛 - Jiří Škorpil
Jiří Škorpil

🐛 + Jiří Škorpil
Jiří Škorpil

🐛 Joao Machado
Joao Machado

🐛 Jochen Krauss
Jochen Krauss

🐛 Johan Hammar
Johan Hammar

🐛 John Karp
John Karp

🐛 John Zhang
John Zhang

🐛 John-Teng
John-Teng

💻 🐛 - Jon Moroney
Jon Moroney

💻 🐛 + Jon Moroney
Jon Moroney

💻 🐛 Jonas Geiregat
Jonas Geiregat

🐛 Jonas Keßler
Jonas Keßler

🐛 Jonathan Wiesel
Jonathan Wiesel

💻 🐛 Jordan
Jordan

🐛 Jordi Llach
Jordi Llach

🐛 Jorge Solórzano
Jorge Solórzano

🐛 - JorneVL
JorneVL

🐛 + JorneVL
JorneVL

🐛 Jose Palafox
Jose Palafox

🐛 Jose Stovall
Jose Stovall

🐛 Joseph
Joseph

💻 Joseph Heenan
Joseph Heenan

🐛 Josh Feingold
Josh Feingold

💻 🐛 Josh Holthaus
Josh Holthaus

🐛 - Joshua S Arquilevich
Joshua S Arquilevich

🐛 + Joshua S Arquilevich
Joshua S Arquilevich

🐛 João Dinis Ferreira
João Dinis Ferreira

📖 João Ferreira
João Ferreira

💻 🐛 João Pedro Schmitt
João Pedro Schmitt

🐛 Juan Martín Sotuyo Dodero
Juan Martín Sotuyo Dodero

💻 📖 🐛 🚧 Juan Pablo Civile
Juan Pablo Civile

🐛 Julian Voronetsky
Julian Voronetsky

🐛 - Julien
Julien

🐛 + Julien
Julien

🐛 Julius
Julius

🐛 JustPRV
JustPRV

🐛 Justin Stroud
Justin Stroud

💻 Jörn Huxhorn
Jörn Huxhorn

🐛 KThompso
KThompso

🐛 Kai Amundsen
Kai Amundsen

🐛 - Karel Vervaeke
Karel Vervaeke

🐛 + Karel Vervaeke
Karel Vervaeke

🐛 Karl-Andero Mere
Karl-Andero Mere

🐛 Karl-Philipp Richter
Karl-Philipp Richter

🐛 Karsten Silz
Karsten Silz

🐛 Kazuma Watanabe
Kazuma Watanabe

🐛 Kev
Kev

🐛 Keve Müller
Keve Müller

🐛 - Kevin Guerra
Kevin Guerra

💻 + Kevin Guerra
Kevin Guerra

💻 Kevin Jones
Kevin Jones

🐛 💻 Kevin Poorman
Kevin Poorman

🐛 Kevin Wayne
Kevin Wayne

🐛 Kieran Black
Kieran Black

🐛 Kirill Zubov
Kirill Zubov

🐛 Kirk Clemens
Kirk Clemens

💻 🐛 - Klaus Hartl
Klaus Hartl

🐛 + Klaus Hartl
Klaus Hartl

🐛 Koen Van Looveren
Koen Van Looveren

🐛 Kris Scheibe
Kris Scheibe

💻 🐛 Krystian Dabrowski
Krystian Dabrowski

🐛 💻 Kunal Thanki
Kunal Thanki

🐛 LaLucid
LaLucid

💻 Larry Diamond
Larry Diamond

💻 🐛 - Lars Knickrehm
Lars Knickrehm

🐛 + Lars Knickrehm
Lars Knickrehm

🐛 Laurent Bovet
Laurent Bovet

🐛 💻 Leo Gutierrez
Leo Gutierrez

🐛 LiGaOg
LiGaOg

💻 Liam Sharp
Liam Sharp

🐛 Lintsi
Lintsi

🐛 Linus Fernandes
Linus Fernandes

🐛 - Lixon Lookose
Lixon Lookose

🐛 + Lixon Lookose
Lixon Lookose

🐛 Logesh
Logesh

🐛 Lorenzo Gabriele
Lorenzo Gabriele

🐛 Loïc Ledoyen
Loïc Ledoyen

🐛 Lucas
Lucas

🐛 Lucas Silva
Lucas Silva

🐛 Lucas Soncini
Lucas Soncini

💻 🐛 - Luis Alcantar
Luis Alcantar

💻 + Luis Alcantar
Luis Alcantar

💻 Lukasz Slonina
Lukasz Slonina

🐛 Lukebray
Lukebray

🐛 Lynn
Lynn

💻 🐛 Lyor Goldstein
Lyor Goldstein

🐛 MCMicS
MCMicS

🐛 Macarse
Macarse

🐛 - Machine account for PMD
Machine account for PMD

💻 + Machine account for PMD
Machine account for PMD

💻 Maciek Siemczyk
Maciek Siemczyk

🐛 Maikel Steneker
Maikel Steneker

💻 🐛 Maksim Moiseikin
Maksim Moiseikin

🐛 Manfred Koch
Manfred Koch

🐛 Manuel Moya Ferrer
Manuel Moya Ferrer

💻 🐛 Manuel Ryan
Manuel Ryan

🐛 - Marat Vyshegorodtsev
Marat Vyshegorodtsev

🐛 + Marat Vyshegorodtsev
Marat Vyshegorodtsev

🐛 Marcel Härle
Marcel Härle

🐛 Marcello Fialho
Marcello Fialho

🐛 Marcin Dąbrowski
Marcin Dąbrowski

💻 Marcin Rataj
Marcin Rataj

🐛 Marcono1234
Marcono1234

🐛 Mark Adamcin
Mark Adamcin

🐛 - Mark Hall
Mark Hall

💻 🐛 + Mark Hall
Mark Hall

💻 🐛 Mark Kolich
Mark Kolich

🐛 Mark Pritchard
Mark Pritchard

🐛 Markus Rathgeb
Markus Rathgeb

🐛 Marquis Wang
Marquis Wang

🐛 MartGit
MartGit

🐛 Martin Feldsztejn
Martin Feldsztejn

🐛 - Martin Lehmann
Martin Lehmann

🐛 + Martin Lehmann
Martin Lehmann

🐛 Martin Spamer
Martin Spamer

🐛 Martin Tarjányi
Martin Tarjányi

🐛 MatFl
MatFl

🐛 Mateusz Stefanski
Mateusz Stefanski

🐛 Mathieu Gouin
Mathieu Gouin

🐛 MatiasComercio
MatiasComercio

💻 🐛 - Matt Benson
Matt Benson

🐛 + Matt Benson
Matt Benson

🐛 Matt De Poorter
Matt De Poorter

🐛 Matt Hargett
Matt Hargett

💻 💵 Matt Harrah
Matt Harrah

🐛 Matt Nelson
Matt Nelson

🐛 Matthew Amos
Matthew Amos

🐛 Matthew Duggan
Matthew Duggan

🐛 - Matthew Hall
Matthew Hall

🐛 + Matthew Hall
Matthew Hall

🐛 Matías Fraga
Matías Fraga

💻 🐛 Maxime Robert
Maxime Robert

💻 🐛 MetaBF
MetaBF

🐛 Metin Dagcilar
Metin Dagcilar

🐛 Michael
Michael

🐛 Michael Bell
Michael Bell

🐛 - Michael Bernstein
Michael Bernstein

🐛 + Michael Bernstein
Michael Bernstein

🐛 Michael Clay
Michael Clay

🐛 Michael Dombrowski
Michael Dombrowski

🐛 Michael Hausegger
Michael Hausegger

🐛 Michael Hoefer
Michael Hoefer

🐛 Michael Kolesnikov
Michael Kolesnikov

🐛 Michael Möbius
Michael Möbius

🐛 - Michael N. Lipp
Michael N. Lipp

🐛 + Michael N. Lipp
Michael N. Lipp

🐛 Michael Pellegrini
Michael Pellegrini

🐛 Michal Kordas
Michal Kordas

🐛 Michał Borek
Michał Borek

🐛 Michał Kuliński
Michał Kuliński

🐛 Miguel Núñez Díaz-Montes
Miguel Núñez Díaz-Montes

🐛 Mihai Ionut
Mihai Ionut

🐛 - Mikhail Kuchma
Mikhail Kuchma

🐛 + Mikhail Kuchma
Mikhail Kuchma

🐛 Mirek Hankus
Mirek Hankus

🐛 Mitch Spano
Mitch Spano

🐛 Mladjan Gadzic
Mladjan Gadzic

🐛 MrAngry52
MrAngry52

🐛 Muminur Choudhury
Muminur Choudhury

🐛 Mykhailo Palahuta
Mykhailo Palahuta

💻 🐛 - Nagendra Kumar Singh
Nagendra Kumar Singh

🐛 + Nagendra Kumar Singh
Nagendra Kumar Singh

🐛 Nahuel Barrios
Nahuel Barrios

🐛 Nakul Sharma
Nakul Sharma

🐛 Nathan Braun
Nathan Braun

🐛 Nathan Reynolds
Nathan Reynolds

🐛 Nathan Reynolds
Nathan Reynolds

🐛 Nathanaël
Nathanaël

🐛 - Naveen
Naveen

💻 + Naveen
Naveen

💻 Nazdravi
Nazdravi

🐛 Neha-Dhonde
Neha-Dhonde

🐛 Nicholas Doyle
Nicholas Doyle

🐛 Nick Butcher
Nick Butcher

🐛 Nico Gallinal
Nico Gallinal

🐛 Nicola Dal Maso
Nicola Dal Maso

🐛 - Nicolas Filotto
Nicolas Filotto

💻 + Nicolas Filotto
Nicolas Filotto

💻 Nicolas Vervelle
Nicolas Vervelle

🐛 Nicolas Vuillamy
Nicolas Vuillamy

📖 Nikita Chursin
Nikita Chursin

🐛 Niklas Baudy
Niklas Baudy

🐛 Nikolas Havrikov
Nikolas Havrikov

🐛 Nilesh Virkar
Nilesh Virkar

🐛 - Nimit Patel
Nimit Patel

🐛 + Nimit Patel
Nimit Patel

🐛 Niranjan Harpale
Niranjan Harpale

🐛 Nirvik Patel
Nirvik Patel

💻 Noah Sussman
Noah Sussman

🐛 Noah0120
Noah0120

🐛 Noam Tamim
Noam Tamim

🐛 Noel Grandin
Noel Grandin

🐛 - Olaf Haalstra
Olaf Haalstra

🐛 + Olaf Haalstra
Olaf Haalstra

🐛 Oleg Andreych
Oleg Andreych

💻 🐛 Oleg Pavlenko
Oleg Pavlenko

🐛 Oleksii Dykov
Oleksii Dykov

💻 🐛 Oliver Eikemeier
Oliver Eikemeier

🐛 Oliver Siegmar
Oliver Siegmar

💵 Olivier Parent
Olivier Parent

💻 🐛 - Ollie Abbey
Ollie Abbey

💻 🐛 + Ollie Abbey
Ollie Abbey

💻 🐛 OverDrone
OverDrone

🐛 Ozan Gulle
Ozan Gulle

💻 🐛 PUNEET JAIN
PUNEET JAIN

🐛 Parbati Bose
Parbati Bose

🐛 Paul Berg
Paul Berg

🐛 Paul Guyot
Paul Guyot

💻 - Pavel Bludov
Pavel Bludov

🐛 + Pavel Bludov
Pavel Bludov

🐛 Pavel Mička
Pavel Mička

🐛 Pedro Nuno Santos
Pedro Nuno Santos

🐛 Pedro Rijo
Pedro Rijo

🐛 Pelisse Romain
Pelisse Romain

💻 📖 🐛 Per Abich
Per Abich

💻 Pete Davids
Pete Davids

🐛 - Peter Bruin
Peter Bruin

🐛 + Peter Bruin
Peter Bruin

🐛 Peter Chittum
Peter Chittum

💻 🐛 Peter Cudmore
Peter Cudmore

🐛 Peter Kasson
Peter Kasson

🐛 Peter Kofler
Peter Kofler

🐛 Peter Paul Bakker
Peter Paul Bakker

💻 Peter Rader
Peter Rader

🐛 - Pham Hai Trung
Pham Hai Trung

🐛 + Pham Hai Trung
Pham Hai Trung

🐛 Philip Graf
Philip Graf

💻 🐛 Philip Hachey
Philip Hachey

🐛 Philippe Ozil
Philippe Ozil

🐛 Phinehas Artemix
Phinehas Artemix

🐛 Phokham Nonava
Phokham Nonava

🐛 Pim van der Loos
Pim van der Loos

💻 ⚠️ - Piotr Szymański
Piotr Szymański

🐛 + Piotr Szymański
Piotr Szymański

🐛 Piotrek Żygieło
Piotrek Żygieło

💻 🐛 📖 Pranay Jaiswal
Pranay Jaiswal

🐛 Prasad Kamath
Prasad Kamath

🐛 Prasanna
Prasanna

🐛 Presh-AR
Presh-AR

🐛 Puneet1726
Puneet1726

🐛 - Rafael Cortês
Rafael Cortês

🐛 + RBRi
RBRi

🐛 + Rafael Cortês
Rafael Cortês

🐛 RaheemShaik999
RaheemShaik999

🐛 RajeshR
RajeshR

💻 🐛 Ramachandra Mohan
Ramachandra Mohan

🐛 Ramel0921
Ramel0921

🐛 Raquel Pau
Raquel Pau

🐛 - Ravikiran Janardhana
Ravikiran Janardhana

🐛 - Reda Benhemmouche
Reda Benhemmouche

🐛 + Ravikiran Janardhana
Ravikiran Janardhana

🐛 + Reda Benhemmouche
Reda Benhemmouche

🐛 Reinhard Schiedermeier
Reinhard Schiedermeier

🐛 Renato Oliveira
Renato Oliveira

💻 🐛 Rich DiCroce
Rich DiCroce

🐛 Richard Corfield
Richard Corfield

💻 Richard Corfield
Richard Corfield

🐛 💻 - Riot R1cket
Riot R1cket

🐛 - Rishabh Jain
Rishabh Jain

🐛 + Riot R1cket
Riot R1cket

🐛 + Rishabh Jain
Rishabh Jain

🐛 RishabhDeep Singh
RishabhDeep Singh

🐛 Rob Baillie
Rob Baillie

🐛 Robbie Martinus
Robbie Martinus

💻 🐛 Robert Henry
Robert Henry

🐛 Robert Mihaly
Robert Mihaly

🐛 - Robert Painsi
Robert Painsi

🐛 - Robert Russell
Robert Russell

🐛 + Robert Painsi
Robert Painsi

🐛 + Robert Russell
Robert Russell

🐛 Robert Sösemann
Robert Sösemann

💻 📖 📢 🐛 Robert Whitebit
Robert Whitebit

🐛 Robin Richtsfeld
Robin Richtsfeld

🐛 Robin Stocker
Robin Stocker

💻 🐛 Robin Wils
Robin Wils

🐛 - RochusOest
RochusOest

🐛 - Rodolfo Noviski
Rodolfo Noviski

🐛 + RochusOest
RochusOest

🐛 + Rodolfo Noviski
Rodolfo Noviski

🐛 Rodrigo Casara
Rodrigo Casara

🐛 Rodrigo Fernandes
Rodrigo Fernandes

🐛 Roman Salvador
Roman Salvador

💻 🐛 Ronald Blaschke
Ronald Blaschke

🐛 Róbert Papp
Róbert Papp

🐛 - Saikat Sengupta
Saikat Sengupta

🐛 - Saksham Handu
Saksham Handu

🐛 + Saikat Sengupta
Saikat Sengupta

🐛 + Saksham Handu
Saksham Handu

🐛 Saladoc
Saladoc

🐛 Salesforce Bob Lightning
Salesforce Bob Lightning

🐛 Sam Carlberg
Sam Carlberg

🐛 Sashko
Sashko

💻 Satoshi Kubo
Satoshi Kubo

🐛 - Scott Kennedy
Scott Kennedy

🐛 - Scott Wells
Scott Wells

🐛 💻 + Scott Kennedy
Scott Kennedy

🐛 + Scott Wells
Scott Wells

🐛 💻 Scrates1
Scrates1

🐛 💻 Scrsloota
Scrsloota

💻 Sebastian Bögl
Sebastian Bögl

🐛 Sebastian Davids
Sebastian Davids

🐛 Sebastian Schuberth
Sebastian Schuberth

🐛 - Sebastian Schwarz
Sebastian Schwarz

🐛 - Seren
Seren

🐛 💻 + Sebastian Schwarz
Sebastian Schwarz

🐛 + Seren
Seren

🐛 💻 Sergey Gorbaty
Sergey Gorbaty

🐛 Sergey Kozlov
Sergey Kozlov

🐛 Sergey Yanzin
Sergey Yanzin

💻 🐛 Seth Wilcox
Seth Wilcox

💻 Shai Bennathan
Shai Bennathan

🐛 💻 - Shubham
Shubham

💻 🐛 - Simon Abykov
Simon Abykov

💻 🐛 + Shubham
Shubham

💻 🐛 + Simon Abykov
Simon Abykov

💻 🐛 Simon Xiao
Simon Xiao

🐛 Srinivasan Venkatachalam
Srinivasan Venkatachalam

🐛 Stanislav Gromov
Stanislav Gromov

🐛 Stanislav Myachenkov
Stanislav Myachenkov

💻 Stefan Birkner
Stefan Birkner

🐛 - Stefan Bohn
Stefan Bohn

🐛 - Stefan Endrullis
Stefan Endrullis

🐛 + Stefan Bohn
Stefan Bohn

🐛 + Stefan Endrullis
Stefan Endrullis

🐛 Stefan Klöss-Schuster
Stefan Klöss-Schuster

🐛 Stefan Wolf
Stefan Wolf

🐛 Stephan H. Wissel
Stephan H. Wissel

🐛 Stephen
Stephen

🐛 Stephen Carter
Stephen Carter

🐛 - Stephen Friedrich
Stephen Friedrich

🐛 - Steve Babula
Steve Babula

💻 + Stephen Friedrich
Stephen Friedrich

🐛 + Steve Babula
Steve Babula

💻 Steven Stearns
Steven Stearns

🐛 💻 Stexxe
Stexxe

🐛 Stian Lågstad
Stian Lågstad

🐛 StuartClayton5
StuartClayton5

🐛 Supun Arunoda
Supun Arunoda

🐛 - Suren Abrahamyan
Suren Abrahamyan

🐛 - Suvashri
Suvashri

📖 + Suren Abrahamyan
Suren Abrahamyan

🐛 + Suvashri
Suvashri

📖 SwatiBGupta1110
SwatiBGupta1110

🐛 SyedThoufich
SyedThoufich

🐛 Szymon Sasin
Szymon Sasin

🐛 T-chuangxin
T-chuangxin

🐛 TERAI Atsuhiro
TERAI Atsuhiro

🐛 - TIOBE Software
TIOBE Software

💻 🐛 - Tarush Singh
Tarush Singh

💻 + TIOBE Software
TIOBE Software

💻 🐛 + Tarush Singh
Tarush Singh

💻 Taylor Smock
Taylor Smock

🐛 Techeira Damián
Techeira Damián

💻 🐛 Ted Husted
Ted Husted

🐛 TehBakker
TehBakker

🐛 The Gitter Badger
The Gitter Badger

🐛 - Theodoor
Theodoor

🐛 - Thiago Henrique Hüpner
Thiago Henrique Hüpner

🐛 + Theodoor
Theodoor

🐛 + Thiago Henrique Hüpner
Thiago Henrique Hüpner

🐛 Thibault Meyer
Thibault Meyer

🐛 Thomas Güttler
Thomas Güttler

🐛 Thomas Jones-Low
Thomas Jones-Low

🐛 Thomas Smith
Thomas Smith

💻 🐛 ThrawnCA
ThrawnCA

🐛 - Thu Vo
Thu Vo

🐛 - Thunderforge
Thunderforge

💻 🐛 + Thu Vo
Thu Vo

🐛 + Thunderforge
Thunderforge

💻 🐛 Tim van der Lippe
Tim van der Lippe

🐛 Tobias Weimer
Tobias Weimer

💻 🐛 Tom Copeland
Tom Copeland

🐛 💻 📖 Tom Daly
Tom Daly

🐛 Tomas
Tomas

🐛 - Tomer Figenblat
Tomer Figenblat

🐛 - Tomi De Lucca
Tomi De Lucca

💻 🐛 + Tomer Figenblat
Tomer Figenblat

🐛 + Tomi De Lucca
Tomi De Lucca

💻 🐛 Torsten Kleiber
Torsten Kleiber

🐛 TrackerSB
TrackerSB

🐛 Tyson Stewart
Tyson Stewart

🐛 Ullrich Hafner
Ullrich Hafner

🐛 Utku Cuhadaroglu
Utku Cuhadaroglu

💻 🐛 - Valentin Brandl
Valentin Brandl

🐛 - Valeria
Valeria

🐛 + Valentin Brandl
Valentin Brandl

🐛 + Valeria
Valeria

🐛 Valery Yatsynovich
Valery Yatsynovich

📖 Vasily Anisimov
Vasily Anisimov

🐛 Vibhor Goyal
Vibhor Goyal

🐛 Vickenty Fesunov
Vickenty Fesunov

🐛 Victor Noël
Victor Noël

🐛 - Vincent Galloy
Vincent Galloy

💻 - Vincent HUYNH
Vincent HUYNH

🐛 + Vincent Galloy
Vincent Galloy

💻 + Vincent HUYNH
Vincent HUYNH

🐛 Vincent Maurin
Vincent Maurin

🐛 Vincent Privat
Vincent Privat

🐛 Vishhwas
Vishhwas

🐛 Vishv_Android
Vishv_Android

🐛 Vitaly
Vitaly

🐛 - Vitaly Polonetsky
Vitaly Polonetsky

🐛 - Vojtech Polivka
Vojtech Polivka

🐛 + Vitaly Polonetsky
Vitaly Polonetsky

🐛 + Vojtech Polivka
Vojtech Polivka

🐛 Vsevolod Zholobov
Vsevolod Zholobov

🐛 Vyom Yadav
Vyom Yadav

💻 Wang Shidong
Wang Shidong

🐛 Waqas Ahmed
Waqas Ahmed

🐛 Wayne J. Earl
Wayne J. Earl

🐛 - Wchenghui
Wchenghui

🐛 - Wener
Wener

💻 + Wchenghui
Wchenghui

🐛 + Wener
Wener

💻 Will Winder
Will Winder

🐛 William Brockhus
William Brockhus

💻 🐛 Wilson Kurniawan
Wilson Kurniawan

🐛 Wim Deblauwe
Wim Deblauwe

🐛 Woongsik Choi
Woongsik Choi

🐛 - XenoAmess
XenoAmess

💻 🐛 - Yang
Yang

💻 + XenoAmess
XenoAmess

💻 🐛 + Yang
Yang

💻 YaroslavTER
YaroslavTER

🐛 Yasar Shaikh
Yasar Shaikh

💻 Young Chan
Young Chan

💻 🐛 YuJin Kim
YuJin Kim

🐛 Yuri Dolzhenko
Yuri Dolzhenko

🐛 - Yurii Dubinka
Yurii Dubinka

🐛 - Zoltan Farkas
Zoltan Farkas

🐛 + Yurii Dubinka
Yurii Dubinka

🐛 + Zoltan Farkas
Zoltan Farkas

🐛 Zustin
Zustin

🐛 aaronhurst-google
aaronhurst-google

🐛 💻 alexmodis
alexmodis

🐛 andreoss
andreoss

🐛 andrey81inmd
andrey81inmd

💻 🐛 - anicoara
anicoara

🐛 - arunprasathav
arunprasathav

🐛 + anicoara
anicoara

🐛 + arunprasathav
arunprasathav

🐛 asiercamara
asiercamara

🐛 astillich-igniti
astillich-igniti

💻 avesolovksyy
avesolovksyy

🐛 avishvat
avishvat

🐛 avivmu
avivmu

🐛 - axelbarfod1
axelbarfod1

🐛 - b-3-n
b-3-n

🐛 + axelbarfod1
axelbarfod1

🐛 + b-3-n
b-3-n

🐛 balbhadra9
balbhadra9

🐛 base23de
base23de

🐛 bergander
bergander

🐛 💻 berkam
berkam

💻 🐛 breizh31
breizh31

🐛 - caesarkim
caesarkim

🐛 - carolyujing
carolyujing

🐛 + caesarkim
caesarkim

🐛 + carolyujing
carolyujing

🐛 cbfiddle
cbfiddle

🐛 cesares-basilico
cesares-basilico

🐛 chrite
chrite

🐛 ciufudean
ciufudean

📖 cobratbq
cobratbq

🐛 - coladict
coladict

🐛 - cosmoJFH
cosmoJFH

🐛 + coladict
coladict

🐛 + cosmoJFH
cosmoJFH

🐛 cristalp
cristalp

🐛 crunsk
crunsk

🐛 cwholmes
cwholmes

🐛 cyberjj999
cyberjj999

🐛 cyw3
cyw3

🐛 📖 - d1ss0nanz
d1ss0nanz

🐛 - dague1
dague1

📖 + d1ss0nanz
d1ss0nanz

🐛 + dague1
dague1

📖 dalizi007
dalizi007

💻 danbrycefairsailcom
danbrycefairsailcom

🐛 dariansanity
dariansanity

🐛 darrenmiliband
darrenmiliband

🐛 davidburstrom
davidburstrom

🐛 - dbirkman-paloalto
dbirkman-paloalto

🐛 - deepak-patra
deepak-patra

🐛 + dbirkman-paloalto
dbirkman-paloalto

🐛 + deepak-patra
deepak-patra

🐛 dependabot[bot]
dependabot[bot]

💻 🐛 dinesh150
dinesh150

🐛 diziaq
diziaq

🐛 dreaminpast123
dreaminpast123

🐛 duanyanan
duanyanan

🐛 - dutt-sanjay
dutt-sanjay

🐛 - duursma
duursma

💻 + dutt-sanjay
dutt-sanjay

🐛 + duursma
duursma

💻 dylanleung
dylanleung

🐛 dzeigler
dzeigler

🐛 eant60
eant60

🐛 ekkirala
ekkirala

🐛 emersonmoura
emersonmoura

🐛 - emouty
emouty

💻 - eugenepugach
eugenepugach

🐛 + emouty
emouty

💻 + eugenepugach
eugenepugach

🐛 fairy
fairy

🐛 filiprafalowicz
filiprafalowicz

💻 flxbl-io
flxbl-io

💵 foxmason
foxmason

🐛 frankegabor
frankegabor

🐛 - frankl
frankl

🐛 - freafrea
freafrea

🐛 + frankl
frankl

🐛 + freafrea
freafrea

🐛 fsapatin
fsapatin

🐛 gearsethenry
gearsethenry

🐛 gracia19
gracia19

🐛 guo fei
guo fei

🐛 gurmsc5
gurmsc5

🐛 - gwilymatgearset
gwilymatgearset

💻 🐛 - haigsn
haigsn

🐛 + gwilymatgearset
gwilymatgearset

💻 🐛 + haigsn
haigsn

🐛 hemanshu070
hemanshu070

🐛 henrik242
henrik242

🐛 hongpuwu
hongpuwu

🐛 hvbtup
hvbtup

💻 🐛 igniti GmbH
igniti GmbH

🐛 - ilovezfs
ilovezfs

🐛 - itaigilo
itaigilo

🐛 + ilovezfs
ilovezfs

🐛 + itaigilo
itaigilo

🐛 jakivey32
jakivey32

🐛 jbennett2091
jbennett2091

🐛 jcamerin
jcamerin

🐛 jkeener1
jkeener1

🐛 jmetertea
jmetertea

🐛 - johnra2
johnra2

💻 - johnzhao9
johnzhao9

🐛 + johnra2
johnra2

💻 + johnzhao9
johnzhao9

🐛 josemanuelrolon
josemanuelrolon

💻 🐛 kabroxiko
kabroxiko

💻 🐛 karthikaiyasamy
karthikaiyasamy

📖 karwer
karwer

🐛 kaulonline
kaulonline

🐛 - kdaemonv
kdaemonv

🐛 - kdebski85
kdebski85

🐛 💻 + kdaemonv
kdaemonv

🐛 + kdebski85
kdebski85

🐛 💻 kenji21
kenji21

💻 🐛 kfranic
kfranic

🐛 khalidkh
khalidkh

🐛 koalalam
koalalam

🐛 krzyk
krzyk

🐛 - lasselindqvist
lasselindqvist

🐛 - lgemeinhardt
lgemeinhardt

🐛 + lasselindqvist
lasselindqvist

🐛 + lgemeinhardt
lgemeinhardt

🐛 lihuaib
lihuaib

🐛 liqingjun123
liqingjun123

🐛 lonelyma1021
lonelyma1021

🐛 lpeddy
lpeddy

🐛 lujiefsi
lujiefsi

💻 - lukelukes
lukelukes

💻 - lyriccoder
lyriccoder

🐛 + lukelukes
lukelukes

💻 + lyriccoder
lyriccoder

🐛 marcelmore
marcelmore

🐛 matchbox
matchbox

🐛 matthiaskraaz
matthiaskraaz

🐛 meandonlyme
meandonlyme

🐛 mikesive
mikesive

🐛 - milossesic
milossesic

🐛 - mluckam
mluckam

💻 🐛 + milossesic
milossesic

🐛 + mluckam
mluckam

💻 🐛 mohan-chinnappan-n
mohan-chinnappan-n

💻 mriddell95
mriddell95

🐛 mrlzh
mrlzh

🐛 msloan
msloan

🐛 mucharlaravalika
mucharlaravalika

🐛 - mvenneman
mvenneman

🐛 - nareshl119
nareshl119

🐛 + mvenneman
mvenneman

🐛 + nareshl119
nareshl119

🐛 nicolas-harraudeau-sonarsource
nicolas-harraudeau-sonarsource

🐛 noerremark
noerremark

🐛 novsirion
novsirion

🐛 nwcm
nwcm

📖 🐛 💻 oggboy
oggboy

🐛 - oinume
oinume

🐛 - orimarko
orimarko

💻 🐛 + oinume
oinume

🐛 + orimarko
orimarko

💻 🐛 pablogomez2197
pablogomez2197

🐛 pacvz
pacvz

💻 pallavi agarwal
pallavi agarwal

🐛 parksungrin
parksungrin

🐛 patpatpat123
patpatpat123

🐛 - patriksevallius
patriksevallius

🐛 - pbrajesh1
pbrajesh1

🐛 + patriksevallius
patriksevallius

🐛 + pbrajesh1
pbrajesh1

🐛 phoenix384
phoenix384

🐛 piotrszymanski-sc
piotrszymanski-sc

💻 plan3d
plan3d

🐛 poojasix
poojasix

🐛 prabhushrikant
prabhushrikant

🐛 - pujitha8783
pujitha8783

🐛 - r-r-a-j
r-r-a-j

🐛 + pujitha8783
pujitha8783

🐛 + r-r-a-j
r-r-a-j

🐛 raghujayjunk
raghujayjunk

🐛 rajeshveera
rajeshveera

🐛 rajeswarreddy88
rajeswarreddy88

🐛 recdevs
recdevs

🐛 reudismam
reudismam

💻 🐛 - rijkt
rijkt

🐛 - rillig-tk
rillig-tk

🐛 + rijkt
rijkt

🐛 + rillig-tk
rillig-tk

🐛 rmohan20
rmohan20

💻 🐛 rnveach
rnveach

🐛 rxmicro
rxmicro

🐛 ryan-gustafson
ryan-gustafson

💻 🐛 sabi0
sabi0

🐛 - scais
scais

🐛 - screamingfrog
screamingfrog

💵 + scais
scais

🐛 + schosin
schosin

🐛 + screamingfrog
screamingfrog

💵 sebbASF
sebbASF

🐛 sergeygorbaty
sergeygorbaty

💻 shilko2013
shilko2013

🐛 shiomiyan
shiomiyan

📖 + + simeonKondr
simeonKondr

🐛 snajberk
snajberk

🐛 sniperrifle2004
sniperrifle2004

🐛 - - snuyanzin
snuyanzin

🐛 💻 + soloturn
soloturn

🐛 soyodream
soyodream

🐛 sratz
sratz

🐛 + + stonio
stonio

🐛 sturton
sturton

💻 🐛 sudharmohan
sudharmohan

🐛 suruchidawar
suruchidawar

🐛 - - svenfinitiv
svenfinitiv

🐛 szymanp23
szymanp23

🐛 💻 tashiscool
tashiscool

🐛 + + test-git-hook
test-git-hook

🐛 testation21
testation21

💻 🐛 thanosa
thanosa

🐛 tiandiyixian
tiandiyixian

🐛 - - tobwoerk
tobwoerk

🐛 tprouvot
tprouvot

🐛 💻 trentchilders
trentchilders

🐛 + + triandicAnt
triandicAnt

🐛 trishul14
trishul14

🐛 tsui
tsui

🐛 wangzitom12306
wangzitom12306

🐛 - - winhkey
winhkey

🐛 witherspore
witherspore

🐛 wjljack
wjljack

🐛 + + wuchiuwong
wuchiuwong

🐛 xingsong
xingsong

🐛 xioayuge
xioayuge

🐛 xnYi9wRezm
xnYi9wRezm

💻 🐛 - - xuanuy
xuanuy

🐛 xyf0921
xyf0921

🐛 yalechen-cyw3
yalechen-cyw3

🐛 + + yasuharu-sato
yasuharu-sato

🐛 zenglian
zenglian

🐛 zgrzyt93
zgrzyt93

💻 🐛 zh3ng
zh3ng

🐛 - - zt_soft
zt_soft

🐛 ztt79
ztt79

🐛 zzzzfeng
zzzzfeng

🐛 + + Árpád Magosányi
Árpád Magosányi

🐛 任贵杰
任贵杰

🐛 茅延安
茅延安

💻 diff --git a/docs/pages/release_notes.md b/docs/pages/release_notes.md index ea6b83967f..af66a0f357 100644 --- a/docs/pages/release_notes.md +++ b/docs/pages/release_notes.md @@ -14,59 +14,33 @@ This is a {{ site.pmd.release_type }} release. ### 🚀 New and noteworthy -### 🌟 New and changed rules - -#### New Rules - -* The new Apex rule {%rule apex/performance/AvoidNonRestrictiveQueries %} finds SOQL and SOSL queries without a where - or limit statement. This can quickly cause governor limit exceptions. - -#### Changed rules -* {%rule apex/codestyle/ClassNamingConventions %}: Two new properties to configure different patterns - for inner classes and interfaces: `innerClassPattern` and `innerInterfacePattern`. - -#### Renamed rules -* {%rule ecmascript/errorprone/InaccurateNumericLiteral %} has been renamed from `InnaccurateNumericLiteral`. - The old rule name still works but is deprecated. - ### 🐛 Fixed Issues -* apex - * [#5094](https://github.com/pmd/pmd/issues/5094): \[apex] "No adapter exists for type" error message printed to stdout instead of stderr -* apex-bestpractices - * [#5095](https://github.com/pmd/pmd/issues/5095): \[apex] ApexUnitTestShouldNotUseSeeAllDataTrue false negative due to casing (regression in PMD 7) -* apex-codestyle - * [#4800](https://github.com/pmd/pmd/issues/4800): \[apex] ClassNamingConvention: Support naming convention for *inner* classes * apex-performance - * [#635](https://github.com/pmd/pmd/issues/635): \[apex] New Rule: Avoid soql/sosl queries without a where clause or limit statement + * [#5139](https://github.com/pmd/pmd/issues/5139): \[apex] OperationWithHighCostInLoop: false negative for triggers +* java + * [#5167](https://github.com/pmd/pmd/issues/5167): \[java] java.lang.IllegalArgumentException: \ cannot be a wildcard bound * java-bestpractices - * [#5117](https://github.com/pmd/pmd/issues/5117): \[java] UnusedPrivateMethod for methods annotated with jakarta.annotation.PostConstruct or PreDestroy -* java-errorprone - * [#1488](https://github.com/pmd/pmd/issues/1488): \[java] MissingStaticMethodInNonInstantiatableClass: False positive with Lombok Builder on Constructor -* javascript-errorprone - * [#2367](https://github.com/pmd/pmd/issues/2367): \[javascript] InnaccurateNumericLiteral is misspelled - * [#4716](https://github.com/pmd/pmd/issues/4716): \[javascript] InaccurateNumericLiteral with number 259200000 -* plsql - * [#5086](https://github.com/pmd/pmd/pull/5086): \[plsql] Fixed issue with missing optional table alias in MERGE usage - * [#5087](https://github.com/pmd/pmd/pull/5087): \[plsql] Add support for SQL_MACRO - * [#5088](https://github.com/pmd/pmd/pull/5088): \[plsql] Add support for 'DEFAULT' clause on the arguments of some oracle functions -* cli - * [#5120](https://github.com/pmd/pmd/issues/5120): \[cli] Can't start designer under Windows + * [#3602](https://github.com/pmd/pmd/issues/3602): \[java] GuardLogStatement: False positive when compile-time constant is created from external constants + * [#4731](https://github.com/pmd/pmd/issues/4731): \[java] GuardLogStatement: Documentation is unclear why getters are flagged + * [#5145](https://github.com/pmd/pmd/issues/5145): \[java] UnusedPrivateMethod: False positive with method calls inside lambda + * [#5151](https://github.com/pmd/pmd/issues/5151): \[java] GuardLogStatement: Should not need to guard parameterized log messages where the replacement arg is a constant from another class + * [#5152](https://github.com/pmd/pmd/issues/5152): \[java] GuardLogStatement: Should not need to guard parameterized log messages where the replacement arg is "this" + * [#5153](https://github.com/pmd/pmd/issues/5153): \[java] GuardLogStatement: Should not need to guard parameterized log messages where the replacement arg is an array element +* plsql-bestpractices + * [#5132](https://github.com/pmd/pmd/issues/5132): \[plsql] TomKytesDespair: XPathException for more complex exception handler ### 🚨 API Changes - -* javascript - * The old rule name `InnaccurateNumericLiteral` has been deprecated. Use the new name - {%rule ecmascript/errorprone/InaccurateNumericLiteral %} instead. +* pmd-jsp + * {%jdoc jsp::lang.jsp.ast.JspParserImpl %} is deprecated now. It should have been package-private + because this is an implementation class that should not be used directly. +* pmd-velocity + * {%jdoc velocity::lang.velocity.ast.VtlParserImpl %} is deprecated now. It should have been package-private + because this is an implementation class that should not be used directly. +* pmd-visualforce + * {%jdoc visualforce::lang.visualforce.ast.VfParserImpl %} is deprecated now. It should have been package-private + because this is an implementation class that should not be used directly. ### ✨ External Contributions -* [#5048](https://github.com/pmd/pmd/pull/5048): \[apex] Added Inner Classes to Apex Class Naming Conventions Rule - [Justin Stroud](https://github.com/justinstroudbah) (@justinstroudbah / @sgnl-labs) -* [#5086](https://github.com/pmd/pmd/pull/5086): \[plsql] Fixed issue with missing optional table alias in MERGE usage - [Arjen Duursma](https://github.com/duursma) (@duursma) -* [#5087](https://github.com/pmd/pmd/pull/5087): \[plsql] Add support for SQL_MACRO - [Arjen Duursma](https://github.com/duursma) (@duursma) -* [#5088](https://github.com/pmd/pmd/pull/5088): \[plsql] Add support for 'DEFAULT' clause on the arguments of some oracle functions - [Arjen Duursma](https://github.com/duursma) (@duursma) -* [#5107](https://github.com/pmd/pmd/pull/5107): \[doc] Update maven.md - Typo fixed for maven target - [karthikaiyasamy](https://github.com/karthikaiyasamy) (@karthikaiyasamy) -* [#5109](https://github.com/pmd/pmd/pull/5109): \[java] Exclude constructor with lombok.Builder for MissingStaticMethodInNonInstantiatableClass - [Krzysztof Debski](https://github.com/kdebski85) (@kdebski85) -* [#5118](https://github.com/pmd/pmd/pull/5118): \[java] FP for UnusedPrivateMethod with Jakarta @PostConstruct/PreDestroy annotations - [Krzysztof Debski](https://github.com/kdebski85) (@kdebski85) -* [#5121](https://github.com/pmd/pmd/pull/5121): \[plsql] Fixed issue with missing optional table alias in MERGE usage - [Arjen Duursma](https://github.com/duursma) (@duursma) {% endtocmaker %} diff --git a/docs/pages/release_notes_old.md b/docs/pages/release_notes_old.md index 7e5f11b546..fd4a63cdb8 100644 --- a/docs/pages/release_notes_old.md +++ b/docs/pages/release_notes_old.md @@ -5,6 +5,86 @@ permalink: pmd_release_notes_old.html Previous versions of PMD can be downloaded here: [Releases - pmd/pmd (GitHub)](https://github.com/pmd/pmd/releases) +## 26-July-2024 - 7.4.0 + +The PMD team is pleased to announce PMD 7.4.0. + +This is a minor release. + +### Table Of Contents + +* [🌟 New and changed rules](#new-and-changed-rules) + * [New Rules](#new-rules) + * [Changed rules](#changed-rules) + * [Renamed rules](#renamed-rules) +* [🐛 Fixed Issues](#fixed-issues) +* [🚨 API Changes](#api-changes) +* [✨ External Contributions](#external-contributions) +* [📈 Stats](#stats) + +### 🌟 New and changed rules + +#### New Rules +* The new Apex rule [`AvoidNonRestrictiveQueries`](https://docs.pmd-code.org/pmd-doc-7.4.0/pmd_rules_apex_performance.html#avoidnonrestrictivequeries) finds SOQL and SOSL queries without a where + or limit statement. This can quickly cause governor limit exceptions. + +#### Changed rules +* [`ClassNamingConventions`](https://docs.pmd-code.org/pmd-doc-7.4.0/pmd_rules_apex_codestyle.html#classnamingconventions) (Apex Codestyle): Two new properties to configure different patterns + for inner classes and interfaces: `innerClassPattern` and `innerInterfacePattern`. + +#### Renamed rules +* [`InaccurateNumericLiteral`](https://docs.pmd-code.org/pmd-doc-7.4.0/pmd_rules_ecmascript_errorprone.html#inaccuratenumericliteral) (JavaScript Error Prone) has been renamed from `InnaccurateNumericLiteral`. + The old rule name still works but is deprecated. + +### 🐛 Fixed Issues +* apex + * [#5094](https://github.com/pmd/pmd/issues/5094): \[apex] "No adapter exists for type" error message printed to stdout instead of stderr +* apex-bestpractices + * [#5095](https://github.com/pmd/pmd/issues/5095): \[apex] ApexUnitTestShouldNotUseSeeAllDataTrue false negative due to casing (regression in PMD 7) +* apex-codestyle + * [#4800](https://github.com/pmd/pmd/issues/4800): \[apex] ClassNamingConvention: Support naming convention for *inner* classes +* apex-performance + * [#635](https://github.com/pmd/pmd/issues/635): \[apex] New Rule: Avoid soql/sosl queries without a where clause or limit statement +* java-bestpractices + * [#5106](https://github.com/pmd/pmd/issues/5106): \[java] AccessorClassGeneration: Node was null for default constructor + * [#5110](https://github.com/pmd/pmd/issues/5110): \[java] UnusedPrivateMethod for method referenced by lombok.Builder.ObtainVia + * [#5117](https://github.com/pmd/pmd/issues/5117): \[java] UnusedPrivateMethod for methods annotated with jakarta.annotation.PostConstruct or PreDestroy +* java-errorprone + * [#1488](https://github.com/pmd/pmd/issues/1488): \[java] MissingStaticMethodInNonInstantiatableClass: False positive with Lombok Builder on Constructor +* javascript-errorprone + * [#2367](https://github.com/pmd/pmd/issues/2367): \[javascript] InnaccurateNumericLiteral is misspelled + * [#4716](https://github.com/pmd/pmd/issues/4716): \[javascript] InaccurateNumericLiteral with number 259200000 +* plsql + * [#5086](https://github.com/pmd/pmd/pull/5086): \[plsql] Fixed issue with missing optional table alias in MERGE usage + * [#5087](https://github.com/pmd/pmd/pull/5087): \[plsql] Add support for SQL_MACRO + * [#5088](https://github.com/pmd/pmd/pull/5088): \[plsql] Add support for 'DEFAULT' clause on the arguments of some oracle functions + * [#5133](https://github.com/pmd/pmd/issues/5133): \[plsql] AssertionError: Root of the tree should implement RootNode for a PL/SQL type declaration +* cli + * [#5120](https://github.com/pmd/pmd/issues/5120): \[cli] Can't start designer under Windows +* core + * [#5091](https://github.com/pmd/pmd/issues/5091): \[core] PMD CPD v7.3.0 gives deprecation warning for skipLexicalErrors even when not used + +### 🚨 API Changes +* javascript + * The old rule name `InnaccurateNumericLiteral` has been deprecated. Use the new name + [`InaccurateNumericLiteral`](https://docs.pmd-code.org/pmd-doc-7.4.0/pmd_rules_ecmascript_errorprone.html#inaccuratenumericliteral) instead. + +### ✨ External Contributions +* [#5048](https://github.com/pmd/pmd/pull/5048): \[apex] Added Inner Classes to Apex Class Naming Conventions Rule - [Justin Stroud](https://github.com/justinstroudbah) (@justinstroudbah / @sgnl-labs) +* [#5086](https://github.com/pmd/pmd/pull/5086): \[plsql] Fixed issue with missing optional table alias in MERGE usage - [Arjen Duursma](https://github.com/duursma) (@duursma) +* [#5087](https://github.com/pmd/pmd/pull/5087): \[plsql] Add support for SQL_MACRO - [Arjen Duursma](https://github.com/duursma) (@duursma) +* [#5088](https://github.com/pmd/pmd/pull/5088): \[plsql] Add support for 'DEFAULT' clause on the arguments of some oracle functions - [Arjen Duursma](https://github.com/duursma) (@duursma) +* [#5107](https://github.com/pmd/pmd/pull/5107): \[doc] Update maven.md - Typo fixed for maven target - [karthikaiyasamy](https://github.com/karthikaiyasamy) (@karthikaiyasamy) +* [#5109](https://github.com/pmd/pmd/pull/5109): \[java] Exclude constructor with lombok.Builder for MissingStaticMethodInNonInstantiatableClass - [Krzysztof Debski](https://github.com/kdebski85) (@kdebski85) +* [#5111](https://github.com/pmd/pmd/pull/5111): \[java] Fix UnusedPrivateMethod for @lombok.Builder.ObtainVia - [Krzysztof Debski](https://github.com/kdebski85) (@kdebski85) +* [#5118](https://github.com/pmd/pmd/pull/5118): \[java] FP for UnusedPrivateMethod with Jakarta @PostConstruct/PreDestroy annotations - [Krzysztof Debski](https://github.com/kdebski85) (@kdebski85) +* [#5121](https://github.com/pmd/pmd/pull/5121): \[plsql] Fixed issue with missing optional table alias in MERGE usage - [Arjen Duursma](https://github.com/duursma) (@duursma) + +### 📈 Stats +* 81 commits +* 32 closed tickets & PRs +* Days since last release: 27 + ## 28-June-2024 - 7.3.0 diff --git a/pmd-ant/pom.xml b/pmd-ant/pom.xml index 2d24dc491c..14273b0ad9 100644 --- a/pmd-ant/pom.xml +++ b/pmd-ant/pom.xml @@ -7,7 +7,7 @@ pmd net.sourceforge.pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT 4.0.0 diff --git a/pmd-ant/src/main/java/net/sourceforge/pmd/ant/CPDTask.java b/pmd-ant/src/main/java/net/sourceforge/pmd/ant/CPDTask.java index c812893930..86558b6048 100644 --- a/pmd-ant/src/main/java/net/sourceforge/pmd/ant/CPDTask.java +++ b/pmd-ant/src/main/java/net/sourceforge/pmd/ant/CPDTask.java @@ -111,9 +111,6 @@ public class CPDTask extends Task { + "Use failOnError=\"false\" to not fail the build.", Project.MSG_WARN); } - // implicitly enable skipLexicalErrors, so that we can fail the build at the end. A report is created in any case. - config.setSkipLexicalErrors(true); - config.setIgnoreAnnotations(ignoreAnnotations); config.setIgnoreLiterals(ignoreLiterals); config.setIgnoreIdentifiers(ignoreIdentifiers); diff --git a/pmd-apex/pom.xml b/pmd-apex/pom.xml index a89fbebb49..b0a349a4d7 100644 --- a/pmd-apex/pom.xml +++ b/pmd-apex/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethod.java b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethod.java index 69367768be..3f44ef5430 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethod.java +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ASTMethod.java @@ -10,6 +10,7 @@ import java.util.stream.Collectors; import net.sourceforge.pmd.lang.document.TextDocument; import net.sourceforge.pmd.lang.document.TextPos2d; import net.sourceforge.pmd.lang.document.TextRegion; +import net.sourceforge.pmd.lang.rule.xpath.NoAttribute; import com.google.summit.ast.SourceLocation; import com.google.summit.ast.declaration.MethodDeclaration; @@ -27,6 +28,12 @@ public final class ASTMethod extends AbstractApexNode implements ApexQualifiable */ private static final String STATIC_INIT_ID = ""; + /** + * Internal name used by the synthetic trigger method. + * @see #isTriggerBlock() + */ + private static final String TRIGGER_INVOKE_ID = ""; + // Store the details instead of wrapping a com.google.summit.ast.Node. // This is to allow synthetic ASTMethod nodes. // An example is the trigger `invoke` method. @@ -150,4 +157,14 @@ public final class ASTMethod extends AbstractApexNode implements ApexQualifiable public int getArity() { return parameterTypes.size(); } + + /** + * Checks whether this method is the synthetic trigger method. + * @return true if this method is the synthetic trigger method + * @since 7.5.0 + */ + @NoAttribute + public boolean isTriggerBlock() { + return TRIGGER_INVOKE_ID.equals(internalName); + } } diff --git a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.kt b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.kt index a41745ce93..20dd5621aa 100644 --- a/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.kt +++ b/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeBuilder.kt @@ -229,7 +229,7 @@ class ApexTreeBuilder(private val task: ParserTask, private val proc: ApexLangua // 2. Add the expected ASTModifier child node buildModifiers(emptyList()).also { it.setParent(invokeMethod) } // 3. Elide the body CompoundStatement->ASTBlockStatement - node.body.forEach { buildChildren(it, parent = invokeMethod as AbstractApexNode) } + node.body.forEach { buildAndSetParent(it, parent = invokeMethod as AbstractApexNode) } } else { buildChildren(node, parent = this, exclude = { it in node.modifiers }) } @@ -737,18 +737,18 @@ class ApexTreeBuilder(private val task: ParserTask, private val proc: ApexLangua findDescendants(root, nodeType = ASTProperty::class).forEach { node -> generateFields(node) } // Sort resulting nodes - findDescendants(root, nodeType = ASTUserClass::class).forEach { node -> + findDescendants(root, nodeType = BaseApexClass::class).forEach { node -> sortUserClassChildren(node) } } /** - * Sort children of [ASTUserClass] in historical order. + * Sort children of [BaseApexClass] (ASTUserClass, ASTUserTrigger, ...) in historical order. * * This sorts [ASTField] nodes immediately after [ASTModifierNode] nodes at * the start of the ordered children. */ - private fun sortUserClassChildren(node: ASTUserClass) { + private fun sortUserClassChildren(node: BaseApexClass<*>) { val children = ArrayList(node.children().toList()) children.sortBy{ when (it) { @@ -772,7 +772,13 @@ class ApexTreeBuilder(private val task: ParserTask, private val proc: ApexLangua /** Generates [ASTField] nodes for the [ASTFieldDeclarationStatements]. */ private fun generateFields(node: ASTFieldDeclarationStatements) { - val parent = node.parent as BaseApexClass<*> + val parent = if (node.parent is BaseApexClass<*>) { + node.parent as BaseApexClass<*> + } else if (node.parent is ASTMethod && (node.parent as ASTMethod).isTriggerBlock) { + node.parent.parent as BaseApexClass<*> + } else { + throw IllegalStateException("Unexpected apex tree - field declaration $node cannot appear hear") + } node.node.declarations .map { decl -> diff --git a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeDumpTest.java b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeDumpTest.java index 0bba0ee4f8..997d76819e 100644 --- a/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeDumpTest.java +++ b/pmd-apex/src/test/java/net/sourceforge/pmd/lang/apex/ast/ApexTreeDumpTest.java @@ -65,4 +65,9 @@ class ApexTreeDumpTest extends BaseTreeDumpTest { void switchStatements() { doTest("SwitchStatements"); } + + @Test + void trigger() { + doTest("AccountTrigger"); + } } diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/AccountTrigger.cls b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/AccountTrigger.cls new file mode 100644 index 0000000000..39b81e2263 --- /dev/null +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/AccountTrigger.cls @@ -0,0 +1,9 @@ +// see https://github.com/pmd/pmd/issues/5139 +trigger AccountTrigger on Account (before insert, before update) { + integer i = 0; + for (i = 0; i <15; i++) { + SObjectType token = Schema.getGlobalDescribe().get('Account'); + } + integer anotherField = 2; + System.debug('test'); +} diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/AccountTrigger.txt b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/AccountTrigger.txt new file mode 100644 index 0000000000..b5999de53f --- /dev/null +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/ast/AccountTrigger.txt @@ -0,0 +1,50 @@ ++- ApexFile[@DefiningType = "AccountTrigger", @RealLoc = true] + +- UserTrigger[@DefiningType = "AccountTrigger", @Image = "AccountTrigger", @Nested = false, @RealLoc = true, @SimpleName = "AccountTrigger", @TargetName = "Account", @Usages = (TriggerUsage.BEFORE_INSERT, TriggerUsage.BEFORE_UPDATE)] + +- ModifierNode[@Abstract = false, @DefiningType = "AccountTrigger", @DeprecatedTestMethod = false, @Final = false, @Global = false, @InheritedSharing = false, @Modifiers = 0, @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @Virtual = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + +- Field[@DefiningType = "AccountTrigger", @Image = "i", @Name = "i", @RealLoc = true, @Type = "Integer", @Value = "0"] + | +- ModifierNode[@Abstract = false, @DefiningType = "AccountTrigger", @DeprecatedTestMethod = false, @Final = false, @Global = false, @InheritedSharing = false, @Modifiers = 0, @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @Virtual = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + +- Field[@DefiningType = "AccountTrigger", @Image = "anotherField", @Name = "anotherField", @RealLoc = true, @Type = "Integer", @Value = "2"] + | +- ModifierNode[@Abstract = false, @DefiningType = "AccountTrigger", @DeprecatedTestMethod = false, @Final = false, @Global = false, @InheritedSharing = false, @Modifiers = 0, @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @Virtual = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + +- Method[@Arity = 0, @CanonicalName = "invoke", @Constructor = false, @DefiningType = "AccountTrigger", @Image = "invoke", @RealLoc = false, @ReturnType = "void", @StaticInitializer = false] + +- ModifierNode[@Abstract = false, @DefiningType = "AccountTrigger", @DeprecatedTestMethod = false, @Final = false, @Global = false, @InheritedSharing = false, @Modifiers = 0, @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @Virtual = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + +- FieldDeclarationStatements[@DefiningType = "AccountTrigger", @RealLoc = true, @TypeArguments = (), @TypeName = "Integer"] + | +- ModifierNode[@Abstract = false, @DefiningType = "AccountTrigger", @DeprecatedTestMethod = false, @Final = false, @Global = false, @InheritedSharing = false, @Modifiers = 0, @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @Virtual = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | +- FieldDeclaration[@DefiningType = "AccountTrigger", @Image = "i", @Name = "i", @RealLoc = true] + | +- LiteralExpression[@Boolean = false, @Decimal = false, @DefiningType = "AccountTrigger", @Double = false, @Image = "0", @Integer = true, @LiteralType = LiteralType.INTEGER, @Long = false, @Name = null, @Null = false, @RealLoc = true, @String = false] + | +- VariableExpression[@DefiningType = "AccountTrigger", @Image = "i", @RealLoc = true] + | +- EmptyReferenceExpression[@DefiningType = null, @RealLoc = false] + +- ForLoopStatement[@DefiningType = "AccountTrigger", @RealLoc = true] + | +- StandardCondition[@DefiningType = "AccountTrigger", @RealLoc = true] + | | +- BooleanExpression[@DefiningType = "AccountTrigger", @Op = BooleanOperator.LESS_THAN, @RealLoc = true] + | | +- VariableExpression[@DefiningType = "AccountTrigger", @Image = "i", @RealLoc = true] + | | | +- EmptyReferenceExpression[@DefiningType = null, @RealLoc = false] + | | +- LiteralExpression[@Boolean = false, @Decimal = false, @DefiningType = "AccountTrigger", @Double = false, @Image = "15", @Integer = true, @LiteralType = LiteralType.INTEGER, @Long = false, @Name = null, @Null = false, @RealLoc = true, @String = false] + | +- Expression[@DefiningType = "AccountTrigger", @RealLoc = true] + | | +- AssignmentExpression[@DefiningType = "AccountTrigger", @Op = AssignmentOperator.EQUALS, @RealLoc = true] + | | +- VariableExpression[@DefiningType = "AccountTrigger", @Image = "i", @RealLoc = true] + | | | +- EmptyReferenceExpression[@DefiningType = null, @RealLoc = false] + | | +- LiteralExpression[@Boolean = false, @Decimal = false, @DefiningType = "AccountTrigger", @Double = false, @Image = "0", @Integer = true, @LiteralType = LiteralType.INTEGER, @Long = false, @Name = null, @Null = false, @RealLoc = true, @String = false] + | +- BlockStatement[@CurlyBrace = true, @DefiningType = "AccountTrigger", @RealLoc = true] + | | +- VariableDeclarationStatements[@DefiningType = "AccountTrigger", @RealLoc = true] + | | +- ModifierNode[@Abstract = false, @DefiningType = "AccountTrigger", @DeprecatedTestMethod = false, @Final = false, @Global = false, @InheritedSharing = false, @Modifiers = 0, @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @Virtual = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | | +- VariableDeclaration[@DefiningType = "AccountTrigger", @Image = "token", @RealLoc = true, @Type = "SObjectType"] + | | +- MethodCallExpression[@DefiningType = "AccountTrigger", @FullMethodName = "get", @InputParametersSize = 1, @MethodName = "get", @RealLoc = true] + | | | +- ReferenceExpression[@DefiningType = "AccountTrigger", @Image = "", @RealLoc = false, @ReferenceType = ReferenceType.METHOD, @SObjectType = false, @SafeNav = false] + | | | | +- MethodCallExpression[@DefiningType = "AccountTrigger", @FullMethodName = "Schema.getGlobalDescribe", @InputParametersSize = 0, @MethodName = "getGlobalDescribe", @RealLoc = true] + | | | | +- ReferenceExpression[@DefiningType = "AccountTrigger", @Image = "Schema", @RealLoc = true, @ReferenceType = ReferenceType.METHOD, @SObjectType = false, @SafeNav = false] + | | | +- LiteralExpression[@Boolean = false, @Decimal = false, @DefiningType = "AccountTrigger", @Double = false, @Image = "Account", @Integer = false, @LiteralType = LiteralType.STRING, @Long = false, @Name = null, @Null = false, @RealLoc = true, @String = true] + | | +- VariableExpression[@DefiningType = "AccountTrigger", @Image = "token", @RealLoc = true] + | | +- EmptyReferenceExpression[@DefiningType = null, @RealLoc = false] + | +- PostfixExpression[@DefiningType = "AccountTrigger", @Op = PostfixOperator.INCREMENT, @RealLoc = true] + | +- VariableExpression[@DefiningType = "AccountTrigger", @Image = "i", @RealLoc = true] + | +- EmptyReferenceExpression[@DefiningType = null, @RealLoc = false] + +- FieldDeclarationStatements[@DefiningType = "AccountTrigger", @RealLoc = true, @TypeArguments = (), @TypeName = "Integer"] + | +- ModifierNode[@Abstract = false, @DefiningType = "AccountTrigger", @DeprecatedTestMethod = false, @Final = false, @Global = false, @InheritedSharing = false, @Modifiers = 0, @Override = false, @Private = false, @Protected = false, @Public = false, @RealLoc = false, @Static = false, @Test = false, @TestOrTestSetup = false, @Transient = false, @Virtual = false, @WebService = false, @WithSharing = false, @WithoutSharing = false] + | +- FieldDeclaration[@DefiningType = "AccountTrigger", @Image = "anotherField", @Name = "anotherField", @RealLoc = true] + | +- LiteralExpression[@Boolean = false, @Decimal = false, @DefiningType = "AccountTrigger", @Double = false, @Image = "2", @Integer = true, @LiteralType = LiteralType.INTEGER, @Long = false, @Name = null, @Null = false, @RealLoc = true, @String = false] + | +- VariableExpression[@DefiningType = "AccountTrigger", @Image = "anotherField", @RealLoc = true] + | +- EmptyReferenceExpression[@DefiningType = null, @RealLoc = false] + +- ExpressionStatement[@DefiningType = "AccountTrigger", @RealLoc = true] + +- MethodCallExpression[@DefiningType = "AccountTrigger", @FullMethodName = "System.debug", @InputParametersSize = 1, @MethodName = "debug", @RealLoc = true] + +- ReferenceExpression[@DefiningType = "AccountTrigger", @Image = "System", @RealLoc = true, @ReferenceType = ReferenceType.METHOD, @SObjectType = false, @SafeNav = false] + +- LiteralExpression[@Boolean = false, @Decimal = false, @DefiningType = "AccountTrigger", @Double = false, @Image = "test", @Integer = false, @LiteralType = LiteralType.STRING, @Long = false, @Name = null, @Null = false, @RealLoc = true, @String = true] diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/CyclomaticComplexity.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/CyclomaticComplexity.xml index fd282bac4a..8fcbd0b6d7 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/CyclomaticComplexity.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/design/xml/CyclomaticComplexity.xml @@ -263,7 +263,7 @@ trigger CaseAssignLevel on CaseAssignLevel__c (after delete, after insert, after 1 1 - The trigger 'CaseAssignLevel' has a cyclomatic complexity of 9. + The trigger 'CaseAssignLevel' has a cyclomatic complexity of 12. diff --git a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/performance/xml/OperationWithHighCostInLoop.xml b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/performance/xml/OperationWithHighCostInLoop.xml index 15a05db1a0..e03e0ea17b 100644 --- a/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/performance/xml/OperationWithHighCostInLoop.xml +++ b/pmd-apex/src/test/resources/net/sourceforge/pmd/lang/apex/rule/performance/xml/OperationWithHighCostInLoop.xml @@ -135,4 +135,18 @@ public class Foo { ]]> + + + #5139 [apex] OperationWithHighCostInLoop not firing in triggers + 1 + 4 + + diff --git a/pmd-cli/pom.xml b/pmd-cli/pom.xml index 415b1a72eb..0d766285df 100644 --- a/pmd-cli/pom.xml +++ b/pmd-cli/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/CpdCommand.java b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/CpdCommand.java index fe8a835774..f823aa3ab9 100644 --- a/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/CpdCommand.java +++ b/pmd-cli/src/main/java/net/sourceforge/pmd/cli/commands/internal/CpdCommand.java @@ -124,7 +124,6 @@ public class CpdCommand extends AbstractAnalysisPmdSubcommand configuration.setRendererName(rendererName); configuration.setSkipBlocksPattern(skipBlocksPattern); configuration.setSkipDuplicates(skipDuplicates); - configuration.setSkipLexicalErrors(skipLexicalErrors); configuration.setSourceEncoding(encoding.getEncoding()); configuration.setInputUri(uri); @@ -133,9 +132,6 @@ public class CpdCommand extends AbstractAnalysisPmdSubcommand configuration.setFailOnError(false); } - // implicitly enable skipLexicalErrors, so that we can fail the build at the end. A report is created in any case. - configuration.setSkipLexicalErrors(true); - return configuration; } diff --git a/pmd-cli/src/test/java/net/sourceforge/pmd/cli/BaseCliTest.java b/pmd-cli/src/test/java/net/sourceforge/pmd/cli/BaseCliTest.java index 33123c3ddd..c19230a94f 100644 --- a/pmd-cli/src/test/java/net/sourceforge/pmd/cli/BaseCliTest.java +++ b/pmd-cli/src/test/java/net/sourceforge/pmd/cli/BaseCliTest.java @@ -5,7 +5,7 @@ package net.sourceforge.pmd.cli; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.emptyString; import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.ByteArrayOutputStream; @@ -146,7 +146,7 @@ abstract class BaseCliTest { } public void checkNoErrorOutput() { - checkStdErr(equalTo("")); + checkStdErr(emptyString()); } public void checkStdOut(Matcher matcher) { diff --git a/pmd-cli/src/test/java/net/sourceforge/pmd/cli/CpdCliTest.java b/pmd-cli/src/test/java/net/sourceforge/pmd/cli/CpdCliTest.java index 3ff31a255d..acbdc1db6f 100644 --- a/pmd-cli/src/test/java/net/sourceforge/pmd/cli/CpdCliTest.java +++ b/pmd-cli/src/test/java/net/sourceforge/pmd/cli/CpdCliTest.java @@ -239,10 +239,24 @@ class CpdCliTest extends BaseCliTest { "--skip-lexical-errors") .verify(r -> { r.checkStdErr(containsPattern("Skipping file: Lexical error in file .*?BadFile\\.java")); + r.checkStdErr(containsString("--skip-lexical-errors is deprecated. Use --no-fail-on-error instead.")); r.checkStdOut(containsString("Found a 5 line (13 tokens) duplication")); }); } + /** + * @see [core] PMD CPD v7.3.0 gives deprecation warning for skipLexicalErrors even when not used #5091 + * @throws Exception + */ + @Test + void noWarningsWithoutSkipLexicalErrors() throws Exception { + runCliSuccessfully("--minimum-tokens", "340", "--language", "java", "--dir", SRC_DIR, "--format", "text") + .verify(r -> { + r.checkNoErrorOutput(); + r.checkStdOut(emptyString()); + }); + } + @Test void testExitCodeWithLexicalErrors() throws Exception { runCli(RECOVERED_ERRORS_OR_VIOLATIONS, diff --git a/pmd-coco/pom.xml b/pmd-coco/pom.xml index 4dafe93c48..00e5b5ade6 100644 --- a/pmd-coco/pom.xml +++ b/pmd-coco/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-core/pom.xml b/pmd-core/pom.xml index a0067a6174..24549e9d1b 100644 --- a/pmd-core/pom.xml +++ b/pmd-core/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDConfiguration.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDConfiguration.java index 3826781b86..8c63ae3252 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDConfiguration.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CPDConfiguration.java @@ -67,7 +67,8 @@ public class CPDConfiguration extends AbstractConfiguration { private boolean ignoreIdentifierAndLiteralSequences = false; @Deprecated - private boolean skipLexicalErrors = false; + // Note: The default value was false until up to 7.3.0 and is true since 7.4.0 + private boolean skipLexicalErrors = true; private boolean noSkipBlocks = false; diff --git a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CpdAnalysis.java b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CpdAnalysis.java index 1df33f5274..6117998e4a 100644 --- a/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CpdAnalysis.java +++ b/pmd-core/src/main/java/net/sourceforge/pmd/cpd/CpdAnalysis.java @@ -153,10 +153,6 @@ public final class CpdAnalysis implements AutoCloseable { @SuppressWarnings("PMD.CloseResource") public void performAnalysis(Consumer consumer) { - if (configuration.isSkipLexicalErrors()) { - LOGGER.warn("The option skipLexicalErrors is deprecated. Use failOnError instead."); - } - try (SourceManager sourceManager = new SourceManager(files.getCollectedFiles())) { Map tokenizers = sourceManager.getTextFiles().stream() diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CpdAnalysisTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CpdAnalysisTest.java index e5140e9abe..0238b76fa3 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CpdAnalysisTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/cpd/CpdAnalysisTest.java @@ -223,7 +223,6 @@ class CpdAnalysisTest { PmdReporter reporter = mock(PmdReporter.class); config.setReporter(reporter); - config.setSkipLexicalErrors(true); // must be true, otherwise CPD is aborted with first processing error try (CpdAnalysis cpd = CpdAnalysis.create(config)) { assertTrue(cpd.files().addSourceFile(FileId.fromPathLikeString("foo.dummy"), DummyLanguageModule.CPD_THROW_LEX_EXCEPTION)); assertTrue(cpd.files().addSourceFile(FileId.fromPathLikeString("foo2.dummy"), DummyLanguageModule.CPD_THROW_MALFORMED_SOURCE_EXCEPTION)); @@ -252,7 +251,6 @@ class CpdAnalysisTest { PmdReporter reporter = mock(PmdReporter.class); config.setReporter(reporter); - config.setSkipLexicalErrors(true); try (CpdAnalysis cpd = CpdAnalysis.create(config)) { assertTrue(cpd.files().addSourceFile(FileId.fromPathLikeString("foo.dummy"), DummyLanguageModule.CPD_THROW_LEX_EXCEPTION)); assertTrue(cpd.files().addSourceFile(FileId.fromPathLikeString("foo2.dummy"), DummyLanguageModule.CPD_THROW_MALFORMED_SOURCE_EXCEPTION)); diff --git a/pmd-cpp/pom.xml b/pmd-cpp/pom.xml index 921d7515cd..5afe7e04ae 100644 --- a/pmd-cpp/pom.xml +++ b/pmd-cpp/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-cs/pom.xml b/pmd-cs/pom.xml index 3641191746..6b60027a0e 100644 --- a/pmd-cs/pom.xml +++ b/pmd-cs/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-dart/pom.xml b/pmd-dart/pom.xml index e5e54e3987..dafa7b143d 100644 --- a/pmd-dart/pom.xml +++ b/pmd-dart/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-dist/pom.xml b/pmd-dist/pom.xml index 4ca2949d3a..ba93ada88a 100644 --- a/pmd-dist/pom.xml +++ b/pmd-dist/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-doc/pom.xml b/pmd-doc/pom.xml index 7aa5ad9343..0f03c26b67 100644 --- a/pmd-doc/pom.xml +++ b/pmd-doc/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-fortran/pom.xml b/pmd-fortran/pom.xml index 128c8c857a..3153a89603 100644 --- a/pmd-fortran/pom.xml +++ b/pmd-fortran/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-gherkin/pom.xml b/pmd-gherkin/pom.xml index b054c8552f..1b5be295da 100644 --- a/pmd-gherkin/pom.xml +++ b/pmd-gherkin/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-go/pom.xml b/pmd-go/pom.xml index 4bdaa9b8e3..a0ca5d0678 100644 --- a/pmd-go/pom.xml +++ b/pmd-go/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-groovy/pom.xml b/pmd-groovy/pom.xml index 40fad655a7..dbb69619a2 100644 --- a/pmd-groovy/pom.xml +++ b/pmd-groovy/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-html/pom.xml b/pmd-html/pom.xml index 06ca2d4c23..6acd925a10 100644 --- a/pmd-html/pom.xml +++ b/pmd-html/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-java/pom.xml b/pmd-java/pom.xml index 354802ca58..4d8d7f994a 100644 --- a/pmd-java/pom.xml +++ b/pmd-java/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java index b3981ea8ad..d69c0e3ac5 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTAnnotation.java @@ -81,8 +81,29 @@ public final class ASTAnnotation extends AbstractJavaTypeNode implements ASTMemb */ public NodeStream getFlatValue(String attrName) { return NodeStream.of(getAttribute(attrName)) - .flatMap(v -> v instanceof ASTMemberValueArrayInitializer ? v.children(ASTMemberValue.class) - : NodeStream.of(v)); + .flatMap(ASTAnnotation::flatValue); + } + + /** + * Return expression values for all attributes. + * This may flatten an array initializer. For example, for the attribute + * named "value": + *
{@code
+     * - @SuppressWarnings -> returns empty node stream
+     * - @SuppressWarning("fallthrough") -> returns ["fallthrough"]
+     * - @SuppressWarning(value={"fallthrough"}) -> returns ["fallthrough"]
+     * - @SuppressWarning({"fallthrough", "rawtypes"}) -> returns ["fallthrough", "rawtypes"]
+     * }
+ */ + public NodeStream getFlatValues() { + return getMembers().map(ASTMemberValuePair::getValue) + .flatMap(ASTAnnotation::flatValue); + } + + private static NodeStream flatValue(ASTMemberValue value) { + return value instanceof ASTMemberValueArrayInitializer + ? value.children(ASTMemberValue.class) + : NodeStream.of(value); } /** diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ConstantFolder.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ConstantFolder.java index eb3c7f1770..5079ee9223 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ConstantFolder.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ConstantFolder.java @@ -9,7 +9,6 @@ import org.apache.commons.lang3.tuple.Pair; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; -import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr; import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol; import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol; import net.sourceforge.pmd.lang.java.types.JPrimitiveType; @@ -42,18 +41,27 @@ final strictfp class ConstantFolder extends JavaVisitorBase { @Override public Object visit(ASTVariableAccess node, Void data) { - return fetchConstFieldReference(node); + JVariableSymbol symbol = node.getReferencedSym(); + if (symbol == null || !symbol.isFinal()) { + return null; + } + @Nullable + ASTVariableId declaratorId = symbol.tryGetNode(); + if (declaratorId != null) { + ASTExpression initializer = declaratorId.getInitializer(); + if (initializer != null) { + return initializer.getConstValue(); + } + } + + return null; } @Override public Object visit(ASTFieldAccess node, Void data) { - return fetchConstFieldReference(node); - } - - private @Nullable Object fetchConstFieldReference(ASTNamedReferenceExpr node) { - JVariableSymbol symbol = node.getReferencedSym(); - if (symbol instanceof JFieldSymbol) { - return ((JFieldSymbol) symbol).getConstValue(); + JFieldSymbol symbol = node.getReferencedSym(); + if (symbol != null) { + return symbol.getConstValue(); } return null; } diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AccessorMethodGenerationRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AccessorMethodGenerationRule.java index 33e8e96c41..7c09f22e37 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AccessorMethodGenerationRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/AccessorMethodGenerationRule.java @@ -17,6 +17,7 @@ import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule; import net.sourceforge.pmd.lang.java.symbols.JAccessibleElementSymbol; import net.sourceforge.pmd.lang.java.symbols.JClassSymbol; +import net.sourceforge.pmd.lang.java.symbols.JConstructorSymbol; import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol; import net.sourceforge.pmd.lang.java.symbols.JMethodSymbol; import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol; @@ -74,6 +75,10 @@ public class AccessorMethodGenerationRule extends AbstractJavaRulechainRule { refExpr.getEnclosingType().getSymbol())) { JavaNode node = sym.tryGetNode(); + if (node == null && JConstructorSymbol.CTOR_NAME.equals(sym.getSimpleName())) { + // might be a default constructor, implicitly defined and not explicitly in the compilation unit + node = sym.getEnclosingClass().tryGetNode(); + } assert node != null : "Node should be in the same compilation unit"; if (reportedNodes.add(node)) { ruleContext.addViolation(node, stripPackageName(refExpr.getEnclosingType().getSymbol())); diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/GuardLogStatementRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/GuardLogStatementRule.java index 1301e2a403..9069831804 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/GuardLogStatementRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/GuardLogStatementRule.java @@ -14,21 +14,21 @@ import java.util.Map; import org.checkerframework.checker.nullness.qual.Nullable; -import net.sourceforge.pmd.lang.java.ast.ASTArgumentList; +import net.sourceforge.pmd.lang.java.ast.ASTArrayAccess; import net.sourceforge.pmd.lang.java.ast.ASTAssignableExpr.ASTNamedReferenceExpr; import net.sourceforge.pmd.lang.java.ast.ASTExpression; import net.sourceforge.pmd.lang.java.ast.ASTExpressionStatement; +import net.sourceforge.pmd.lang.java.ast.ASTFieldAccess; import net.sourceforge.pmd.lang.java.ast.ASTIfStatement; -import net.sourceforge.pmd.lang.java.ast.ASTInfixExpression; import net.sourceforge.pmd.lang.java.ast.ASTLambdaExpression; +import net.sourceforge.pmd.lang.java.ast.ASTLiteral; import net.sourceforge.pmd.lang.java.ast.ASTMethodCall; import net.sourceforge.pmd.lang.java.ast.ASTMethodReference; -import net.sourceforge.pmd.lang.java.ast.ASTStringLiteral; +import net.sourceforge.pmd.lang.java.ast.ASTThisExpression; +import net.sourceforge.pmd.lang.java.ast.ASTTypeExpression; import net.sourceforge.pmd.lang.java.ast.ASTVariableAccess; -import net.sourceforge.pmd.lang.java.ast.ASTVariableId; -import net.sourceforge.pmd.lang.java.ast.BinaryOp; +import net.sourceforge.pmd.lang.java.ast.QualifiableExpression; import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule; -import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol; import net.sourceforge.pmd.lang.java.types.TypeTestUtil; import net.sourceforge.pmd.properties.PropertyDescriptor; import net.sourceforge.pmd.reporting.RuleContext; @@ -113,62 +113,23 @@ public class GuardLogStatementRule extends AbstractJavaRulechainRule { return null; } + @SuppressWarnings("PMD.SimplifyBooleanReturns") private boolean needsGuard(ASTMethodCall node) { - if (node.getArguments().size() == 0) { + if (node.getArguments().isEmpty()) { return false; } - ASTArgumentList argumentList = node.getArguments(); - for (ASTExpression child : argumentList) { - if (child.descendantsOrSelf() - .filterIs(ASTInfixExpression.class) - .filter(n -> n.getOperator() == BinaryOp.ADD) - .nonEmpty() - && TypeTestUtil.isA(String.class, child)) { - // only consider the first String argument - which is the log message - and return here - return !isConstantStringExpression(child); - } - } - - return true; - } - - private boolean isConstantStringExpression(ASTExpression expr) { - if (expr == null) { - return false; - } - - if (expr instanceof ASTStringLiteral) { + // get the message expression + // it must either be a direct access (var / param access, lambda, method ref, etc.) + // or a compile-time constant string to not require a guard + int messageArg = getMessageArgIndex(node); + ASTExpression messageExpr = node.getArguments().get(messageArg); + if (!isDirectAccess(messageExpr) && !messageExpr.isCompileTimeConstant()) { return true; } - if (expr instanceof ASTVariableAccess) { - ASTVariableAccess var = (ASTVariableAccess) expr; - if (var.isCompileTimeConstant()) { - return true; - } - JVariableSymbol symbol = var.getReferencedSym(); - if (symbol == null) { - return false; - } - if (!var.getReferencedSym().isFinal()) { - return false; - } - @Nullable - ASTVariableId declaratorId = symbol.tryGetNode(); - if (declaratorId != null) { - return isConstantStringExpression(declaratorId.getInitializer()); - } - } - - if (expr instanceof ASTInfixExpression) { - ASTInfixExpression infix = (ASTInfixExpression) expr; - if (isConstantStringExpression(infix.getLeftOperand()) - && isConstantStringExpression(infix.getRightOperand())) { - return true; - } - } - return false; + // if any additional params are not a direct access, we need a guard + return !areAdditionalParamsDirectAccess(node, messageArg + 1); } private boolean hasGuard(ASTMethodCall node, String logLevel) { @@ -210,20 +171,22 @@ public class GuardLogStatementRule extends AbstractJavaRulechainRule { private @Nullable String getLogLevelName(ASTMethodCall methodCall) { String methodName = methodCall.getMethodName(); if (!JAVA_UTIL_LOG_METHOD.equals(methodName)) { - if (isUnguardedAccessOk(methodCall, 0)) { - return null; - } return methodName; // probably logger.warn(...) } - // else it's java.util.logging, eg - // LOGGER.log(Level.FINE, "m") - if (isUnguardedAccessOk(methodCall, 1)) { - return null; - } return getJutilLogLevelInFirstArg(methodCall); } + private int getMessageArgIndex(ASTMethodCall methodCall) { + String methodName = methodCall.getMethodName(); + if (JAVA_UTIL_LOG_METHOD.equals(methodName)) { + // LOGGER.log(Level.FINE, "m") + return 1; + } + + return 0; + } + private @Nullable String getJutilLogLevelInFirstArg(ASTMethodCall methodCall) { ASTExpression firstArg = methodCall.getArguments().toStream().get(0); if (TypeTestUtil.isA("java.util.logging.Level", firstArg) && firstArg instanceof ASTNamedReferenceExpr) { @@ -232,12 +195,36 @@ public class GuardLogStatementRule extends AbstractJavaRulechainRule { return null; } - private boolean isUnguardedAccessOk(ASTMethodCall call, int messageArgIndex) { + private boolean areAdditionalParamsDirectAccess(ASTMethodCall call, int messageArgIndex) { // return true if the statement has limited overhead even if unguarded, // so that we can ignore it return call.getArguments().toStream() .drop(messageArgIndex) // remove the level argument if needed - .all(it -> it instanceof ASTStringLiteral || it instanceof ASTLambdaExpression || it instanceof ASTVariableAccess || it instanceof ASTMethodReference); + .all(GuardLogStatementRule::isDirectAccess); + } + + private static boolean isDirectAccess(ASTExpression it) { + final boolean isPermittedType = it instanceof ASTLiteral || it instanceof ASTLambdaExpression + || it instanceof ASTVariableAccess || it instanceof ASTThisExpression + || it instanceof ASTMethodReference || it instanceof ASTFieldAccess + || it instanceof ASTArrayAccess; + + if (!isPermittedType) { + return false; + } + + if (it instanceof QualifiableExpression) { + final ASTExpression qualifier = ((QualifiableExpression) it).getQualifier(); + + // for array access, we also care about the index expression + if (it instanceof ASTArrayAccess && !isDirectAccess(((ASTArrayAccess) it).getIndexExpression())) { + return false; + } + + return qualifier == null || qualifier instanceof ASTTypeExpression || isDirectAccess(qualifier); + } + + return true; } private void extractProperties() { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java index 85c45bb3f4..f26108d9dc 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/rule/bestpractices/UnusedPrivateMethodRule.java @@ -14,13 +14,15 @@ import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; +import org.apache.commons.lang3.StringUtils; + import net.sourceforge.pmd.lang.ast.NodeStream; import net.sourceforge.pmd.lang.java.ast.ASTAnnotation; import net.sourceforge.pmd.lang.java.ast.ASTCompilationUnit; +import net.sourceforge.pmd.lang.java.ast.ASTMemberValue; import net.sourceforge.pmd.lang.java.ast.ASTMethodCall; import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration; import net.sourceforge.pmd.lang.java.ast.ASTMethodReference; -import net.sourceforge.pmd.lang.java.ast.ASTModifierList; import net.sourceforge.pmd.lang.java.ast.JavaNode; import net.sourceforge.pmd.lang.java.ast.MethodUsage; import net.sourceforge.pmd.lang.java.ast.ModifierOwner.Visibility; @@ -51,23 +53,33 @@ public class UnusedPrivateMethodRule extends AbstractIgnoredAnnotationRule { @Override public Object visit(ASTCompilationUnit file, Object param) { // We do three traversals: - // - one to find methods referenced by Junit5 MethodSource annotations + // - one to find methods: + // --- referenced by any attribute of any annotation + // --- with name same as a method annotated with Junit5 MethodSource if the annotation value is empty // - one to find the "interesting methods", ie those that may be violations // - another to find the possible usages. We only try to resolve // method calls/method refs that may refer to a method in the // first set, ie, not every call in the file. - - Set methodsUsedByAnnotations = file.descendants(ASTMethodDeclaration.class) - .crossFindBoundaries() - .children(ASTModifierList.class) - .children(ASTAnnotation.class) - .filter(t -> TypeTestUtil.isA("org.junit.jupiter.params.provider.MethodSource", t)) - .toStream() - // Get the referenced method names… if none, use the test method name instead - .flatMap(a -> a.getFlatValue("value").isEmpty() - ? Stream.of(a.ancestors(ASTMethodDeclaration.class).first().getName()) - : a.getFlatValue("value").toStream().map(mv -> (String) mv.getConstValue())) - .collect(Collectors.toSet()); + Set methodsUsedByAnnotations = + file.descendants(ASTAnnotation.class) + .crossFindBoundaries() + .toStream() + .flatMap(a -> Stream.concat( + a.getFlatValues().toStream() + .map(ASTMemberValue::getConstValue) + .filter(String.class::isInstance) + .map(String.class::cast) + .filter(StringUtils::isNotEmpty), + NodeStream.of(a) + .filter(it -> TypeTestUtil.isA("org.junit.jupiter.params.provider.MethodSource", it) + && it.getFlatValue("value").isEmpty()) + .ancestors(ASTMethodDeclaration.class) + .take(1) + .toStream() + .map(ASTMethodDeclaration::getName) + ) + ) + .collect(Collectors.toSet()); Map> consideredNames = file.descendants(ASTMethodDeclaration.class) diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java index 051ea91c02..a6ac882819 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/TypeOps.java @@ -1170,6 +1170,13 @@ public final class TypeOps { } else if (!upwards) { // If Ai is a type that mentions a restricted type variable, then Ai' is undefined. return NO_DOWN_PROJECTION; + } else if (u instanceof JWildcardType) { + // The rest of this function, below, treats u as the bound of a wildcard, + // but if u is already a wildcard (and therefore ai was a wildcard), we + // are already done. + newTargs.add(u); + change = true; + continue; } change = true; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/BaseInvocMirror.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/BaseInvocMirror.java index d497c0801b..12fabedf2c 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/BaseInvocMirror.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/BaseInvocMirror.java @@ -31,9 +31,17 @@ abstract class BaseInvocMirror extends BasePolyMirror< private MethodCtDecl ctDecl; private List args; + /** + * Some method invocations may appear to be poly expressions, + * but they have no context type (for instance because they + * are in the initializer of a local with inferred type). + * These must be treated as standalone expressions. + */ + protected final boolean mayBePoly; - BaseInvocMirror(JavaExprMirrors mirrors, T call, @Nullable ExprMirror parent, MirrorMaker subexprMaker) { + BaseInvocMirror(JavaExprMirrors mirrors, T call, boolean mustBeStandalone, @Nullable ExprMirror parent, MirrorMaker subexprMaker) { super(mirrors, call, parent, subexprMaker); + mayBePoly = !mustBeStandalone; } @Override @@ -61,8 +69,13 @@ abstract class BaseInvocMirror extends BasePolyMirror< protected MethodCtDecl getStandaloneCtdecl() { MethodCallSite site = factory.infer.newCallSite(this, null); - // this is cached for later anyway - return factory.infer.getCompileTimeDecl(site); + if (mayBePoly) { + // this is cached for later anyway + return factory.infer.getCompileTimeDecl(site); + } else { + factory.infer.inferInvocationRecursively(site); + return site.getExpr().getCtDecl(); + } } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/ConditionalMirrorImpl.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/ConditionalMirrorImpl.java index f0f5217fb6..2c236580e3 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/ConditionalMirrorImpl.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/ConditionalMirrorImpl.java @@ -19,7 +19,6 @@ import net.sourceforge.pmd.lang.java.types.JTypeMirror; import net.sourceforge.pmd.lang.java.types.TypeConversion; import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror; import net.sourceforge.pmd.lang.java.types.internal.infer.ExprMirror.BranchingMirror; -import net.sourceforge.pmd.lang.java.types.internal.infer.MethodCallSite; import net.sourceforge.pmd.lang.java.types.internal.infer.ast.JavaExprMirrors.MirrorMaker; class ConditionalMirrorImpl extends BasePolyMirror implements BranchingMirror { @@ -135,23 +134,7 @@ class ConditionalMirrorImpl extends BasePolyMirror imp } if (e instanceof ASTMethodCall) { - /* - A method invocation expression (§15.12) for which the chosen most specific method (§15.12.2.5) has return type boolean or Boolean. - Note that, for a generic method, this is the type before instantiating the method's type arguments. - - */ - JTypeMirror current = InternalApiBridge.getTypeMirrorInternal(e); - if (current != null) { - // don't redo the compile-time decl resolution - // The CTDecl is cached on the mirror, not the node - return current; - } - - MethodCallSite site = factory.infer.newCallSite((InvocationMirror) mirror, null); - - return factory.infer.getCompileTimeDecl(site) - .getMethodType() - .getReturnType(); + return mirror.getStandaloneType(); } return null; diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/CtorInvocMirror.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/CtorInvocMirror.java index 5aea093a0e..bb9167a335 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/CtorInvocMirror.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/CtorInvocMirror.java @@ -29,8 +29,9 @@ import net.sourceforge.pmd.util.IteratorUtil; class CtorInvocMirror extends BaseInvocMirror implements CtorInvocationMirror { - CtorInvocMirror(JavaExprMirrors mirrors, ASTConstructorCall call, ExprMirror parent, MirrorMaker subexprMaker) { - super(mirrors, call, parent, subexprMaker); + CtorInvocMirror(JavaExprMirrors mirrors, ASTConstructorCall call, + boolean mustBeStandalone, ExprMirror parent, MirrorMaker subexprMaker) { + super(mirrors, call, mustBeStandalone, parent, subexprMaker); } @Override @@ -47,6 +48,8 @@ class CtorInvocMirror extends BaseInvocMirror implements Cto @Override public JTypeMirror getStandaloneType() { if (isDiamond()) { + // todo if the expr must be standalone then we + // should infer this from the provided arguments. return null; } return getNewType(); @@ -130,7 +133,7 @@ class CtorInvocMirror extends BaseInvocMirror implements Cto EnumCtorInvocMirror(JavaExprMirrors mirrors, ASTEnumConstant call, ExprMirror parent, MirrorMaker subexprMaker) { - super(mirrors, call, parent, subexprMaker); + super(mirrors, call, false, parent, subexprMaker); } @Override @@ -163,7 +166,7 @@ class CtorInvocMirror extends BaseInvocMirror implements Cto ExplicitCtorInvocMirror(JavaExprMirrors mirrors, ASTExplicitConstructorInvocation call, ExprMirror parent, MirrorMaker subexprMaker) { - super(mirrors, call, parent, subexprMaker); + super(mirrors, call, false, parent, subexprMaker); } @Override diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/JavaExprMirrors.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/JavaExprMirrors.java index eb8e57b3e1..8287afec35 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/JavaExprMirrors.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/JavaExprMirrors.java @@ -68,7 +68,7 @@ public final class JavaExprMirrors { ExprMirror makeSubexprDefault(ASTExpression e, @Nullable ExprMirror parent, MirrorMaker subexprMaker) { if (e instanceof InvocationNode) { - return getInvocationMirror((InvocationNode) e, parent, subexprMaker); + return getInvocationMirror((InvocationNode) e, parent, false, subexprMaker); } else if (e instanceof ASTLambdaExpression || e instanceof ASTMethodReference) { return getFunctionalMirror(e, parent, subexprMaker); } else if (e instanceof ASTConditionalExpression) { @@ -81,11 +81,13 @@ public final class JavaExprMirrors { } } - ExprMirror getBranchMirrorSubexpression(ASTExpression e, boolean isStandalone, @NonNull BranchingMirror parent, MirrorMaker subexprMaker) { + ExprMirror getBranchMirrorSubexpression(ASTExpression e, boolean mustBeStandalone, @NonNull BranchingMirror parent, MirrorMaker subexprMaker) { if (e instanceof ASTConditionalExpression) { - return new ConditionalMirrorImpl(this, (ASTConditionalExpression) e, isStandalone, parent, subexprMaker); + return new ConditionalMirrorImpl(this, (ASTConditionalExpression) e, mustBeStandalone, parent, subexprMaker); } else if (e instanceof ASTSwitchExpression) { - return new SwitchMirror(this, (ASTSwitchExpression) e, isStandalone, parent, subexprMaker); + return new SwitchMirror(this, (ASTSwitchExpression) e, mustBeStandalone, parent, subexprMaker); + } else if (e instanceof InvocationNode) { + return getInvocationMirror((InvocationNode) e, parent, mustBeStandalone, subexprMaker); } else { return subexprMaker.createMirrorForSubexpression(e, parent, subexprMaker); } @@ -96,14 +98,15 @@ public final class JavaExprMirrors { } public InvocationMirror getInvocationMirror(InvocationNode e, MirrorMaker subexprMaker) { - return getInvocationMirror(e, null, subexprMaker); + return getInvocationMirror(e, null, false, subexprMaker); } - private InvocationMirror getInvocationMirror(InvocationNode e, @Nullable ExprMirror parent, MirrorMaker subexprMaker) { + private InvocationMirror getInvocationMirror(InvocationNode e, @Nullable ExprMirror parent, + boolean mustBeStandalone, MirrorMaker subexprMaker) { if (e instanceof ASTMethodCall) { - return new MethodInvocMirror(this, (ASTMethodCall) e, parent, subexprMaker); + return new MethodInvocMirror(this, (ASTMethodCall) e, mustBeStandalone, parent, subexprMaker); } else if (e instanceof ASTConstructorCall) { - return new CtorInvocMirror(this, (ASTConstructorCall) e, parent, subexprMaker); + return new CtorInvocMirror(this, (ASTConstructorCall) e, mustBeStandalone, parent, subexprMaker); } else if (e instanceof ASTExplicitConstructorInvocation) { return new CtorInvocMirror.ExplicitCtorInvocMirror(this, (ASTExplicitConstructorInvocation) e, parent, subexprMaker); } else if (e instanceof ASTEnumConstant) { diff --git a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/MethodInvocMirror.java b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/MethodInvocMirror.java index fd66d5116f..3404147596 100644 --- a/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/MethodInvocMirror.java +++ b/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/types/internal/infer/ast/MethodInvocMirror.java @@ -26,14 +26,16 @@ import net.sourceforge.pmd.lang.java.types.internal.infer.ast.JavaExprMirrors.Mi class MethodInvocMirror extends BaseInvocMirror { - MethodInvocMirror(JavaExprMirrors mirrors, ASTMethodCall call, @Nullable ExprMirror parent, MirrorMaker subexprMaker) { - super(mirrors, call, parent, subexprMaker); + MethodInvocMirror(JavaExprMirrors mirrors, ASTMethodCall call, + boolean isStandalone, + @Nullable ExprMirror parent, MirrorMaker subexprMaker) { + super(mirrors, call, isStandalone, parent, subexprMaker); } @Override public @Nullable JTypeMirror getStandaloneType() { JMethodSig ctdecl = getStandaloneCtdecl().getMethodType(); - return isContextDependent(ctdecl) ? null : ctdecl.getReturnType(); + return mayBePoly && isContextDependent(ctdecl) ? null : ctdecl.getReturnType(); } private static boolean isContextDependent(JMethodSig m) { diff --git a/pmd-java/src/main/resources/category/java/bestpractices.xml b/pmd-java/src/main/resources/category/java/bestpractices.xml index a8a3169254..4bf4a370bf 100644 --- a/pmd-java/src/main/resources/category/java/bestpractices.xml +++ b/pmd-java/src/main/resources/category/java/bestpractices.xml @@ -602,8 +602,8 @@ for (int i = 0, j = 0; i < 10; i++, j += 2) { class="net.sourceforge.pmd.lang.java.rule.bestpractices.GuardLogStatementRule" externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#guardlogstatement"> -Whenever using a log level, one should check if the loglevel is actually enabled, or -otherwise skip the associate String creation and manipulation. +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. @@ -611,7 +611,7 @@ with lambdas. The available alternatives depend on the actual logging framework. 2 calculateExpensiveLoggingText()); + +// … alternatively use method references +log.debug("log something expensive: {}", this::calculateExpensiveLoggingText); ]]> diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/GuardLogStatementTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/GuardLogStatementTest.java index 5a1979c853..a4f1432202 100644 --- a/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/GuardLogStatementTest.java +++ b/pmd-java/src/test/java/net/sourceforge/pmd/lang/java/rule/bestpractices/GuardLogStatementTest.java @@ -8,4 +8,6 @@ import net.sourceforge.pmd.test.PmdRuleTst; class GuardLogStatementTest extends PmdRuleTst { // no additional unit tests + + public static final String TERM_MSG = "A terminating log message."; } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TypeOpsTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TypeOpsTest.kt index 55a1b19a82..421a778c4a 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TypeOpsTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/TypeOpsTest.kt @@ -95,7 +95,44 @@ class TypeOpsTest : FunSpec({ } + test("#5167 problem in projection") { + val (acu, spy) = javaParser.parseWithTypeInferenceSpy( + """ +import java.lang.annotation.Annotation; +interface Bar { + Baz getBaz(); +} + +interface Predicate { + boolean check(T t); +} +interface Stream{ + T findSome(); +} +interface Baz{ + Stream> filterMethods(Predicate p); +} + +class Foo { + + private static Bar foo( + Bar type, Class annotation, boolean required) { + var method = type.getBaz().filterMethods(m -> true).findSome(); + return method; + } +} + """.trimIndent() + ) + + val (barT) = acu.declaredTypeSignatures() + val methodId = acu.varId("method") + + spy.shouldBeOk { + methodId shouldHaveType barT[`?`] + } + } } } + }) diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/BranchingExprsTests.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/BranchingExprsTests.kt index 51eb5943df..756df350fb 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/BranchingExprsTests.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/BranchingExprsTests.kt @@ -279,7 +279,7 @@ class Scratch { val (ternary1, ternary2) = acu.descendants(ASTConditionalExpression::class.java).toList() spy.shouldBeOk { - ternary1 shouldHaveType gen.t_Collection[captureMatcher(`?`)] // java.util.Collection + ternary1 shouldHaveType gen.t_Collection[ts.OBJECT] // java.util.Collection ternary2 shouldHaveType gen.`t_Collection{String}` // java.util.Collection } } diff --git a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/LocalVarInferenceTest.kt b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/LocalVarInferenceTest.kt index 268b973d29..6b1e1c327d 100644 --- a/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/LocalVarInferenceTest.kt +++ b/pmd-java/src/test/kotlin/net/sourceforge/pmd/lang/java/types/internal/infer/LocalVarInferenceTest.kt @@ -4,10 +4,11 @@ package net.sourceforge.pmd.lang.java.types.internal.infer -import net.sourceforge.pmd.lang.test.ast.shouldMatchN import net.sourceforge.pmd.lang.java.ast.ProcessorTestSpec import net.sourceforge.pmd.lang.java.ast.variableAccess import net.sourceforge.pmd.lang.java.types.* +import net.sourceforge.pmd.lang.test.ast.component6 +import net.sourceforge.pmd.lang.test.ast.shouldMatchN /** * @@ -101,4 +102,39 @@ class Scratch { acu.varId("k") shouldHaveType Runnable::class.decl } } + parserTest("Local var with conditional and 2 poly expressions") { + val (acu, spy) = parser.parseWithTypeInferenceSpy( + """ +interface Collector {} +interface Stream { + R collect(Collector collector); +} +interface List {} +interface Function { R apply(T t); } +public class Scratch { + + static Collector>> groupingByNullable(Function key){} + static { + var lookup = System.currentTimeMillis() > 100L // permission based + ? Dao.source1().collect(groupingByNullable(Data::parent)) // DAO call #1 + : Dao.source2().collect(groupingByNullable(Data::parent)); // DAO call #2 + } + + interface Data { + Integer parent(); + } + static class Dao { + static Stream source1(){} + static Stream source2(){} + } +} + """.trimIndent() + ) + + spy.shouldBeOk { + val (_, _, list, _, _, data) = acu.declaredTypeSignatures() + // not the anon type + acu.varId("lookup") shouldHaveType list[list[data]] + } + } }) diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AccessorClassGeneration.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AccessorClassGeneration.xml index 9980924616..f5a610e8f0 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AccessorClassGeneration.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/AccessorClassGeneration.xml @@ -7,6 +7,7 @@ inner class has private constructor 1 + 3 java 10 + + + #5106 [java] AccessorClassGeneration: Node was null for default constructor + 1 + 2 + + java 10 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/GuardLogStatement.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/GuardLogStatement.xml index d1e8ad23ae..4c8970291d 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/GuardLogStatement.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/GuardLogStatement.xml @@ -578,6 +578,196 @@ public class GuardLogStatementTest { final Logger logger = LogManager.getLogger(GuardLogStatementTest.class); logger.info("Some info: {}", GuardLogStatementTest::foo); } +} + ]]> + + + + GuardLogStatement should flag method reference from method / constructor calls + 2 + + + + + #5151 Field accesses do not require guards + 0 + + + + + #5151 Field accesses on method call returned values require guards + 2 + + + + + #5152 "this" do not require guards + 0 + + + + + #5153 array access to constants do not require guards + 0 + + + + + array access with computed keys require guards + 1 + + + + + #5153 array access to method returned values require guards + 1 + + + + + #3602 False positive when compile-time constant is created from external constants + 0 + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml index 4dbcae2e97..e81d963fcb 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/bestpractices/xml/UnusedPrivateMethod.xml @@ -27,6 +27,18 @@ public class Foo { ]]> + + simple unused annotated private method + 1 + + + anonymous inner class calls private method 0 @@ -2100,4 +2112,26 @@ class FooTest{ } ]]> + + UnusedPrivateMethod for Lombok ObtainVia #5110 + 0 + foo; + + private List fooProvider() { + return Collections.emptyList(); + } +} + ]]> + diff --git a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientStringBuffering.xml b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientStringBuffering.xml index faaebfad2b..c6cd35430c 100644 --- a/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientStringBuffering.xml +++ b/pmd-java/src/test/resources/net/sourceforge/pmd/lang/java/rule/performance/xml/InefficientStringBuffering.xml @@ -393,8 +393,7 @@ public class Foo { No violation: Avoid concat in append method invocations - 3 - 26,39,45 + 0 diff --git a/pmd-javascript/pom.xml b/pmd-javascript/pom.xml index 5fea2f05ec..ffa785c486 100644 --- a/pmd-javascript/pom.xml +++ b/pmd-javascript/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-jsp/etc/grammar/Jsp.jjt b/pmd-jsp/etc/grammar/Jsp.jjt index 1f74b3dcf7..c87cb23aae 100644 --- a/pmd-jsp/etc/grammar/Jsp.jjt +++ b/pmd-jsp/etc/grammar/Jsp.jjt @@ -33,7 +33,10 @@ package net.sourceforge.pmd.lang.jsp.ast; /** * JSP Parser for PMD. * @author Pieter, Application Engineers NV/SA, http://www.ae.be + * @deprecated Since 7.5.0. JspParserImpl should have been package private because this is an implementation class + * that should not be used directly. */ +@Deprecated public class JspParserImpl { diff --git a/pmd-jsp/pom.xml b/pmd-jsp/pom.xml index a4452b174e..9535354b81 100644 --- a/pmd-jsp/pom.xml +++ b/pmd-jsp/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-julia/pom.xml b/pmd-julia/pom.xml index 72bb59e026..0b26645c0b 100644 --- a/pmd-julia/pom.xml +++ b/pmd-julia/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-kotlin/pom.xml b/pmd-kotlin/pom.xml index 0a7cf896ef..7ca3e8f3ed 100644 --- a/pmd-kotlin/pom.xml +++ b/pmd-kotlin/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-lang-test/pom.xml b/pmd-lang-test/pom.xml index fe39bb602d..be3d520ccb 100644 --- a/pmd-lang-test/pom.xml +++ b/pmd-lang-test/pom.xml @@ -12,7 +12,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-languages-deps/pom.xml b/pmd-languages-deps/pom.xml index 358ecf6234..44f68f8698 100644 --- a/pmd-languages-deps/pom.xml +++ b/pmd-languages-deps/pom.xml @@ -4,7 +4,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT pmd-languages-deps diff --git a/pmd-lua/pom.xml b/pmd-lua/pom.xml index e1c07de633..b8d1f9f492 100644 --- a/pmd-lua/pom.xml +++ b/pmd-lua/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-matlab/pom.xml b/pmd-matlab/pom.xml index 4cc4232138..c214076a47 100644 --- a/pmd-matlab/pom.xml +++ b/pmd-matlab/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-modelica/pom.xml b/pmd-modelica/pom.xml index 83e9f19c5e..e891252fef 100644 --- a/pmd-modelica/pom.xml +++ b/pmd-modelica/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-objectivec/pom.xml b/pmd-objectivec/pom.xml index d45fab3959..c4bcba1a01 100644 --- a/pmd-objectivec/pom.xml +++ b/pmd-objectivec/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-perl/pom.xml b/pmd-perl/pom.xml index b2d709d222..6879f273a9 100644 --- a/pmd-perl/pom.xml +++ b/pmd-perl/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-php/pom.xml b/pmd-php/pom.xml index 4aa8fffef4..c769355e6b 100644 --- a/pmd-php/pom.xml +++ b/pmd-php/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-plsql/etc/grammar/PLSQL.jjt b/pmd-plsql/etc/grammar/PLSQL.jjt index b674c0ec6e..4b4092e495 100644 --- a/pmd-plsql/etc/grammar/PLSQL.jjt +++ b/pmd-plsql/etc/grammar/PLSQL.jjt @@ -176,7 +176,7 @@ import java.util.ArrayList; import java.util.List; /** - * @deprecated PLSQLParserImpl should have been package private because this is an implementation class + * @deprecated Since 7.3.0. PLSQLParserImpl should have been package private because this is an implementation class * that should not be used directly. */ @Deprecated @@ -871,6 +871,9 @@ ASTCompilationDataType CompilationDataType() : } } +/** + * https://docs.oracle.com/en/database/oracle/oracle-database/23/lnpls/CREATE-TYPE-statement.html#GUID-389D603D-FBD0-452A-8414-240BBBC57034__OBJECT_BASE_TYPE_DEF-DE2DD0FF + */ ASTCollectionTypeName CollectionTypeName() : { PLSQLNode size=null, precision=null; StringBuilder sb = new StringBuilder(); @@ -886,8 +889,8 @@ ASTCollectionTypeName CollectionTypeName() : sb.append(token.getImage()); } } - (LOOKAHEAD(2) "(" size=NumericLiteral() {sb.append( "(" + size);} - ["," precision=NumericLiteral() {sb.append( "," + precision);}] + (LOOKAHEAD(2) "(" size = NumericLiteral() { sb.append("(").append(size.getImage()); } + ["," precision = NumericLiteral() { sb.append(",").append(precision.getImage()); }] [ {sb.append( " CHAR") ;}] [ {sb.append( " BYTE") ;}] ")" {sb.append( ")");})? @@ -993,12 +996,8 @@ ASTScalarDataTypeName ScalarDataTypeName() : LOOKAHEAD(4) ( + + + #5132 [plsql] TomKytesDespair - exception for more complex exception handler + 0 + + diff --git a/pmd-python/pom.xml b/pmd-python/pom.xml index 30961424e9..70820180ab 100644 --- a/pmd-python/pom.xml +++ b/pmd-python/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-ruby/pom.xml b/pmd-ruby/pom.xml index d480993717..e6bb7f2f2a 100644 --- a/pmd-ruby/pom.xml +++ b/pmd-ruby/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-scala-modules/pmd-scala-common/pom.xml b/pmd-scala-modules/pmd-scala-common/pom.xml index 02e24ea8bb..0491ec1df8 100644 --- a/pmd-scala-modules/pmd-scala-common/pom.xml +++ b/pmd-scala-modules/pmd-scala-common/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../../pom.xml diff --git a/pmd-scala-modules/pmd-scala_2.12/pom.xml b/pmd-scala-modules/pmd-scala_2.12/pom.xml index de0ac943c8..96aa58c01f 100644 --- a/pmd-scala-modules/pmd-scala_2.12/pom.xml +++ b/pmd-scala-modules/pmd-scala_2.12/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd-scala-common - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pmd-scala-common/pom.xml diff --git a/pmd-scala-modules/pmd-scala_2.13/pom.xml b/pmd-scala-modules/pmd-scala_2.13/pom.xml index eba570c541..45962bcd51 100644 --- a/pmd-scala-modules/pmd-scala_2.13/pom.xml +++ b/pmd-scala-modules/pmd-scala_2.13/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd-scala-common - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pmd-scala-common/pom.xml diff --git a/pmd-swift/pom.xml b/pmd-swift/pom.xml index 198560d743..142ee0f8fc 100644 --- a/pmd-swift/pom.xml +++ b/pmd-swift/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-test-schema/pom.xml b/pmd-test-schema/pom.xml index 5744a993a5..42dc277260 100644 --- a/pmd-test-schema/pom.xml +++ b/pmd-test-schema/pom.xml @@ -11,7 +11,7 @@ pmd net.sourceforge.pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-test/pom.xml b/pmd-test/pom.xml index ea1d1c0700..25c15e82ba 100644 --- a/pmd-test/pom.xml +++ b/pmd-test/pom.xml @@ -8,7 +8,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-tsql/pom.xml b/pmd-tsql/pom.xml index f3f513368a..63afe738d7 100644 --- a/pmd-tsql/pom.xml +++ b/pmd-tsql/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-velocity/etc/grammar/Vtl.jjt b/pmd-velocity/etc/grammar/Vtl.jjt index 74804d4dd0..3c9cbb533a 100644 --- a/pmd-velocity/etc/grammar/Vtl.jjt +++ b/pmd-velocity/etc/grammar/Vtl.jjt @@ -58,7 +58,10 @@ import net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken; * @author Geir Magnusson Jr. * @author Henning P. Schmiedehausen * @version $Id$ -*/ + * @deprecated Since 7.5.0. VtlParserImpl should have been package private because this is an implementation class + * that should not be used directly. + */ +@Deprecated public class VtlParserImpl { private void throwParseException(String message) { diff --git a/pmd-velocity/pom.xml b/pmd-velocity/pom.xml index 305f484614..0b54a6f9fc 100644 --- a/pmd-velocity/pom.xml +++ b/pmd-velocity/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-visualforce/etc/grammar/Vf.jjt b/pmd-visualforce/etc/grammar/Vf.jjt index 6fa854e7c3..81c31b2df7 100644 --- a/pmd-visualforce/etc/grammar/Vf.jjt +++ b/pmd-visualforce/etc/grammar/Vf.jjt @@ -13,6 +13,11 @@ options { PARSER_BEGIN(VfParserImpl) package net.sourceforge.pmd.lang.visualforce.ast; +/** + * @deprecated Since 7.5.0. VfParserImpl should have been package private because this is an implementation class + * that should not be used directly. + */ +@Deprecated public class VfParserImpl { diff --git a/pmd-visualforce/pom.xml b/pmd-visualforce/pom.xml index 150a52cae1..078a631a97 100644 --- a/pmd-visualforce/pom.xml +++ b/pmd-visualforce/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pmd-xml/pom.xml b/pmd-xml/pom.xml index 6e6876f751..c543968070 100644 --- a/pmd-xml/pom.xml +++ b/pmd-xml/pom.xml @@ -7,7 +7,7 @@ net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 81df4e149e..87396b1377 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 net.sourceforge.pmd pmd - 7.4.0-SNAPSHOT + 7.5.0-SNAPSHOT pom PMD @@ -83,7 +83,7 @@ - 2024-06-28T08:42:40Z + 2024-07-26T06:43:17Z 8 @@ -100,7 +100,7 @@ 5.0 3.2.5 10.14.0 - 3.3.1 + 3.4.0 3.24.0 1.10.14 3.6.3 @@ -177,7 +177,7 @@ org.apache.maven.plugins maven-dependency-plugin - 3.6.1 + 3.7.1 org.apache.maven.plugins @@ -265,7 +265,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.12.1 + 3.13.0 ${java.version} @@ -562,22 +562,22 @@ net.sourceforge.pmd pmd-core - 7.3.0 + 7.4.0 net.sourceforge.pmd pmd-java - 7.3.0 + 7.4.0 net.sourceforge.pmd pmd-jsp - 7.3.0 + 7.4.0 net.sourceforge.pmd pmd-javascript - 7.3.0 + 7.4.0 @@ -590,12 +590,12 @@ org.apache.maven.plugins maven-site-plugin - 4.0.0-M13 + 4.0.0-M16 org.codehaus.mojo versions-maven-plugin - 2.16.2 + 2.17.1 org.sonatype.plugins @@ -820,7 +820,7 @@ org.pcollections pcollections - 3.2.0 + 4.0.2 net.sourceforge.pmd @@ -855,7 +855,7 @@ org.apache.commons commons-text - 1.11.0 + 1.12.0 org.slf4j @@ -988,7 +988,7 @@ net.bytebuddy byte-buddy-agent - 1.14.12 + 1.14.19 test