Merge branch 'master' into pmd/7.0.x

This commit is contained in:
Andreas Dangel 2021-01-16 10:37:27 +01:00
commit f0f2286f98
27 changed files with 515 additions and 152 deletions

View File

@ -32,95 +32,55 @@ function regression_tester_setup_ci() {
}
#
# Generate a new baseline and upload it to sourceforge
#
# Note: this function always succeeds, even if the upload fails.
# In that case, just a error logging is provided.
# Generate a new baseline and upload it to pmd-code.org
#
function regression_tester_uploadBaseline() {
log_debug "$FUNCNAME branch=${PMD_CI_BRANCH}"
local targetUrl="https://sourceforge.net/projects/pmd/files/pmd-regression-tester/"
local pmdcodeUrl="https://pmd-code.org/pmd-regression-tester/"
local baseline_branch="${PMD_CI_BRANCH:-$PMD_CI_TAG}"
log_debug "$FUNCNAME branch=${baseline_branch}"
local errexitstate="$(shopt -po errexit)"
set +e # disable errexit
(
# This handler is called if any command fails
function upload_failed() {
log_error "Error while uploading ${BRANCH_FILENAME}-baseline.zip to pmd-code.org!"
log_error "Please upload manually: ${pmdcodeUrl}"
#log_error "Error while uploading ${BRANCH_FILENAME}-baseline.zip to sourceforge!"
#log_error "Please upload manually: ${targetUrl}"
}
# exit subshell after trap
set -e
trap upload_failed ERR
log_info "Generating and uploading baseline for pmdtester..."
cd ..
bundle config --local gemfile pmd/Gemfile
bundle config set --local path pmd/vendor/bundle
bundle exec pmdtester \
--mode single \
--local-git-repo ./pmd \
--patch-branch ${PMD_CI_BRANCH:-$PMD_CI_TAG} \
--patch-config ./pmd/.ci/files/all-java.xml \
--list-of-project ./pmd/.ci/files/project-list.xml --html-flag \
--error-recovery
cd target/reports
BRANCH_FILENAME="${PMD_CI_BRANCH:-$PMD_CI_TAG}"
BRANCH_FILENAME="${BRANCH_FILENAME/\//_}"
zip -q -r ${BRANCH_FILENAME}-baseline.zip ${BRANCH_FILENAME}/
# ssh-key for pmd-code.org is setup already by pmd_ci_setup_ssh
scp ${BRANCH_FILENAME}-baseline.zip pmd@pmd-code.org:/httpdocs/pmd-regression-tester/
log_success "Successfully uploaded ${BRANCH_FILENAME}-baseline.zip to ${pmdcodeUrl}"
#../../pmd/.ci/travis_wait "rsync -avh ${BRANCH_FILENAME}-baseline.zip ${PMD_SF_USER}@web.sourceforge.net:/home/frs/project/pmd/pmd-regression-tester/"
#log_success "Successfully uploaded ${BRANCH_FILENAME}-baseline.zip to ${targetUrl}"
)
# restore errexit state
eval "$errexitstate"
log_info "Generating and uploading baseline for pmdtester (${baseline_branch})..."
pushd ..
rm -f .bundle/config
bundle config set --local gemfile pmd/Gemfile
bundle exec pmdtester \
--mode single \
--local-git-repo ./pmd \
--patch-branch ${baseline_branch} \
--patch-config ./pmd/.ci/files/all-java.xml \
--list-of-project ./pmd/.ci/files/project-list.xml --html-flag \
--error-recovery
pushd target/reports
BRANCH_FILENAME="${baseline_branch/\//_}"
zip -q -r ${BRANCH_FILENAME}-baseline.zip ${BRANCH_FILENAME}/
# ssh-key for pmd-code.org is setup already by pmd_ci_setup_ssh
scp ${BRANCH_FILENAME}-baseline.zip pmd@pmd-code.org:/httpdocs/pmd-regression-tester/
log_success "Successfully uploaded ${BRANCH_FILENAME}-baseline.zip to ${pmdcodeUrl}"
popd
popd
}
#
# Execute danger, which executes pmd-regression-tester (via Dangerfile).
#
# Note: this function always succeeds, even if the danger fails.
# In that case, just a error logging is provided.
#
function regression_tester_executeDanger() {
log_debug "$FUNCNAME"
local errexitstate="$(shopt -po errexit)"
set +e # disable errexit
(
# This handler is called if any command fails
function danger_failed() {
log_error "Error while executing danger/pmd-regression-tester"
}
# Create a corresponding remote branch locally
if ! git show-ref --verify --quiet refs/heads/${PMD_CI_BRANCH}; then
git fetch --no-tags --depth=1 origin +refs/heads/${PMD_CI_BRANCH}:refs/remotes/origin/${PMD_CI_BRANCH}
git branch ${PMD_CI_BRANCH} origin/${PMD_CI_BRANCH}
log_debug "Created local branch ${PMD_CI_BRANCH}"
fi
# Fetch more commits of the PR for danger and regression tester
git fetch --no-tags --depth=50 origin +$(git rev-parse HEAD^2):
# Fetch more commits from master branch for regression tester
if [[ "${PMD_CI_BRANCH}" != "master" ]]; then
git fetch --no-tags --depth=50 origin +master:
git branch master origin/master
fi
# exit subshell after trap
set -e
trap danger_failed ERR
# Create a corresponding remote branch locally
if ! git show-ref --verify --quiet refs/heads/${PMD_CI_BRANCH}; then
git fetch --no-tags --depth=1 origin +refs/heads/${PMD_CI_BRANCH}:refs/remotes/origin/${PMD_CI_BRANCH}
git branch ${PMD_CI_BRANCH} origin/${PMD_CI_BRANCH}
log_debug "Created local branch ${PMD_CI_BRANCH}"
fi
# Fetch more commits of the PR for danger and regression tester
git fetch --no-tags --depth=50 origin +$(git rev-parse HEAD^2):
# Fetch more commits from master branch for regression tester
if [[ "${PMD_CI_BRANCH}" != "master" ]]; then
git fetch --no-tags --depth=50 origin +master:
git branch master origin/master
fi
log_info "Running danger on branch ${PMD_CI_BRANCH}"
bundle exec danger --verbose
log_success "Executing danger successfully"
)
# restore errexit state
eval "$errexitstate"
log_info "Running danger on branch ${PMD_CI_BRANCH}"
bundle exec danger --verbose
log_success "Executed danger successfully"
}

View File

@ -6,7 +6,7 @@ jobs:
build:
runs-on: ${{ matrix.os }}
continue-on-error: false
timeout-minutes: 30
timeout-minutes: 60
strategy:
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]

View File

@ -45,7 +45,7 @@ There are various channels, on which you can ask questions:
* On [StackOverflow](https://stackoverflow.com/questions/tagged/pmd): Make sure, to tag your question with "pmd".
* Create a issue for your question at <https://github.com/pmd/pmd/issues>.
* Create a new discussion for your question at <https://github.com/pmd/pmd/discussions>.
* Ask your question on Gitter <https://gitter.im/pmd/pmd>.

View File

@ -87,8 +87,9 @@ def upload_report
`tar -cf #{tar_filename} diff1/ diff2/`
report_url = `curl -u #{ENV['PMD_CI_CHUNK_TOKEN']} -T #{tar_filename} https://chunk.io`
if $?.success?
@logger.info "Successfully uploaded #{tar_filename} to chunk.io"
report_url.chomp
report_url.chomp!
@logger.info "Successfully uploaded #{tar_filename} to #{report_url}"
report_url
else
@logger.error "Error while uploading #{tar_filename} to chunk.io: #{report_url}"
warn("Uploading the diff report failed, this message is mainly used to remind the maintainers of PMD.")

View File

@ -3,7 +3,7 @@ source 'https://rubygems.org/'
# bleeding edge from git
#gem 'pmdtester', :git => 'https://github.com/pmd/pmd-regression-tester.git'
gem 'pmdtester', '~> 1.1'
gem 'pmdtester', '~> 1'
gem 'danger', '~> 5.6', '>= 5.6'
# This group is only needed for rendering release notes

View File

@ -31,36 +31,38 @@ GEM
multipart-post (>= 1.2, < 3)
faraday-http-cache (1.3.1)
faraday (~> 0.8)
fugit (1.4.1)
fugit (1.4.2)
et-orbi (~> 1.1, >= 1.1.8)
raabro (~> 1.4)
git (1.7.0)
git (1.8.1)
rchardet (~> 1.8)
kramdown (1.17.0)
liquid (4.0.3)
liquid (5.0.0)
logger-colors (1.0.0)
mini_portile2 (2.4.0)
mini_portile2 (2.5.0)
multipart-post (2.1.1)
nap (1.1.0)
no_proxy_fix (0.1.2)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
octokit (4.19.0)
nokogiri (1.11.1)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
octokit (4.20.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
open4 (1.3.4)
pmdtester (1.1.0)
pmdtester (1.1.1)
differ (~> 0.1)
liquid (>= 4.0)
logger-colors (~> 1.0)
nokogiri (~> 1.8)
nokogiri (>= 1.11.0.rc4)
rufus-scheduler (~> 3.5)
slop (~> 4.6)
public_suffix (4.0.6)
raabro (1.4.0)
racc (1.5.2)
rchardet (1.8.0)
rouge (3.25.0)
rufus-scheduler (3.6.0)
rouge (3.26.0)
rufus-scheduler (3.7.0)
fugit (~> 1.1, >= 1.1.6)
safe_yaml (1.0.5)
sawyer (0.8.2)
@ -69,7 +71,7 @@ GEM
slop (4.8.2)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
tzinfo (2.0.3)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
unicode-display_width (1.7.0)
@ -79,7 +81,7 @@ PLATFORMS
DEPENDENCIES
danger (~> 5.6, >= 5.6)
liquid (>= 4.0.0)
pmdtester (~> 1.1)
pmdtester (~> 1)
rouge (>= 1.7, < 4)
safe_yaml (>= 1.0)

View File

@ -22,10 +22,12 @@ Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex, Scala, Swift,
## Support
* How do I? -- Ask a question on [StackOverflow](https://stackoverflow.com/questions/tagged/pmd).
* I got this error, why? -- Ask a question on [StackOverflow](https://stackoverflow.com/questions/tagged/pmd).
* How do I? -- Ask a question on [StackOverflow](https://stackoverflow.com/questions/tagged/pmd)
or on [discussions](https://github.com/pmd/pmd/discussions).
* I got this error, why? -- Ask a question on [StackOverflow](https://stackoverflow.com/questions/tagged/pmd)
or on [discussions](https://github.com/pmd/pmd/discussions).
* I got this error and I'm sure it's a bug -- file an [issue](https://github.com/pmd/pmd/issues).
* I have an idea/request/question -- file an [issue](https://github.com/pmd/pmd/issues).
* I have an idea/request/question -- create a new [discussion](https://github.com/pmd/pmd/discussions).
* I have a quick question -- ask on our [Gitter chat](https://gitter.im/pmd/pmd).
* Where's your documentation? -- <https://pmd.github.io/latest/>

View File

@ -1,7 +1,7 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (6.0.3.2)
activesupport (6.0.3.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@ -17,37 +17,40 @@ GEM
commonmarker (0.17.13)
ruby-enum (~> 0.5)
concurrent-ruby (1.1.7)
dnsruby (1.61.4)
dnsruby (1.61.5)
simpleidn (~> 0.1)
em-websocket (0.5.1)
em-websocket (0.5.2)
eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0)
ethon (0.12.0)
ffi (>= 1.3.0)
eventmachine (1.2.7)
execjs (2.7.0)
faraday (1.0.1)
faraday (1.3.0)
faraday-net_http (~> 1.0)
multipart-post (>= 1.2, < 3)
ffi (1.13.1)
ruby2_keywords
faraday-net_http (1.0.0)
ffi (1.14.2)
forwardable-extended (2.6.0)
gemoji (3.0.1)
github-pages (207)
github-pages (209)
github-pages-health-check (= 1.16.1)
jekyll (= 3.9.0)
jekyll-avatar (= 0.7.0)
jekyll-coffeescript (= 1.1.1)
jekyll-commonmark-ghpages (= 0.1.6)
jekyll-default-layout (= 0.1.4)
jekyll-feed (= 0.13.0)
jekyll-feed (= 0.15.1)
jekyll-gist (= 1.5.0)
jekyll-github-metadata (= 2.13.0)
jekyll-mentions (= 1.5.1)
jekyll-mentions (= 1.6.0)
jekyll-optional-front-matter (= 0.3.2)
jekyll-paginate (= 1.1.0)
jekyll-readme-index (= 0.3.0)
jekyll-redirect-from (= 0.15.0)
jekyll-redirect-from (= 0.16.0)
jekyll-relative-links (= 0.6.1)
jekyll-remote-theme (= 0.4.1)
jekyll-remote-theme (= 0.4.2)
jekyll-sass-converter (= 1.5.2)
jekyll-seo-tag (= 2.6.1)
jekyll-sitemap (= 1.4.0)
@ -55,7 +58,7 @@ GEM
jekyll-theme-architect (= 0.1.1)
jekyll-theme-cayman (= 0.1.1)
jekyll-theme-dinky (= 0.1.1)
jekyll-theme-hacker (= 0.1.1)
jekyll-theme-hacker (= 0.1.2)
jekyll-theme-leap-day (= 0.1.1)
jekyll-theme-merlot (= 0.1.1)
jekyll-theme-midnight (= 0.1.1)
@ -66,14 +69,14 @@ GEM
jekyll-theme-tactile (= 0.1.1)
jekyll-theme-time-machine (= 0.1.1)
jekyll-titles-from-headings (= 0.5.3)
jemoji (= 0.11.1)
jemoji (= 0.12.0)
kramdown (= 2.3.0)
kramdown-parser-gfm (= 1.1.0)
liquid (= 4.0.3)
mercenary (~> 0.3)
minima (= 2.5.1)
nokogiri (>= 1.10.4, < 2.0)
rouge (= 3.19.0)
rouge (= 3.23.0)
terminal-table (~> 1.4)
github-pages-health-check (1.16.1)
addressable (~> 2.3)
@ -114,14 +117,14 @@ GEM
rouge (>= 2.0, < 4.0)
jekyll-default-layout (0.1.4)
jekyll (~> 3.0)
jekyll-feed (0.13.0)
jekyll-feed (0.15.1)
jekyll (>= 3.7, < 5.0)
jekyll-gist (1.5.0)
octokit (~> 4.2)
jekyll-github-metadata (2.13.0)
jekyll (>= 3.4, < 5.0)
octokit (~> 4.0, != 4.4.0)
jekyll-mentions (1.5.1)
jekyll-mentions (1.6.0)
html-pipeline (~> 2.3)
jekyll (>= 3.7, < 5.0)
jekyll-optional-front-matter (0.3.2)
@ -129,14 +132,15 @@ GEM
jekyll-paginate (1.1.0)
jekyll-readme-index (0.3.0)
jekyll (>= 3.0, < 5.0)
jekyll-redirect-from (0.15.0)
jekyll-redirect-from (0.16.0)
jekyll (>= 3.3, < 5.0)
jekyll-relative-links (0.6.1)
jekyll (>= 3.3, < 5.0)
jekyll-remote-theme (0.4.1)
jekyll-remote-theme (0.4.2)
addressable (~> 2.0)
jekyll (>= 3.5, < 5.0)
rubyzip (>= 1.3.0)
jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0)
rubyzip (>= 1.3.0, < 3.0)
jekyll-sass-converter (1.5.2)
sass (~> 3.4)
jekyll-seo-tag (2.6.1)
@ -153,8 +157,8 @@ GEM
jekyll-theme-dinky (0.1.1)
jekyll (~> 3.5)
jekyll-seo-tag (~> 2.0)
jekyll-theme-hacker (0.1.1)
jekyll (~> 3.5)
jekyll-theme-hacker (0.1.2)
jekyll (> 3.5, < 5.0)
jekyll-seo-tag (~> 2.0)
jekyll-theme-leap-day (0.1.1)
jekyll (~> 3.5)
@ -188,7 +192,7 @@ GEM
jekyll (>= 3.3, < 5.0)
jekyll-watch (2.2.1)
listen (~> 3.0)
jemoji (0.11.1)
jemoji (0.12.0)
gemoji (~> 3.0)
html-pipeline (~> 2.2)
jekyll (>= 3.0, < 5.0)
@ -197,32 +201,35 @@ GEM
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
liquid (4.0.3)
listen (3.2.1)
listen (3.4.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
mini_portile2 (2.4.0)
mini_portile2 (2.5.0)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.14.1)
minitest (5.14.3)
multipart-post (2.1.1)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
octokit (4.18.0)
nokogiri (1.11.1)
mini_portile2 (~> 2.5.0)
racc (~> 1.4)
octokit (4.20.0)
faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3)
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (3.1.1)
racc (1.5.2)
rb-fsevent (0.10.4)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.4)
rouge (3.19.0)
rouge (3.23.0)
ruby-enum (0.8.0)
i18n
ruby2_keywords (0.0.2)
rubyzip (2.3.0)
safe_yaml (1.0.5)
sass (3.7.4)
@ -240,13 +247,13 @@ GEM
thread_safe (0.3.6)
typhoeus (1.4.0)
ethon (>= 0.9.0)
tzinfo (1.2.7)
tzinfo (1.2.9)
thread_safe (~> 0.1)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.7)
unicode-display_width (1.7.0)
zeitwerk (2.4.0)
zeitwerk (2.4.2)
PLATFORMS
ruby

View File

@ -252,7 +252,7 @@ we may decide to remove some APIs that were not tagged as deprecated, though we'
###### Around RuleSet parsing
* {% jdoc core::RuleSetFactory %} and {% jdoc core::RuleSetFactoryUtils %} have been deprecated in favor of {% jdoc core::RuleSetLoader %}. This is easier to configure, and more maintainable than the multiple overloads of `RuleSetFactoryUtils`.
* {% jdoc core::RuleSetFactory %} and {% jdoc core::RulesetsFactoryUtils %} have been deprecated in favor of {% jdoc core::RuleSetLoader %}. This is easier to configure, and more maintainable than the multiple overloads of `RulesetsFactoryUtils`.
* Some static creation methods have been added to {% jdoc core::RuleSet %} for simple cases, eg {% jdoc core::RuleSet#forSingleRule(core::Rule) %}. These replace some counterparts in {% jdoc core::RuleSetFactory %}
* Since {% jdoc core::RuleSets %} is also deprecated, many APIs that require a RuleSets instance now are deprecated, and have a counterpart that expects a `List<RuleSet>`.
* {% jdoc core::RuleSetReferenceId %}, {% jdoc core::RuleSetReference %}, {% jdoc core::RuleSetFactoryCompatibility %} are deprecated. They are most likely not relevant outside of the implementation of pmd-core.

View File

@ -1,8 +1,8 @@
---
title: Getting Help
permalink: pmd_about_help.html
author: Andreas Dangel <andreas.dangel@adangel.org>
last_updated: September 2017
author: Andreas Dangel <andreas.dangel@pmd-code.org>
last_updated: January 2021
---
There are numerous ways of getting help:
@ -13,7 +13,7 @@ There are numerous ways of getting help:
* If you found a bug, please create a new [github issue](https://github.com/pmd/pmd/issues).
* You can also ask questions in our [sourceforge forum](https://sourceforge.net/p/pmd/discussion/).
* You can also ask questions on [github discussions](https://github.com/pmd/pmd/discussions).
* Or you can join the [Mailing List](https://lists.sourceforge.net/lists/listinfo/pmd-devel) or browse
through the archives ([archive1](http://java-pmd.30631.n5.nabble.com/), [archive2](http://web.archive.org/web/20160715035623/http://blog.gmane.org:80/gmane.comp.java.audit.pmd.devel)).

View File

@ -21,9 +21,18 @@ This is a {{ site.pmd.release_type }} release.
### Fixed Issues
* core
* [#2994](https://github.com/pmd/pmd/pull/2994): \[core] Fix code climate severity strings
* java-bestpractices
* [#575](https://github.com/pmd/pmd/issues/575): \[java] LiteralsFirstInComparisons should consider constant fields
### API Changes
### External Contributions
* [#2964](https://github.com/pmd/pmd/pull/2964): \[cs] Update C# grammar for additional C# 7 and C# 8 features - [Maikel Steneker](https://github.com/maikelsteneker)
* [#2983](https://github.com/pmd/pmd/pull/2983): \[java] LiteralsFirstInComparisons should consider constant fields - [Ozan Gulle](https://github.com/ozangulle)
* [#2994](https://github.com/pmd/pmd/pull/2994): \[core] Fix code climate severity strings - [Vincent Maurin](https://github.com/vmaurin)
{% endtocmaker %}

View File

@ -70,7 +70,7 @@ Thanks to Jeff Bartolotta and Roopa Mohan for contributing this!
##### Around RuleSet parsing
* <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RuleSetFactory.html#"><code>RuleSetFactory</code></a> and <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RulesetsFactoryUtils.html#"><code>RulesetsFactoryUtils</code></a> have been deprecated in favor of <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RuleSetLoader.html#"><code>RuleSetLoader</code></a>. This is easier to configure, and more maintainable than the multiple overloads of `RuleSetFactoryUtils`.
* <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RuleSetFactory.html#"><code>RuleSetFactory</code></a> and <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RulesetsFactoryUtils.html#"><code>RulesetsFactoryUtils</code></a> have been deprecated in favor of <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RuleSetLoader.html#"><code>RuleSetLoader</code></a>. This is easier to configure, and more maintainable than the multiple overloads of `RulesetsFactoryUtils`.
* Some static creation methods have been added to <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RuleSet.html#"><code>RuleSet</code></a> for simple cases, eg <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RuleSet.html#forSingleRule(net.sourceforge.pmd.Rule)"><code>forSingleRule</code></a>. These replace some counterparts in <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RuleSetFactory.html#"><code>RuleSetFactory</code></a>
* Since <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RuleSets.html#"><code>RuleSets</code></a> is also deprecated, many APIs that require a RuleSets instance now are deprecated, and have a counterpart that expects a `List<RuleSet>`.
* <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RuleSetReferenceId.html#"><code>RuleSetReferenceId</code></a>, <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RuleSetReference.html#"><code>RuleSetReference</code></a>, <a href="https://docs.pmd-code.org/apidocs/pmd-core/6.30.0/net/sourceforge/pmd/RuleSetFactoryCompatibility.html#"><code>RuleSetFactoryCompatibility</code></a> are deprecated. They are most likely not relevant outside of the implementation of pmd-core.

View File

@ -80,12 +80,16 @@ public class CodeClimateRenderer extends AbstractIncrementingRenderer {
switch (rule.getPriority()) {
case HIGH:
issue.severity = "critical";
issue.severity = "blocker";
break;
case MEDIUM_HIGH:
issue.severity = "critical";
break;
case MEDIUM:
issue.severity = "major";
break;
case MEDIUM_LOW:
issue.severity = "normal";
issue.severity = "minor";
break;
case LOW:
default:

View File

@ -13,6 +13,7 @@ import net.sourceforge.pmd.Report;
import net.sourceforge.pmd.Report.ConfigurationError;
import net.sourceforge.pmd.Report.ProcessingError;
import net.sourceforge.pmd.ReportTest;
import net.sourceforge.pmd.RulePriority;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.RuleWithProperties;
import net.sourceforge.pmd.lang.ast.DummyNode;
@ -66,8 +67,12 @@ public abstract class AbstractRendererTest {
private Report reportTwoViolations() {
Report report = new Report();
report.addRuleViolation(newRuleViolation(1));
report.addRuleViolation(newRuleViolation(2));
RuleViolation informationalRuleViolation = newRuleViolation(1);
informationalRuleViolation.getRule().setPriority(RulePriority.LOW);
report.addRuleViolation(informationalRuleViolation);
RuleViolation severeRuleViolation = newRuleViolation(2);
severeRuleViolation.getRule().setPriority(RulePriority.HIGH);
report.addRuleViolation(severeRuleViolation);
return report;
}

View File

@ -30,7 +30,7 @@ public class CSVRendererTest extends AbstractRendererTest {
public String getExpectedMultiple() {
return getHeader()
+ "\"1\",\"\",\"" + getSourceCodeFilename() + "\",\"5\",\"1\",\"blah\",\"RuleSet\",\"Foo\"" + PMD.EOL
+ "\"2\",\"\",\"" + getSourceCodeFilename() + "\",\"5\",\"1\",\"blah\",\"RuleSet\",\"Foo\"" + PMD.EOL;
+ "\"2\",\"\",\"" + getSourceCodeFilename() + "\",\"1\",\"1\",\"blah\",\"RuleSet\",\"Foo\"" + PMD.EOL;
}
@Override

View File

@ -77,7 +77,7 @@ public class CodeClimateRendererTest extends AbstractRendererTest {
+ "violationSuppressXPath | | Suppress violations on nodes which match a given relative XPath expression.\\n"
+ "\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"" + getSourceCodeFilename() + "\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}"
+ "\u0000" + PMD.EOL + "{\"type\":\"issue\",\"check_name\":\"Foo\",\"description\":\"blah\","
+ "\"content\":{\"body\":\"## Foo\\n\\nSince: PMD null\\n\\nPriority: Low\\n\\n"
+ "\"content\":{\"body\":\"## Foo\\n\\nSince: PMD null\\n\\nPriority: High\\n\\n"
+ "[Categories](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#categories): Style\\n\\n"
+ "[Remediation Points](https://github.com/codeclimate/platform/blob/master/spec/analyzers/SPEC.md#remediation-points): 50000\\n\\n"
+ "desc\\n\\n"
@ -85,7 +85,7 @@ public class CodeClimateRendererTest extends AbstractRendererTest {
+ "Name | Value | Description\\n" + "--- | --- | ---\\n"
+ "violationSuppressRegex | | Suppress violations with messages matching a regular expression\\n"
+ "violationSuppressXPath | | Suppress violations on nodes which match a given relative XPath expression.\\n"
+ "\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"" + getSourceCodeFilename() + "\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"info\",\"remediation_points\":50000}"
+ "\"},\"categories\":[\"Style\"],\"location\":{\"path\":\"" + getSourceCodeFilename() + "\",\"lines\":{\"begin\":1,\"end\":1}},\"severity\":\"blocker\",\"remediation_points\":50000}"
+ "\u0000" + PMD.EOL;
}

View File

@ -79,6 +79,7 @@ public class JsonRendererTest extends AbstractRendererTest {
public String filter(String expected) {
String result = expected
.replaceAll("\"timestamp\":\\s*\"[^\"]+\"", "\"timestamp\": \"--replaced--\"")
.replaceAll("\"pmdVersion\":\\s*\"[^\"]+\"", "\"pmdVersion\": \"unknown\"")
.replaceAll("\r\n", "\n"); // make the test run on Windows, too
return result;
}

View File

@ -62,7 +62,7 @@ public class XMLRendererTest extends AbstractRendererTest {
return getHeader() + "<file name=\"" + getSourceCodeFilename() + "\">" + PMD.EOL
+ "<violation beginline=\"1\" endline=\"1\" begincolumn=\"1\" endcolumn=\"1\" rule=\"Foo\" ruleset=\"RuleSet\" priority=\"5\">"
+ PMD.EOL + "blah" + PMD.EOL + "</violation>" + PMD.EOL
+ "<violation beginline=\"1\" endline=\"1\" begincolumn=\"1\" endcolumn=\"2\" rule=\"Foo\" ruleset=\"RuleSet\" priority=\"5\">"
+ "<violation beginline=\"1\" endline=\"1\" begincolumn=\"1\" endcolumn=\"2\" rule=\"Foo\" ruleset=\"RuleSet\" priority=\"1\">"
+ PMD.EOL + "blah" + PMD.EOL + "</violation>" + PMD.EOL + "</file>" + PMD.EOL + "</pmd>" + PMD.EOL;
}

View File

@ -24,7 +24,7 @@
"description": "blah",
"rule": "Foo",
"ruleset": "RuleSet",
"priority": 5
"priority": 1
}
]
}

View File

@ -19,7 +19,8 @@ private boolean verbatium;
BYTE_ORDER_MARK: '\u00EF\u00BB\u00BF';
SINGLE_LINE_DOC_COMMENT: '///' InputCharacter* -> channel(COMMENTS_CHANNEL);
DELIMITED_DOC_COMMENT: '/**' .*? '*/' -> channel(COMMENTS_CHANNEL);
EMPTY_DELIMITED_DOC_COMMENT: '/***/' -> channel(COMMENTS_CHANNEL);
DELIMITED_DOC_COMMENT: '/**' ~'/' .*? '*/' -> channel(COMMENTS_CHANNEL);
SINGLE_LINE_COMMENT: '//' InputCharacter* -> channel(COMMENTS_CHANNEL);
DELIMITED_COMMENT: '/*' .*? '*/' -> channel(COMMENTS_CHANNEL);
@ -119,6 +120,7 @@ TYPEOF: 'typeof';
UINT: 'uint';
ULONG: 'ulong';
UNCHECKED: 'unchecked';
UNMANAGED: 'unmanaged';
UNSAFE: 'unsafe';
USHORT: 'ushort';
USING: 'using';
@ -138,10 +140,11 @@ IDENTIFIER: '@'? IdentifierOrKeyword;
//B.1.8 Literals
// 0.Equals() would be parsed as an invalid real (1. branch) causing a lexer error
LITERAL_ACCESS: [0-9]+ IntegerTypeSuffix? '.' '@'? IdentifierOrKeyword;
INTEGER_LITERAL: [0-9]+ IntegerTypeSuffix?;
HEX_INTEGER_LITERAL: '0' [xX] HexDigit+ IntegerTypeSuffix?;
REAL_LITERAL: [0-9]* '.' [0-9]+ ExponentPart? [FfDdMm]? | [0-9]+ ([FfDdMm] | ExponentPart [FfDdMm]?);
LITERAL_ACCESS: [0-9] ('_'* [0-9])* IntegerTypeSuffix? '.' '@'? IdentifierOrKeyword;
INTEGER_LITERAL: [0-9] ('_'* [0-9])* IntegerTypeSuffix?;
HEX_INTEGER_LITERAL: '0' [xX] ('_'* HexDigit)+ IntegerTypeSuffix?;
BIN_INTEGER_LITERAL: '0' [bB] ('_'* [01])+ IntegerTypeSuffix?;
REAL_LITERAL: ([0-9] ('_'* [0-9])*)? '.' [0-9] ('_'* [0-9])* ExponentPart? [FfDdMm]? | [0-9] ('_'* [0-9])* ([FfDdMm] | ExponentPart [FfDdMm]?);
CHARACTER_LITERAL: '\'' (~['\\\r\n\u0085\u2028\u2029] | CommonCharacter) '\'';
REGULAR_STRING: '"' (~["\\\r\n\u0085\u2028\u2029] | CommonCharacter)* '"';
@ -234,6 +237,8 @@ OP_OR_ASSIGNMENT: '|=';
OP_XOR_ASSIGNMENT: '^=';
OP_LEFT_SHIFT: '<<';
OP_LEFT_SHIFT_ASSIGNMENT: '<<=';
OP_COALESCING_ASSIGNMENT: '??=';
OP_RANGE: '..';
// https://msdn.microsoft.com/en-us/library/dn961160.aspx
mode INTERPOLATION_STRING;
@ -271,6 +276,7 @@ WARNING: 'warning' Whitespace+ -> channel(DIREC
REGION: 'region' Whitespace* -> channel(DIRECTIVE), mode(DIRECTIVE_TEXT);
ENDREGION: 'endregion' Whitespace* -> channel(DIRECTIVE), mode(DIRECTIVE_TEXT);
PRAGMA: 'pragma' Whitespace+ -> channel(DIRECTIVE), mode(DIRECTIVE_TEXT);
NULLABLE: 'nullable' Whitespace+ -> channel(DIRECTIVE), mode(DIRECTIVE_TEXT);
DIRECTIVE_DEFAULT: 'default' -> channel(DIRECTIVE), type(DEFAULT);
DIRECTIVE_HIDDEN: 'hidden' -> channel(DIRECTIVE);
DIRECTIVE_OPEN_PARENS: '(' -> channel(DIRECTIVE), type(OPEN_PARENS);
@ -303,7 +309,7 @@ fragment NewLineCharacter
;
fragment IntegerTypeSuffix: [lL]? [uU] | [uU]? [lL];
fragment ExponentPart: [eE] ('+' | '-')? [0-9]+;
fragment ExponentPart: [eE] ('+' | '-')? [0-9] ('_'* [0-9])*;
fragment CommonCharacter
: SimpleEscapeSequence
@ -1102,4 +1108,4 @@ fragment UnicodeClassND
| '\uaa50'..'\uaa59'
| '\uabf0'..'\uabf9'
| '\uff10'..'\uff19'
;
;

View File

@ -100,6 +100,11 @@ public class CsTokenizerTest extends CpdTextComparisonTest {
doTest("listOfNumbers", "_ignored", skipLiteralSequences());
}
@Test
public void testCSharp7And8Additions() {
doTest("csharp7And8Additions");
}
private Properties ignoreUsings() {
return properties(true, false);
}

View File

@ -1,3 +1,5 @@
/**/
// the previous comment is an empty delimited comment and not a document comment
class Foo { /// class X
/* aaa

View File

@ -1,8 +1,8 @@
[Image] or [Truncated image[ Bcol Ecol
L1
L3
[class] 1 6
[Foo] 7 10
[{] 11 12
L6
L8
[}] 2 3
EOF

View File

@ -0,0 +1,26 @@
#nullable enable
using System;
using System.Collections.Generic;
class CSharp7And8Additions
{
private static void Literals()
{
int x = 30_000_000; // digit separators
int b = 0b00101000; // boolean literal
}
private static unsafe void DisplaySize<T>() where T : unmanaged // unmanaged keyword
{
Console.WriteLine($"{typeof(T)} is unmanaged and its size is {sizeof(T)} bytes");
}
private static void Operators()
{
List<int>? l = null;
(l ??= new List<int>()).Add(5); // null-coalescing assignment operator
var array = new int[] { 1, 2, 3, 4, 5 };
var slice1 = array[2..^3]; // range operator
}
}

View File

@ -0,0 +1,155 @@
[Image] or [Truncated image[ Bcol Ecol
L1
[#] 1 1
L2
[using] 1 5
[System] 7 12
[;] 13 13
L3
[using] 1 5
[System] 7 12
[.] 13 13
[Collections] 14 24
[.] 25 25
[Generic] 26 32
[;] 33 33
L5
[class] 1 5
[CSharp7And8Additions] 7 26
L6
[{] 1 1
L7
[private] 5 11
[static] 13 18
[void] 20 23
[Literals] 25 32
[(] 33 33
[)] 34 34
L8
[{] 5 5
L9
[int] 9 11
[x] 13 13
[=] 15 15
[30_000_000] 17 26
[;] 27 27
L10
[int] 9 11
[b] 13 13
[=] 15 15
[0b00101000] 17 26
[;] 27 27
L11
[}] 5 5
L13
[private] 5 11
[static] 13 18
[unsafe] 20 25
[void] 27 30
[DisplaySize] 32 42
[<] 43 43
[T] 44 44
[>] 45 45
[(] 46 46
[)] 47 47
[where] 49 53
[T] 55 55
[:] 57 57
[unmanaged] 59 67
L14
[{] 5 5
L15
[Console] 9 15
[.] 16 16
[WriteLine] 17 25
[(] 26 26
[$"] 27 28
[typeof] 30 35
[(] 36 36
[T] 37 37
[)] 38 38
[ is unmanaged and its size is ] 40 69
[sizeof] 71 76
[(] 77 77
[T] 78 78
[)] 79 79
[ bytes] 81 86
["] 87 87
[)] 88 88
[;] 89 89
L16
[}] 5 5
L18
[private] 5 11
[static] 13 18
[void] 20 23
[Operators] 25 33
[(] 34 34
[)] 35 35
L19
[{] 5 5
L20
[List] 9 12
[<] 13 13
[int] 14 16
[>] 17 17
[?] 18 18
[l] 20 20
[=] 22 22
[null] 24 27
[;] 28 28
L21
[(] 9 9
[l] 10 10
[??=] 12 14
[new] 16 18
[List] 20 23
[<] 24 24
[int] 25 27
[>] 28 28
[(] 29 29
[)] 30 30
[)] 31 31
[.] 32 32
[Add] 33 35
[(] 36 36
[5] 37 37
[)] 38 38
[;] 39 39
L23
[var] 9 11
[array] 13 17
[=] 19 19
[new] 21 23
[int] 25 27
[\[] 28 28
[\]] 29 29
[{] 31 31
[1] 33 33
[,] 34 34
[2] 36 36
[,] 37 37
[3] 39 39
[,] 40 40
[4] 42 42
[,] 43 43
[5] 45 45
[}] 47 47
[;] 48 48
L24
[var] 9 11
[slice1] 13 18
[=] 20 20
[array] 22 26
[\[] 27 27
[2] 28 28
[..] 29 30
[^] 31 31
[3] 32 32
[\]] 33 33
[;] 34 34
L25
[}] 5 5
L26
[}] 1 1
EOF

View File

@ -7,12 +7,29 @@ package net.sourceforge.pmd.lang.java.rule.bestpractices;
import static net.sourceforge.pmd.util.CollectionUtil.listOf;
import static net.sourceforge.pmd.util.CollectionUtil.setOf;
import java.util.List;
import java.util.Set;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.lang.java.ast.ASTArgumentList;
import net.sourceforge.pmd.lang.java.ast.ASTArguments;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBodyDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTConditionalAndExpression;
import net.sourceforge.pmd.lang.java.ast.ASTConditionalOrExpression;
import net.sourceforge.pmd.lang.java.ast.ASTEqualityExpression;
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
import net.sourceforge.pmd.lang.java.ast.ASTName;
import net.sourceforge.pmd.lang.java.ast.ASTNullLiteral;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
import net.sourceforge.pmd.lang.java.ast.ASTStringLiteral;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
@ -49,6 +66,106 @@ public class LiteralsFirstInComparisonsRule extends AbstractJavaRulechainRule {
return call.getMethodType().getFormalParameters().equals(listOf(call.getTypeSystem().OBJECT));
}
/*
* This corresponds to the following XPath expression:
* (../PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix/Literal[@StringLiteral= true()])
* and
* ( count(../PrimarySuffix/Arguments/ArgumentList/Expression) = 1 )
*/
private boolean isSingleStringLiteralArgument(ASTPrimarySuffix primarySuffix) {
return isSingleArgumentSuffix(primarySuffix) && isStringLiteralFirstArgumentOfSuffix(primarySuffix);
}
private boolean isSingleArgumentSuffix(ASTPrimarySuffix primarySuffix) {
return primarySuffix.getArgumentCount() == 1;
}
private boolean isStringLiteralFirstArgumentOfSuffix(ASTPrimarySuffix primarySuffix) {
try {
JavaNode firstLiteralArg = getFirstLiteralArgument(primarySuffix);
JavaNode firstNameArg = getFirstNameArgument(primarySuffix);
return isStringLiteral(firstLiteralArg) || isConstantString(firstNameArg);
} catch (NullPointerException e) {
return false;
}
}
private JavaNode getFirstLiteralArgument(ASTPrimarySuffix primarySuffix) {
return getArgumentPrimaryPrefix(primarySuffix).getFirstChildOfType(ASTLiteral.class);
}
private JavaNode getFirstNameArgument(ASTPrimarySuffix primarySuffix) {
return getArgumentPrimaryPrefix(primarySuffix).getFirstChildOfType(ASTName.class);
}
private JavaNode getArgumentPrimaryPrefix(ASTPrimarySuffix primarySuffix) {
ASTArguments arguments = primarySuffix.getFirstChildOfType(ASTArguments.class);
ASTArgumentList argumentList = arguments.getFirstChildOfType(ASTArgumentList.class);
ASTExpression expression = argumentList.getFirstChildOfType(ASTExpression.class);
ASTPrimaryExpression primaryExpression = expression.getFirstChildOfType(ASTPrimaryExpression.class);
return primaryExpression.getFirstChildOfType(ASTPrimaryPrefix.class);
}
private boolean isStringLiteral(JavaNode node) {
if (node instanceof ASTLiteral) {
ASTLiteral literal = (ASTLiteral) node;
return literal.isStringLiteral();
}
return false;
}
private boolean isConstantString(JavaNode node) {
if (node instanceof ASTName) {
ASTName name = (ASTName) node;
ASTClassOrInterfaceBody classBody = name.getFirstParentOfType(ASTClassOrInterfaceBody.class);
ASTClassOrInterfaceBodyDeclaration classOrInterfaceBodyDeclaration = classBody.getFirstChildOfType(ASTClassOrInterfaceBodyDeclaration.class);
List<ASTFieldDeclaration> fieldDeclarations = classOrInterfaceBodyDeclaration.findChildrenOfType(ASTFieldDeclaration.class);
for (ASTFieldDeclaration fieldDeclaration : fieldDeclarations) {
ASTVariableDeclarator declaration = fieldDeclaration.getFirstChildOfType(ASTVariableDeclarator.class);
if (declaration.getName().equals(name.getImage())
&& String.class.equals(declaration.getType())
&& fieldDeclaration.isFinal()
&& fieldDeclaration.isStatic()) {
return true;
}
}
}
return false;
}
private boolean isNotWithinNullComparison(ASTPrimaryExpression node) {
return !isWithinNullComparison(node);
}
/*
* Expression/ConditionalAndExpression//EqualityExpression(@Image='!=']//NullLiteral
* Expression/ConditionalOrExpression//EqualityExpression(@Image='==']//NullLiteral
*/
private boolean isWithinNullComparison(ASTPrimaryExpression node) {
for (ASTExpression parentExpr : node.getParentsOfType(ASTExpression.class)) {
if (isNullComparison(parentExpr)) {
return true;
}
}
return false;
}
private boolean isNullComparison(ASTExpression expression) {
return isAndNotNullComparison(expression) || isOrNullComparison(expression);
}
private boolean isAndNotNullComparison(ASTExpression expression) {
ASTConditionalAndExpression andExpression = expression
.getFirstChildOfType(ASTConditionalAndExpression.class);
return andExpression != null && hasEqualityExpressionWithNullLiteral(andExpression, "!=");
}
private boolean isOrNullComparison(ASTExpression expression) {
ASTConditionalOrExpression orExpression = expression
.getFirstChildOfType(ASTConditionalOrExpression.class);
return orExpression != null && hasEqualityExpressionWithNullLiteral(orExpression, "==");
}
private void checkArgs(RuleContext ctx, ASTMethodCall call) {
ASTExpression arg = call.getArguments().get(0);
ASTExpression qualifier = call.getQualifier();
@ -56,4 +173,12 @@ public class LiteralsFirstInComparisonsRule extends AbstractJavaRulechainRule {
addViolation(ctx, call);
}
}
private boolean hasEqualityExpressionWithNullLiteral(JavaNode node, String equalityOp) {
ASTEqualityExpression equalityExpression = node.getFirstDescendantOfType(ASTEqualityExpression.class);
if (equalityExpression != null && equalityExpression.hasImageEqualTo(equalityOp)) {
return equalityExpression.hasDescendantOfType(ASTNullLiteral.class);
}
return false;
}
}

View File

@ -319,6 +319,7 @@ public class Foo {
}
]]></code>
</test-code>
<test-code>
<description>FN with unresolved types</description>
<expected-problems>2</expected-problems>
@ -332,6 +333,58 @@ class Foo {
assertTrue(hasMap.getMap().get("fi").equals("fum"));
assertTrue(hasMap.getMap().get("fa") == null);
}
}
]]></code>
</test-code>
<test-code>
<description>#575 LiteralsFirstInComparisons to consider constant fields, i.e. static final Strings</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Foo {
private static final String TEST_CONSTANT = "Test-Constant";
public boolean test(String someString) {
return someString.equals(TEST_CONSTANT);
}
}
]]></code>
</test-code>
<test-code>
<description>#575 LiteralsFirstInComparisons must not trigger if the field is not final</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
private static String TEST_CONSTANT = "Test-Constant";
public boolean test(String someString) {
return someString.equals(TEST_CONSTANT);
}
}
]]></code>
</test-code>
<test-code>
<description>#575 LiteralsFirstInComparisons must not trigger if the field is not static</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
private final String TEST_CONSTANT = "Test-Constant";
public boolean test(String someString) {
return someString.equals(TEST_CONSTANT);
}
}
]]></code>
</test-code>
<test-code>
<description>#575 LiteralsFirstInComparisons must not trigger if the constant field is not a String</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
private final Integer TEST_CONSTANT = 5;
public boolean test(String someString) {
return someString.equals(TEST_CONSTANT);
}
}
]]></code>
</test-code>