forked from phoedos/pmd
Merge branch 'master' into pmd/7.0.x
This commit is contained in:
commit
f0f2286f98
@ -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"
|
||||
}
|
||||
|
2
.github/workflows/pull-requests.yml
vendored
2
.github/workflows/pull-requests.yml
vendored
@ -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 ]
|
||||
|
@ -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>.
|
||||
|
||||
|
@ -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.")
|
||||
|
2
Gemfile
2
Gemfile
@ -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
|
||||
|
28
Gemfile.lock
28
Gemfile.lock
@ -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)
|
||||
|
||||
|
@ -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/>
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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)).
|
||||
|
@ -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 %}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@
|
||||
"description": "blah",
|
||||
"rule": "Foo",
|
||||
"ruleset": "RuleSet",
|
||||
"priority": 5
|
||||
"priority": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -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'
|
||||
;
|
||||
;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
/**/
|
||||
// the previous comment is an empty delimited comment and not a document comment
|
||||
class Foo { /// class X
|
||||
/* aaa
|
||||
|
||||
|
@ -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
|
||||
|
26
pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/csharp7And8Additions.cs
vendored
Normal file
26
pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/csharp7And8Additions.cs
vendored
Normal 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
|
||||
}
|
||||
}
|
155
pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/csharp7And8Additions.txt
vendored
Normal file
155
pmd-cs/src/test/resources/net/sourceforge/pmd/lang/cs/cpd/testdata/csharp7And8Additions.txt
vendored
Normal 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
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
Loading…
x
Reference in New Issue
Block a user