Merge branch 'master' into support-jrt-fs

This commit is contained in:
Andreas Dangel
2023-10-26 10:02:11 +02:00
953 changed files with 21725 additions and 16413 deletions

View File

@ -2153,7 +2153,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/11549103?v=4",
"profile": "https://github.com/cyw3",
"contributions": [
"bug"
"bug",
"doc"
]
},
{
@ -7153,7 +7154,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/111259588?v=4",
"profile": "https://github.com/nwcm",
"contributions": [
"doc"
"doc",
"bug"
]
},
{
@ -7192,6 +7194,90 @@
"contributions": [
"code"
]
},
{
"login": "krdabrowski",
"name": "Krystian Dabrowski",
"avatar_url": "https://avatars.githubusercontent.com/u/98942253?v=4",
"profile": "https://github.com/krdabrowski",
"contributions": [
"bug",
"code"
]
},
{
"login": "AndreyBozhko",
"name": "Andrey Bozhko",
"avatar_url": "https://avatars.githubusercontent.com/u/22246447?v=4",
"profile": "https://github.com/AndreyBozhko",
"contributions": [
"doc"
]
},
{
"login": "rcorfieldffdc",
"name": "Richard Corfield",
"avatar_url": "https://avatars.githubusercontent.com/u/42997936?v=4",
"profile": "https://github.com/rcorfieldffdc",
"contributions": [
"code"
]
},
{
"login": "m0rjc",
"name": "Richard Corfield",
"avatar_url": "https://avatars.githubusercontent.com/u/994206?v=4",
"profile": "https://github.com/m0rjc",
"contributions": [
"bug",
"code"
]
},
{
"login": "eant60",
"name": "eant60",
"avatar_url": "https://avatars.githubusercontent.com/u/41472980?v=4",
"profile": "https://github.com/eant60",
"contributions": [
"bug"
]
},
{
"login": "Marcono1234",
"name": "Marcono1234",
"avatar_url": "https://avatars.githubusercontent.com/u/11685886?v=4",
"profile": "https://github.com/Marcono1234",
"contributions": [
"bug"
]
},
{
"login": "eugenepugach",
"name": "eugenepugach",
"avatar_url": "https://avatars.githubusercontent.com/u/133967768?v=4",
"profile": "https://github.com/eugenepugach",
"contributions": [
"bug"
]
},
{
"login": "harbulot",
"name": "Bruno Harbulot",
"avatar_url": "https://avatars.githubusercontent.com/u/80994?v=4",
"profile": "http://blog.distributedmatter.net/",
"contributions": [
"bug"
]
},
{
"login": "shai-bennathan",
"name": "Shai Bennathan",
"avatar_url": "https://avatars.githubusercontent.com/u/62336907?v=4",
"profile": "https://github.com/shai-bennathan",
"contributions": [
"bug",
"code"
]
}
],
"contributorsPerLine": 7,

View File

@ -9,7 +9,7 @@ SCRIPT_INCLUDES="log.bash utils.bash setup-secrets.bash openjdk.bash maven.bash
source "$(dirname "$0")/inc/fetch_ci_scripts.bash" && fetch_ci_scripts
function build() {
pmd_ci_log_group_start "Prepare Java 8+11+17, Bundler"
pmd_ci_log_group_start "Prepare Java 8+11+17+21, Bundler"
pmd_ci_openjdk_install_adoptium 11
pmd_ci_openjdk_setdefault 11
PMD_MAVEN_EXTRA_OPTS=()
@ -18,7 +18,13 @@ function build() {
pmd_ci_openjdk_install_adoptium 8
pmd_ci_log_info "Install openjdk17 for integration tests and pmd-regression-tests"
pmd_ci_openjdk_install_adoptium 17
PMD_MAVEN_EXTRA_OPTS=(-Djava8.home="${HOME}/openjdk8" -Djava17.home="${HOME}/openjdk17")
pmd_ci_log_info "Install openjdk21 for integration tests and pmd-regression-tests"
pmd_ci_openjdk_install_adoptium 21
PMD_MAVEN_EXTRA_OPTS=(
-Djava8.home="${HOME}/openjdk8"
-Djava17.home="${HOME}/openjdk17"
-Djava21.home="${HOME}/openjdk21"
)
fi
pmd_ci_build_setup_bundler
pmd_ci_log_group_end
@ -100,7 +106,8 @@ function build() {
pmd_ci_build_and_upload_doc
pmd_ci_log_group_end
if pmd_ci_maven_isReleaseBuild; then
# release is published only for the case b) pmd-cli/pmd-dist release
if pmd_ci_maven_isReleaseBuild && [[ "${PMD_CI_TAG}" == *-dist ]]; then
pmd_ci_log_group_start "Publishing Release"
pmd_ci_gh_releases_publishRelease "$GH_RELEASE"
pmd_ci_sourceforge_selectDefault "${PMD_CI_MAVEN_PROJECT_VERSION}"
@ -108,10 +115,14 @@ function build() {
pmd_ci_log_group_end
fi
# create a baseline for snapshot builds (when pmd-dist is built)
# or for release builds for case b) when pmd-cli/pmd-dist is released
if pmd_ci_maven_isSnapshotBuild || [[ "${PMD_CI_TAG}" == *-dist ]]; then
pmd_ci_log_group_start "Creating new baseline for regression tester"
regression_tester_setup_ci
regression_tester_uploadBaseline
pmd_ci_log_group_end
fi
#
# everything from here runs only on snapshots, not on release builds
@ -130,7 +141,7 @@ function build() {
-Dpmd.skip \
--show-version --errors --batch-mode \
clean package \
sonar:sonar -Dsonar.login="${SONAR_TOKEN}" -Psonar
sonar:sonar -Dsonar.login="${SONAR_TOKEN}" -Psonar,cli-dist
pmd_ci_log_success "New sonar results: https://sonarcloud.io/dashboard?id=net.sourceforge.pmd%3Apmd"
pmd_ci_log_group_end
@ -146,7 +157,7 @@ function build() {
-DrepoToken="${COVERALLS_REPO_TOKEN}" \
--show-version --errors --batch-mode \
clean package jacoco:report \
coveralls:report -Pcoveralls
coveralls:report -Pcoveralls,cli-dist
pmd_ci_log_success "New coveralls result: https://coveralls.io/github/pmd/pmd"
pmd_ci_log_group_end
fi
@ -172,30 +183,58 @@ function pmd_ci_build_run() {
if pmd_ci_maven_isReleaseBuild; then
pmd_ci_log_info "This is a release build"
mvn_profiles="${mvn_profiles},pmd-release"
# There are two possible (release) builds:
if [[ "${PMD_CI_TAG}" != *-dist ]]; then
# a) pmd-core and languages modules
./mvnw clean deploy -P"${mvn_profiles}",'!cli-dist' --show-version --errors --batch-mode "${PMD_MAVEN_EXTRA_OPTS[@]}"
else
# b) pmd-cli and pmd-dist
./mvnw clean deploy -P"${mvn_profiles},cli-dist" -pl pmd-cli,pmd-dist --show-version --errors --batch-mode "${PMD_MAVEN_EXTRA_OPTS[@]}"
fi
else
pmd_ci_log_info "This is a snapshot build"
./mvnw clean deploy -P"${mvn_profiles},cli-dist" --show-version --errors --batch-mode "${PMD_MAVEN_EXTRA_OPTS[@]}"
fi
./mvnw clean deploy -P${mvn_profiles} --show-version --errors --batch-mode "${PMD_MAVEN_EXTRA_OPTS[@]}"
}
#
# Deploys the binary distribution
#
function pmd_ci_deploy_build_artifacts() {
# Deploy to sourceforge files https://sourceforge.net/projects/pmd/files/pmd/
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-bin.zip"
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-src.zip"
# Deploy SBOM
cp pmd-dist/target/bom.xml "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
cp pmd-dist/target/bom.json "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
if pmd_ci_maven_isSnapshotBuild; then
# Deploy to sourceforge files https://sourceforge.net/projects/pmd/files/pmd/
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-bin.zip"
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-src.zip"
# Deploy SBOM
cp pmd-dist/target/bom.xml "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
cp pmd-dist/target/bom.json "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
fi
if pmd_ci_maven_isReleaseBuild; then
# release build case a): only pmd-core and language modules released
if pmd_ci_maven_isReleaseBuild && [[ "${PMD_CI_TAG}" != *-dist ]]; then
# create a draft github release
pmd_ci_gh_releases_createDraftRelease "${PMD_CI_TAG}" "$(git rev-list -n 1 "${PMD_CI_TAG}")"
GH_RELEASE="$RESULT"
fi
# release build case b): pmd-cli and pmd-dist are released
if pmd_ci_maven_isReleaseBuild && [[ "${PMD_CI_TAG}" == *-dist ]]; then
# Deploy to sourceforge files https://sourceforge.net/projects/pmd/files/pmd/
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-bin.zip"
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-src.zip"
# Deploy SBOM
cp pmd-dist/target/bom.xml "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
cp pmd-dist/target/bom.json "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.xml"
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "pmd-dist/target/pmd-${PMD_CI_MAVEN_PROJECT_VERSION}-cyclonedx.json"
# draft release has already been created
pmd_ci_gh_releases_getLatestDraftRelease
GH_RELEASE="$RESULT"
# Deploy to github releases
pmd_ci_gh_releases_uploadAsset "$GH_RELEASE" "pmd-dist/target/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-bin.zip"
@ -215,7 +254,7 @@ function pmd_ci_build_and_upload_doc() {
pmd_doc_create_archive
pmd_ci_sourceforge_uploadFile "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "docs/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-doc.zip"
if pmd_ci_maven_isReleaseBuild; then
if pmd_ci_maven_isReleaseBuild && [[ "${PMD_CI_TAG}" != *-dist ]]; then
pmd_ci_gh_releases_uploadAsset "$GH_RELEASE" "docs/pmd-dist-${PMD_CI_MAVEN_PROJECT_VERSION}-doc.zip"
fi
@ -224,19 +263,21 @@ function pmd_ci_build_and_upload_doc() {
# Deploy javadoc to https://docs.pmd-code.org/apidocs/*/${PMD_CI_MAVEN_PROJECT_VERSION}/
pmd_code_uploadJavadoc "${PMD_CI_MAVEN_PROJECT_VERSION}" "$(pwd)"
# render release notes
# updating github release text
rm -f .bundle/config
bundle config set --local path vendor/bundle
bundle config set --local with release_notes_preprocessing
bundle install
# renders, and skips the first 6 lines - the Jekyll front-matter
local rendered_release_notes
rendered_release_notes=$(bundle exec docs/render_release_notes.rb docs/pages/release_notes.md | tail -n +6)
local release_name
release_name="PMD ${PMD_CI_MAVEN_PROJECT_VERSION} ($(date -u +%d-%B-%Y))"
# Upload to https://sourceforge.net/projects/pmd/files/pmd/${PMD_CI_MAVEN_PROJECT_VERSION}/ReadMe.md
pmd_ci_sourceforge_uploadReleaseNotes "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "${rendered_release_notes}"
if pmd_ci_maven_isSnapshotBuild || [[ "${PMD_CI_TAG}" != *-dist ]]; then
# render release notes
# updating github release text
rm -f .bundle/config
bundle config set --local path vendor/bundle
bundle config set --local with release_notes_preprocessing
bundle install
# renders, and skips the first 6 lines - the Jekyll front-matter
local rendered_release_notes
rendered_release_notes=$(bundle exec docs/render_release_notes.rb docs/pages/release_notes.md | tail -n +6)
local release_name
release_name="PMD ${PMD_CI_MAVEN_PROJECT_VERSION} ($(date -u +%d-%B-%Y))"
# Upload to https://sourceforge.net/projects/pmd/files/pmd/${PMD_CI_MAVEN_PROJECT_VERSION}/ReadMe.md
pmd_ci_sourceforge_uploadReleaseNotes "pmd/${PMD_CI_MAVEN_PROJECT_VERSION}" "${rendered_release_notes}"
fi
if pmd_ci_maven_isSnapshotBuild && [ "${PMD_CI_BRANCH}" = "master" ]; then
# only for snapshot builds from branch master: https://docs.pmd-code.org/snapshot -> pmd-doc-${PMD_CI_MAVEN_PROJECT_VERSION}
@ -248,7 +289,7 @@ function pmd_ci_build_and_upload_doc() {
pmd_ci_sourceforge_rsyncSnapshotDocumentation "${PMD_CI_MAVEN_PROJECT_VERSION}" "snapshot"
fi
if pmd_ci_maven_isReleaseBuild; then
if pmd_ci_maven_isReleaseBuild && [[ "${PMD_CI_TAG}" != *-dist ]]; then
# documentation is already uploaded to https://docs.pmd-code.org/pmd-doc-${PMD_CI_MAVEN_PROJECT_VERSION}
# we only need to setup symlinks for the released version
pmd_code_createSymlink "${PMD_CI_MAVEN_PROJECT_VERSION}" "latest"
@ -284,7 +325,7 @@ function pmd_ci_dogfood() {
sed -i 's/<version>[0-9]\{1,\}\.[0-9]\{1,\}\.[0-9]\{1,\}.*<\/version>\( *<!-- pmd.dogfood.version -->\)/<version>'"${PMD_CI_MAVEN_PROJECT_VERSION}"'<\/version>\1/' pom.xml
if [ "${PMD_CI_MAVEN_PROJECT_VERSION}" = "7.0.0-SNAPSHOT" ]; then
sed -i 's/pmd-dogfood-config\.xml/pmd-dogfood-config7.xml/' pom.xml
mpmdVersion=(-Denforcer.skip=true -Dpmd.plugin.version=3.21.1-pmd-7-SNAPSHOT)
mpmdVersion=(-Denforcer.skip=true -Dpmd.plugin.version=3.21.1-pmd-7.0.0-SNAPSHOT)
fi
./mvnw verify --show-version --errors --batch-mode "${PMD_MAVEN_EXTRA_OPTS[@]}" \
"${mpmdVersion[@]}" \

View File

@ -1,4 +1,4 @@
<?xml version="1.0"?>
<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="All Regression Rules"
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"

View File

@ -32,7 +32,7 @@ jobs:
os: [ ubuntu-latest, windows-latest, macos-latest ]
if: ${{ !contains(github.event.head_commit.message, '[skip ci]') }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 2
- uses: actions/cache@v3
@ -55,7 +55,7 @@ jobs:
run: |
echo "LANG=en_US.UTF-8" >> $GITHUB_ENV
echo "MAVEN_OPTS=-Daether.connector.http.connectionMaxTtl=180 -DautoReleaseAfterClose=true -DstagingProgressTimeoutMinutes=30" >> $GITHUB_ENV
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/master/scripts" >> $GITHUB_ENV
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/22/scripts" >> $GITHUB_ENV
- name: Check Environment
shell: bash
run: |

View File

@ -17,14 +17,14 @@ jobs:
runs-on: ubuntu-latest
continue-on-error: false
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 100
- name: Setup Environment
shell: bash
run: |
echo "LANG=en_US.UTF-8" >> $GITHUB_ENV
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/master/scripts" >> $GITHUB_ENV
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/22/scripts" >> $GITHUB_ENV
- name: Sync
run: .ci/git-repo-sync.sh
shell: bash

View File

@ -15,7 +15,7 @@ jobs:
os: [ ubuntu-latest ]
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: actions/cache@v3
with:
path: |
@ -36,7 +36,7 @@ jobs:
run: |
echo "LANG=en_US.UTF-8" >> $GITHUB_ENV
echo "MAVEN_OPTS=-Daether.connector.http.connectionMaxTtl=180 -DstagingProgressTimeoutMinutes=30" >> $GITHUB_ENV
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/master/scripts" >> $GITHUB_ENV
echo "PMD_CI_SCRIPTS_URL=https://raw.githubusercontent.com/pmd/build-tools/22/scripts" >> $GITHUB_ENV
- name: Check Environment
shell: bash
run: |

View File

@ -14,5 +14,5 @@
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.2/apache-maven-3.9.2-bin.zip
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.4/apache-maven-3.9.4-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar

View File

@ -51,18 +51,16 @@ def run_pmdtester
message2 = create_message
end
report_url = upload_report
tar_report
if report_url
message1 += "[Full report](#{report_url}/diff1/index.html)"
message1 += "[Download full report as build artifact](#{ENV['PMD_CI_JOB_URL']})"
# set value of sticky to true and the message is kept after new commits are submitted to the PR
message(message1, sticky: true)
if message2
message2 += "[Download full report as build artifact](#{ENV['PMD_CI_JOB_URL']})"
# set value of sticky to true and the message is kept after new commits are submitted to the PR
message(message1, sticky: true)
if message2
message2 += "[Full report](#{report_url}/diff2/index.html)"
# set value of sticky to true and the message is kept after new commits are submitted to the PR
message(message2, sticky: true)
end
message(message2, sticky: true)
end
rescue StandardError => e
@ -84,23 +82,13 @@ def create_message
"#{@summary[:configerrors][:removed]} configuration errors.\n"
end
def upload_report
def tar_report
Dir.chdir('target') do
tar_filename = "pr-#{ENV['PMD_CI_PULL_REQUEST_NUMBER']}-diff-report-#{Time.now.strftime("%Y-%m-%dT%H-%M-%SZ")}.tar.gz"
`tar czf #{tar_filename} diff1/ diff2/`
tar_size = (10 * File.size(tar_filename) / 1024 / 1024)/10.0
@logger.info "Uploading file #{tar_filename} (#{tar_size}mb) now..."
report_url = `curl -u #{ENV['PMD_CI_CHUNK_TOKEN']} -T #{tar_filename} https://chunk.io`
if $?.success?
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.")
nil
end
@logger.info "Created file #{tar_filename} (#{tar_size}mb)"
end
end

View File

@ -1,8 +1,9 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.8.4)
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
base64 (0.1.1)
claide (1.1.0)
claide-plugins (0.9.2)
cork
@ -12,23 +13,24 @@ GEM
concurrent-ruby (1.2.2)
cork (0.3.0)
colored2 (~> 3.1)
danger (9.2.0)
danger (9.3.2)
claide (~> 1.0)
claide-plugins (>= 0.9.2)
colored2 (~> 3.1)
cork (~> 0.1)
faraday (>= 0.9.0, < 3.0)
faraday-http-cache (~> 2.0)
git (~> 1.7)
git (~> 1.13)
kramdown (~> 2.3)
kramdown-parser-gfm (~> 1.0)
no_proxy_fix
octokit (~> 5.0)
octokit (~> 6.0)
terminal-table (>= 1, < 4)
differ (0.1.2)
et-orbi (1.2.7)
tzinfo
faraday (2.7.5)
faraday (2.7.11)
base64
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-http-cache (2.5.0)
@ -46,13 +48,13 @@ GEM
kramdown (~> 2.0)
liquid (5.4.0)
logger-colors (1.0.0)
mini_portile2 (2.8.2)
mini_portile2 (2.8.4)
nap (1.1.0)
no_proxy_fix (0.1.2)
nokogiri (1.15.2)
nokogiri (1.15.4)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
octokit (5.6.1)
octokit (6.1.1)
faraday (>= 1, < 3)
sawyer (~> 0.9)
open4 (1.3.4)
@ -63,14 +65,14 @@ GEM
nokogiri (~> 1.13)
rufus-scheduler (~> 3.8)
slop (~> 4.9)
public_suffix (5.0.1)
public_suffix (5.0.3)
raabro (1.4.0)
racc (1.6.2)
racc (1.7.1)
rchardet (1.8.0)
rexml (3.2.5)
rouge (4.1.1)
rexml (3.2.6)
rouge (4.1.3)
ruby2_keywords (0.0.5)
rufus-scheduler (3.8.2)
rufus-scheduler (3.9.1)
fugit (~> 1.1, >= 1.1.6)
safe_yaml (1.0.5)
sawyer (0.9.2)

View File

@ -22,7 +22,8 @@ Scala is supported, but there are currently no Scala rules available.
Additionally, it includes **CPD**, the copy-paste-detector. CPD finds duplicated code in
C/C++, C#, Dart, Fortran, Gherkin, Go, Groovy, HTML, Java, JavaScript, JSP, Kotlin, Lua, Matlab, Modelica,
Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex and Visualforce, Scala, Swift, T-SQL and XML.
Objective-C, Perl, PHP, PLSQL, Python, Ruby, Salesforce.com Apex and Visualforce, Scala, Swift, T-SQL,
Apache Velocity, and XML.
In the future we hope to add support for data/control flow analysis and automatic (quick) fixes where
it makes sense.

View File

@ -101,8 +101,8 @@ echo " the new release based on the release notes. Also add any deprecated ru
echo
echo "* Update **../pmd.github.io/_config.yml** to mention the new release"
echo
echo "* Update property \`pmd-designer.version\` in **pom.xml** to reference the latest pmd-designer release"
echo " See <https://search.maven.org/search?q=g:net.sourceforge.pmd%20AND%20a:pmd-ui&core=gav> for the available releases."
echo "* Update property \`pmd-designer.version\` in **pom.xml** to reference the version, that will be released"
echo " later in this process."
echo
echo "Press enter to continue..."
read -r
@ -170,8 +170,8 @@ git commit -a -m "Prepare pmd release ${RELEASE_VERSION}"
-DreleaseVersion="${RELEASE_VERSION}" \
-DdevelopmentVersion="${DEVELOPMENT_VERSION}" \
-DscmCommentPrefix="[release] " \
-Pgenerate-rule-docs
-Darguments='-Pgenerate-rule-docs,!cli-dist' \
'-Pgenerate-rule-docs,!cli-dist'
echo
echo "Tag has been pushed.... now check github actions: <https://github.com/pmd/pmd/actions>"
@ -235,14 +235,46 @@ EOF
git commit -a -m "Prepare next development version [skip ci]"
git push origin "${CURRENT_BRANCH}"
./mvnw -B release:clean
echo
echo
echo
echo "* Wait until the new version is synced to maven central and appears as latest version in"
echo " <https://repo.maven.apache.org/maven2/net/sourceforge/pmd/pmd/maven-metadata.xml>."
echo
echo
echo "Then proceed with releasing pmd-designer..."
echo "<https://github.com/pmd/pmd-designer/blob/master/releasing.md>"
echo
echo "Press enter to continue when pmd-designer is available in maven-central..."
echo "<https://repo.maven.apache.org/maven2/net/sourceforge/pmd/pmd-ui/maven-metadata.xml>."
read -r
echo
echo "Continuing with release of pmd-cli and pmd-dist..."
git checkout "pmd_releases/${RELEASE_VERSION}"
./mvnw versions:update-parent -DparentVersion="${RELEASE_VERSION}" -DskipResolution=true -DgenerateBackupPoms=false -pl pmd-cli,pmd-dist
git add pmd-cli/pom.xml pmd-dist/pom.xml
git commit -m "[release] prepare release pmd_releases/${RELEASE_VERSION}-dist"
git tag -m "[release] copy for tag pmd_releases/${RELEASE_VERSION}-dist" "pmd_releases/${RELEASE_VERSION}-dist"
git push origin tag "pmd_releases/${RELEASE_VERSION}-dist"
git checkout master
# make sure parent reference is correct
./mvnw versions:update-parent -DparentVersion="${DEVELOPMENT_VERSION}" -DskipResolution=true -DgenerateBackupPoms=false -pl pmd-cli,pmd-dist
git add pmd-cli/pom.xml pmd-dist/pom.xml
changes=$(git status --porcelain 2>/dev/null | grep -c -E "^[AMDRC]" || true)
if [ "$changes" -gt 0 ]; then
git commit -m "Prepare next development version [skip ci]"
git push origin "${CURRENT_BRANCH}"
fi
echo
echo "Second tag 'pmd_releases/${RELEASE_VERSION}-dist' has been pushed ... now check github actions: <https://github.com/pmd/pmd/actions>"
echo
echo
echo "Verify the new release on github: <https://github.com/pmd/pmd/releases/tag/pmd_releases/${RELEASE_VERSION}>"
echo "and the news entry at <https://sourceforge.net/p/pmd/news/>"
echo
echo "* Wait until the new version is synced to maven central and appears as latest version in"
echo " <https://repo.maven.apache.org/maven2/net/sourceforge/pmd/pmd/maven-metadata.xml>."
echo "* Send out an announcement mail to the mailing list:"
echo
echo "To: PMD Developers List <pmd-devel@lists.sourceforge.net>"

View File

@ -1,19 +1,20 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (7.0.5)
activesupport (7.0.8)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
addressable (2.8.4)
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
base64 (0.1.1)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.11.1)
colorator (1.1.0)
commonmarker (0.23.9)
commonmarker (0.23.10)
concurrent-ruby (1.2.2)
dnsruby (1.70.0)
simpleidn (~> 0.2.1)
@ -23,12 +24,13 @@ GEM
ethon (0.16.0)
ffi (>= 1.15.0)
eventmachine (1.2.7)
execjs (2.8.1)
faraday (2.7.5)
execjs (2.9.1)
faraday (2.7.11)
base64
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-net_http (3.0.2)
ffi (1.15.5)
ffi (1.16.2)
forwardable-extended (2.6.0)
gemoji (3.0.1)
github-pages (228)
@ -86,7 +88,7 @@ GEM
activesupport (>= 2)
nokogiri (>= 1.4)
http_parser.rb (0.8.0)
i18n (1.13.0)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
jekyll (3.9.3)
addressable (~> 2.4)
@ -205,13 +207,13 @@ GEM
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
mercenary (0.3.6)
mini_portile2 (2.8.2)
mini_portile2 (2.8.4)
minima (2.5.1)
jekyll (>= 3.5, < 5.0)
jekyll-feed (~> 0.9)
jekyll-seo-tag (~> 2.1)
minitest (5.18.0)
nokogiri (1.15.2)
minitest (5.20.0)
nokogiri (1.15.4)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
octokit (4.25.1)
@ -220,11 +222,11 @@ GEM
pathutil (0.16.2)
forwardable-extended (~> 2.6)
public_suffix (4.0.7)
racc (1.6.2)
racc (1.7.1)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
ffi (~> 1.0)
rexml (3.2.5)
rexml (3.2.6)
rouge (3.26.0)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)

View File

@ -3,7 +3,7 @@ repository: pmd/pmd
pmd:
version: 7.0.0-SNAPSHOT
previous_version: 6.55.0
date: 27-June-2023
date: ??-?????-2023
release_type: major
# release types: major, minor, bugfix

View File

@ -34,6 +34,9 @@ entries:
- title: User Documentation
output: web, pdf
folderitems:
- title: Migration Guide for PMD 7
url: /pmd_userdocs_migrating_to_pmd7.html
output: web, pdf
- title: Installation and basic CLI usage
url: /pmd_userdocs_installation.html
output: web, pdf
@ -121,6 +124,9 @@ entries:
- title: PMD Java API
output: web, pdf
url: /pmd_userdocs_tools_java_api.html
- title: bld PMD Extension
output: web, pdf
url: /pmd_userdocs_tools_bld.html
- title: CI integrations
output: web, pdf
url: /pmd_userdocs_tools_ci.html
@ -310,7 +316,7 @@ entries:
- title: null
output: web, pdf
subfolders:
- title: Salesforce VisualForce Rules
- title: Salesforce Visualforce Rules
output: web, pdf
subfolderitems:
- title: Index
@ -346,7 +352,7 @@ entries:
- title: null
output: web, pdf
subfolders:
- title: VM Rules
- title: Velocity Template Language (VTL) Rules
output: web, pdf
subfolderitems:
- title: Index
@ -379,6 +385,9 @@ entries:
- title: Index
output: web, pdf
url: /pmd_rules_xml.html
- title: Best Practices
output: web, pdf
url: /pmd_rules_xml_bestpractices.html
- title: Error Prone
output: web, pdf
url: /pmd_rules_xml_errorprone.html
@ -400,12 +409,41 @@ entries:
- title: Language-Specific Documentation
output: web, pdf
folderitems:
- title: Overview
url: /pmd_languages_index.html
output: web, pdf
- title: Language configuration
url: /pmd_languages_configuration.html
output: web, pdf
- title: Apex
url: /pmd_languages_apex.html
output: web, pdf
- title: C/C++
url: /pmd_languages_cpp.html
output: web, pdf
- title: C#
url: /pmd_languages_cs.html
output: web, pdf
- title: Coco
url: /pmd_languages_coco.html
output: web, pdf
- title: Dart
url: /pmd_languages_dart.html
output: web, pdf
- title: Fortran
url: /pmd_languages_fortran.html
output: web, pdf
- title: Gherkin
url: /pmd_languages_gherkin.html
output: web, pdf
- title: Go
url: /pmd_languages_go.html
output: web, pdf
- title: Groovy
url: /pmd_languages_groovy.html
- title: HTML
url: /pmd_languages_html.html
output: web, pdf
- title: Java
url: /pmd_languages_java.html
output: web, pdf
@ -415,30 +453,57 @@ entries:
- title: JSP
url: /pmd_languages_jsp.html
output: web, pdf
- title: Julia
url: /pmd_languages_julia.html
output: web, pdf
- title: Kotlin
url: /pmd_languages_kotlin.html
output: web, pdf
- title: Lua
url: /pmd_languages_lua.html
output: web, pdf
- title: Matlab
url: /pmd_languages_matlab.html
output: web, pdf
- title: Modelica
url: /pmd_languages_modelica.html
output: web, pdf
- title: Objective-C
url: /pmd_languages_objectivec.html
output: web, pdf
- title: Perl
url: /pmd_languages_perl.html
output: web, pdf
- title: PHP
url: /pmd_languages_php.html
output: web, pdf
- title: PLSQL
url: /pmd_languages_plsql.html
output: web, pdf
- title: Python
url: /pmd_languages_python.html
output: web, pdf
- title: Ruby
url: /pmd_languages_ruby.html
output: web, pdf
- title: Scala
url: /pmd_languages_scala.html
output: web, pdf
- title: Swift
url: /pmd_languages_swift.html
output: web, pdf
- title: T-SQL
url: /pmd_languages_tsql.html
output: web, pdf
- title: Visualforce
url: /pmd_languages_visualforce.html
output: web, pdf
- title: Velocity Template Language (VTL)
url: /pmd_languages_vm.html
output: web, pdf
- title: XML and XML dialects
url: /pmd_languages_xml.html
output: web, pdf
- title: HTML
url: /pmd_languages_html.html
output: web, pdf
- title: Gherkin
url: /pmd_languages_gherkin.html
output: web, pdf
- title: Julia
url: /pmd_languages_julia.html
output: web, pdf
- title: Coco
url: /pmd_languages_coco.html
output: web, pdf
- title: Developer Documentation
output: web, pdf
folderitems:
@ -490,6 +555,9 @@ entries:
- title: Creating (XML) dump of the AST
url: /pmd_devdocs_experimental_ast_dump.html
output: web, pdf
- title: List of experimental Features
url: /tag_experimental.html
output: web, pdf
- title: Project documentation
output: web, pdf
folderitems:

View File

@ -10,3 +10,6 @@ allowed-tags:
- tools # About tools and integrations, Maven, gradle, etc.
- devdocs # About PMD internals, contributing, building, projects
- languages # Language-specific documentation pages
- PmdCapableLanguage
- CpdCapableLanguage
- experimental

View File

@ -0,0 +1,12 @@
<details class="language-info">
<summary>Language Info for {{include.name}}</summary>
<div class="card">
<ul class="list-group list-group-flush">
{% if include.since %}<li class="list-group-item">Since PMD {{include.since}}</li>{% endif %}
<li class="list-group-item">Implementation: {% jdoc include.implementation %}</li>
<li class="list-group-item">Id: {{include.id}}</li>
<li class="list-group-item">PMD: {% if include.supports_pmd %}✔️{% else %}❌{% endif %}</li>
<li class="list-group-item">CPD: {% if include.supports_cpd %}✔️{% else %}❌{% endif %}</li>
</ul>
</div>
</details>

View File

@ -13,7 +13,10 @@ layout: default
{% if page.summary %}
<div class="summary">{{page.summary}}</div>
{% endif %}
<div id="inline-toc"><!-- empty, move TOC here when screen size too small --></div>
<details id="inline-toc-details">
<summary>Table of Contents</summary>
<div id="inline-toc"><!-- empty, move TOC here when screen size too small --></div>
</details>
{{content}}

View File

@ -106,16 +106,25 @@ class JavadocTag < Liquid::Tag
def initialize(tag_name, doc_ref, tokens)
super
# sanitize a little
doc_ref.delete! " \"'"
@doc_ref = doc_ref
end
arr = doc_ref.split("#") # split into fqcn + member suffix
def render(var_ctx)
# maybe the parameter is actually a variable - try to resolve it first
if var_ctx.key?(@doc_ref)
@doc_ref = var_ctx[@doc_ref]
end
# sanitize a little
@doc_ref.delete! " \"'"
arr = @doc_ref.split("#") # split into fqcn + member suffix
@type_fqcn = arr[0]
@member_suffix = arr[1] || "" # default to empty string
unless Regexp.new('(!\w*!)?' + Regexp.union(JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX, JDocNamespaceDeclaration::SYM_REGEX).source ) =~ @type_fqcn
fail "Wrong syntax for type reference, expected eg nspace::a.b.C, !opts!nspace::a.b.C, or :nspace"
fail "Wrong syntax for type reference, expected eg nspace::a.b.C, !opts!nspace::a.b.C, or :nspace, but got \'" + @type_fqcn + "\'"
end
# If no options, then split produces [@type_fqcn]
@ -130,14 +139,11 @@ class JavadocTag < Liquid::Tag
elsif tag_name == "jdoc_old"
@use_previous_api_version = true
end
end
def render(var_ctx)
artifact_name, @type_fqcn = JDocNamespaceDeclaration::parse_fqcn(@type_fqcn, var_ctx)
resolved_type = JavadocTag::fqcn_type(artifact_name, @type_fqcn)
JavadocTag::diagnose(artifact_name, @type_fqcn, @is_package_ref, resolved_type)
diagnose(var_ctx, artifact_name, @type_fqcn, @is_package_ref, resolved_type)
# Expand FQCN of arguments
@member_suffix.gsub!(JDocNamespaceDeclaration::NAMESPACED_FQCN_REGEX) {|fqcn| JDocNamespaceDeclaration::parse_fqcn(fqcn, var_ctx)[1]}
@ -215,15 +221,18 @@ class JavadocTag < Liquid::Tag
BASE_PMD_DIR = File.join(File.expand_path(File.dirname(__FILE__)), "..", "..")
def self.diagnose(artifact_id, fqcn, expect_package, resolved_type)
def diagnose(context, artifact_id, fqcn, expect_package, resolved_type)
tag_name= expect_package ? "jdoc_package" : "jdoc"
# Note: the line numbers don't account for the frontmatter lines
# See https://github.com/jekyll/jekyll/issues/7192 and https://github.com/jekyll/jekyll/pull/9385
location = "#{context['page']['path']}:#{@line_number}+?"
if resolved_type == :package && !expect_package
warn "\e[33;1m#{tag_name} generated link to #{fqcn}, but it was found to be a package name. Did you mean to use jdoc_package instead of jdoc?\e[0m"
warn "\e[33;1m#{location}: #{tag_name} generated link to #{fqcn}, but it was found to be a package name. Did you mean to use jdoc_package instead of jdoc?\e[0m"
elsif resolved_type == :file && expect_package
warn "\e[33;1m#{tag_name} generated link to #{fqcn}, but it was found to be a java file name. Did you mean to use jdoc instead of jdoc_package?\e[0m"
warn "\e[33;1m#{location}: #{tag_name} generated link to #{fqcn}, but it was found to be a java file name. Did you mean to use jdoc instead of jdoc_package?\e[0m"
elsif !resolved_type
warn "\e[33;1m#{tag_name} generated link to #{fqcn}, but the #{expect_package ? "directory" : "source file"} couldn't be found in the source tree of #{artifact_id}\e[0m"
warn "\e[33;1m#{location}: #{tag_name} generated link to #{fqcn}, but the #{expect_package ? "directory" : "source file"} couldn't be found in the source tree of #{artifact_id}\e[0m"
end
end

View File

@ -99,10 +99,11 @@ class JDocNamespaceDeclaration < Liquid::Tag
private
JDOC_NAMESPACE_MAP = "jdoc_nspaces"
RESERVED_NSPACES = ['ant', 'apex', 'core', 'cpp', 'cs', 'dart', 'dist', 'doc', 'fortran', 'go', 'groovy', 'java',
'javascript', 'jsp',
'kotlin', 'lua', 'matlab', 'objectivec', 'perl', 'php', 'plsql', 'python', 'ruby', 'scala', 'swift',
'test', 'test-schema', 'ui',
RESERVED_NSPACES = ['ant', 'apex', 'cli', 'coco', 'core', 'cpp', 'cs', 'dart', 'dist', 'doc',
'fortran', 'gherkin', 'go', 'groovy', 'html', 'java',
'javascript', 'jsp', 'julia',
'kotlin', 'lang-test', 'lua', 'matlab', 'objectivec', 'perl', 'php', 'plsql', 'python', 'ruby', 'scala', 'swift',
'test', 'test-schema', 'tsql', 'ui',
'modelica', 'visualforce', 'vm', 'xml'].flat_map {|m| [m, "pmd-" + m]}
def self.make_base_namespaces

View File

@ -1007,9 +1007,12 @@ span.soft {
}
}
@media (max-width: 990px) {
@media (min-height: 600px) and (min-width: 990px) {
/* sticky sidebar for big screens */
#mysidebar {
position: relative;
position: fixed !important;
overflow: scroll;
height: 80%;
}
}
@ -1025,6 +1028,15 @@ span.soft {
}
}
#inline-toc-details {
display: none;
}
@media (max-width: 1350px) {
#inline-toc-details {
display: block;
}
}
.col-md-9 img {
max-width: 100%;
max-height: 100%;
@ -1259,3 +1271,7 @@ h4.panel-title {
a.edit-header {
font-size: 15px;
}
.language-info {
margin: 2em;
}

View File

@ -87,3 +87,10 @@ li.sidebarTitle {
margin-bottom:2.5px;
margin-left:5px;
}
blockquote {
border-left: 5px solid #01c172;
padding: 10px 0 10px 1rem;
margin: 1rem 0;
font-style: italic;
}

View File

@ -17,17 +17,6 @@ $(document).ready(function () {
headers: 'h2,h3,h4',
});
$('#mysidebar').height($(".nav").height());
// this script says, if the height of the viewport is greater than 600px, then insert position-fixed class,
// which makes the nav bar float in a fixed position as your scroll. If you have a lot of nav items,
// this height may not work for you.
var h = $(window).height();
//console.log (h);
if (h > 600) {
$( '#mysidebar' ).attr('class', 'nav position-fixed');
}
// activate tooltips. although this is a bootstrap js function, it must be activated this way in your theme.
$('[data-toggle="tooltip"]').tooltip({
placement: 'top',

View File

@ -56,8 +56,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
* Make sure to add your new module to PMD's parent pom as `<module>` entry, so that it is built alongside the
other languages.
* Also add your new module to the dependencies list in "pmd-languages-deps/pom.xml", so that the new language
is automatically available in the binary distribution (pmd-dist) as well as for the shell-completion
in the pmd-cli module.
is automatically available in the binary distribution (pmd-dist).
## 2. Implement an AST parser for your language
@ -120,13 +119,13 @@ definitely don't come for free. It is much effort and requires perseverance to i
* This is needed to support CPD (copy paste detection)
* We provide a default implementation using [`AntlrTokenManager`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/AntlrTokenizer.java).
* You must create your own "AntlrTokenizer" such as we do with
[`SwiftTokenizer`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/cpd/SwiftTokenizer.java).
[`SwiftTokenizer`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/cpd/SwiftTokenizer.java).
* If you wish to filter specific tokens (e.g. comments to support CPD suppression via "CPD-OFF" and "CPD-ON")
you can create your own implementation of
[`AntlrTokenFilter`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/AntlrTokenFilter.java).
[`AntlrTokenFilter`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/AntlrTokenFilter.java).
You'll need to override then the protected method `getTokenFilter(AntlrTokenManager)`
and return your custom filter. See the tokenizer for C# as an exmaple:
[`CsTokenizer`](https://github.com/pmd/pmd/blob/master/pmd-cs/src/main/java/net/sourceforge/pmd/cpd/CsTokenizer.java).
[`CsTokenizer`](https://github.com/pmd/pmd/blob/master/pmd-cs/src/main/java/net/sourceforge/pmd/lang/cs/cpd/CsTokenizer.java).
If you don't need a custom token filter, you don't need to override the method. It returns the default
`AntlrTokenFilter` which doesn't filter anything.
@ -143,7 +142,9 @@ definitely don't come for free. It is much effort and requires perseverance to i
* For a minimal implementation, it just needs to return a parser *(see step #6)*.
* It can be used to provide other features for your language like
* violation suppression logic
* violation decorators, to add additional language specific information to the created violations
* {% jdoc core::reporting::ViolationDecorator %}s, to add additional language specific information to the
created violations. The [Java language module](pmd_languages_java.html#violation-decorators) uses this to
provide the method name or class name, where the violation occurred.
* metrics
* custom XPath functions
@ -169,7 +170,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
## 10. Create an abstract rule class for the language
* You need to create your own abstract rule class in order to interface your language with PMD's generic rule
execution.
* See [`AbstractSwiftRule`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/AbstractSwiftRule.java) as an example.
* See [`AbstractSwiftRule`](https://github.com/pmd/pmd/blob/master/pmd-swift/src/main/java/net/sourceforge/pmd/lang/swift/rule/AbstractSwiftRule.java) as an example.
* The rule basically just extends
[`AbstractVisitorRule`](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/lang/rule/AbstractVisitorRule.java)
and only redefines the abstract `buildVisitor()` method to return our own type of visitor.
@ -229,3 +230,25 @@ definitely don't come for free. It is much effort and requires perseverance to i
This will load all rulesets and verify, that all required attributes are provided.
*Note:* You'll need to add your ruleset to `categories.properties`, so that it can be found.
### 15. Create documentation page
Finishing up your new language module by adding a page in the documentation. Create a new markdown file
`<langId>.md` in `docs/pages/pmd/languages/`. This file should have the following frontmatter:
```
---
title: <Language Name>
permalink: pmd_languages_<langId>.html
last_updated: <Month> <Year> (<PMD Version>)
tags: [languages, PmdCapableLanguage, CpdCapableLanguage]
---
```
On this page, language specifics can be documented, e.g. when the language was first supported by PMD.
There is also the following Jekyll Include, that creates summary box for the language:
```
{% raw %}
{% include language_info.html name='<Language Name>' id='<langId>' implementation='<langId>::lang.<langId>.<langId>LanguageModule' supports_cpd=true supports_pmd=true %}
{% endraw %}
```

View File

@ -33,22 +33,22 @@ definitely don't come for free. It is much effort and requires perseverance to i
" %}
## Steps
## 1. Start with a new sub-module
### 1. Start with a new sub-module
* See pmd-java or pmd-vm for examples.
* Make sure to add your new module to PMD's parent pom as `<module>` entry, so that it is built alongside the
other languages.
* Also add your new module to the dependencies list in "pmd-languages-deps/pom.xml", so that the new language
is automatically available in the binary distribution (pmd-dist) as well as for the shell-completion
in the pmd-cli module.
is automatically available in the binary distribution (pmd-dist).
## 2. Implement an AST parser for your language
### 2. Implement an AST parser for your language
* Ideally an AST parser should be implemented as a JJT file *(see VmParser.jjt or Java.jjt for example)*
* There is nothing preventing any other parser implementation, as long as you have some way to convert an input
stream into an AST tree. Doing it as a JJT simplifies maintenance down the road.
* See this link for reference: [https://javacc.java.net/doc/JJTree.html](https://javacc.java.net/doc/JJTree.html)
## 3. Create AST node classes
### 3. Create AST node classes
* For each AST node that your parser can generate, there should be a class
* The name of the AST class should be “AST” + “whatever is the name of the node in JJT file”.
* For example, if JJT contains a node called “IfStatement”, there should be a class called “ASTIfStatement”
@ -57,7 +57,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
creation later. *(see SimpleNode for Velocity and AbstractJavaNode for Java for example)*
* Note: These AST node classes are generated usually once by javacc/jjtree and can then be modified as needed.
## 4. Generate your parser (using JJT)
### 4. Generate your parser (using JJT)
* An ant script is being used to compile jjt files into classes. This is in `javacc-wrapper.xml` file in the
top-level pmd sources.
* The ant script is executed via the `maven-antrun-plugin`. Add this plugin to your `pom.xml` file and configure
@ -65,7 +65,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
* The ant script is called in the phase `generate-sources` whenever the whole project is built. But you can
call `./mvnw generate-sources` directly for your module if you want your parser to be generated.
## 5. Create a PMD parser “adapter”
### 5. Create a PMD parser “adapter”
* Create a new class that extends `JjtreeParserAdapter`.
* This is a generic class, and you need to declare the root AST node.
* There are two important methods to implement
@ -75,18 +75,20 @@ definitely don't come for free. It is much effort and requires perseverance to i
* `parseImpl` method should return the root node of the AST tree obtained by parsing the CharStream source
* See `VmParser` class as an example
## 6. Create a language version handler
### 6. Create a language version handler
* Extend `AbstractPmdLanguageVersionHandler` *(see VmHandler for example)*
* This class is sort of a gateway between PMD and all parsing logic specific to your language.
* For a minimal implementation, it just needs to return a parser *(see step #5)*.
* It can be used to provide other features for your language like
* violation suppression logic
* violation decorators, to add additional language specific information to the created violations
* {% jdoc core::reporting::ViolationDecorator %}s, to add additional language specific information to the
created violations. The [Java language module](pmd_languages_java.html#violation-decorators) uses this to
provide the method name or class name, where the violation occurred.
* metrics (see below "Optional features")
* custom XPath functions
* See `VmHandler` class as an example
## 7. Create a base visitor
### 7. Create a base visitor
* A parser visitor adapter is not needed anymore with PMD 7. The visitor interface now provides a default
implementation.
* The visitor for JavaCC based AST is generated along the parser from the grammar file. The
@ -95,7 +97,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
* In order to help use this visitor later on, a base visitor class should be created.
See `VmVisitorBase` as an example.
## 8. Make PMD recognize your language
### 8. Make PMD recognize your language
* Create your own subclass of `net.sourceforge.pmd.lang.impl.SimpleLanguageModuleBase`. *(see VmLanguageModule or
JavaLanguageModule as an example)*
* Add for each version of your language a call to `addVersion` in your language modules constructor.
@ -104,7 +106,7 @@ definitely don't come for free. It is much effort and requires perseverance to i
* Create the service registration via the text file `src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language`.
Add your fully qualified class name as a single line into it.
## 9. Add AST regression tests
### 9. Add AST regression tests
For languages, that use an external library for parsing, the AST can easily change when upgrading the library.
Also for languages, where we have the grammar under our control, it is useful to have such tests.
@ -151,19 +153,19 @@ The Scala module also has a test, written in Kotlin instead of Java:
`net.sourceforge.pmd.lang.scala.ast.ScalaParserTests`.
## 10. Create an abstract rule class for the language
### 10. Create an abstract rule class for the language
* Extend `AbstractRule` and implement the parser visitor interface for your language *(see AbstractVmRule for example)*
* All other rules for your language should extend this class. The purpose of this class is to implement visit
methods for all AST types to simply delegate to default behavior. This is useful because most rules care only
about specific AST nodes, but PMD needs to know what to do with each node - so this just lets you use default
behavior for nodes you dont care about.
## 11. Create rules
### 11. Create rules
* Rules are created by extending the abstract rule class created in step 9 *(see `EmptyForeachStmtRule` for example)*
* Creating rules is already pretty well documented in PMD - and its no different for a new language,
except you may have different AST nodes.
## 12. Test the rules
### 12. Test the rules
* Testing rules is described in depth in [Testing your rules](pmd_userdocs_extending_testing.html).
* Each rule has its own test class: Create a test class for your rule extending `PmdRuleTst`
*(see AvoidReassigningParametersTest in pmd-vm for example)*
@ -181,6 +183,29 @@ The Scala module also has a test, written in Kotlin instead of Java:
*Note:* You'll need to add your category ruleset to `categories.properties`, so that it can be found.
### 13. Create documentation page
Finishing up your new language module by adding a page in the documentation. Create a new markdown file
`<langId>.md` in `docs/pages/pmd/languages/`. This file should have the following frontmatter:
```
---
title: <Language Name>
permalink: pmd_languages_<langId>.html
last_updated: <Month> <Year> (<PMD Version>)
tags: [languages, PmdCapableLanguage, CpdCapableLanguage]
---
```
On this page, language specifics can be documented, e.g. when the language was first supported by PMD.
There is also the following Jekyll Include, that creates summary box for the language:
```
{% raw %}
{% include language_info.html name='<Language Name>' id='<langId>' implementation='<langId>::lang.<langId>.<langId>LanguageModule' supports_cpd=true supports_pmd=true %}
{% endraw %}
```
## Debugging with Rule Designer
When implementing your grammar it may be very useful to see how PMD parses your example files.
@ -193,9 +218,9 @@ This can be achieved with Rule Designer:
* Register it in the `AvailableSyntaxHighlighters` enumeration.
* Now build your implementation and place the `target/pmd-ui-<version>-SNAPSHOT.jar` to the `lib` directory inside your `pmd-bin-...` distribution (you have to delete old `pmd-ui-*.jar` from there).
# Optional features
## Optional features
## Metrics
### Metrics
If you want to add support for computing metrics:
* Create a package `lang.<langname>.metrics`

View File

@ -1,106 +1,133 @@
---
title: How to add a new CPD language
short_title: Add a new CPD language
short_title: Adding a new CPD language
tags: [devdocs, extending]
summary: How to add a new CPD language
last_updated: March 18, 2019 (6.13.0)
summary: How to add a new language module with CPD support.
last_updated: April 2023 (7.0.0)
permalink: pmd_devdocs_major_adding_new_cpd_language.html
author: Matías Fraga <fragamati@gmail.com>
author: Matías Fraga, Clément Fournier
---
First of all, thanks for the contribution!
## Adding support for a CPD language
Happily for you, to add CPD support for a new language is now easier than ever!
CPD works generically on the tokens produced by a {% jdoc core::cpd.Tokenizer %}.
To add support for a new language, the crucial piece is writing a tokenizer that
splits the source file into the tokens specific to your language. Thankfully you
can use a stock [Antlr grammar](https://github.com/antlr/grammars-v4) or JavaCC
grammar to generate a lexer for you. If you cannot use a lexer generator, for
instance because you are wrapping a lexer from another library, it is still relatively
easy to implement the Tokenizer interface.
{% include callout.html content="**Pro Tip**: If you wish to add a new language, there are more than 50 languages you could easily add with just an [Antlr grammar](https://github.com/antlr/grammars-v4)." type="primary" %}
Use the following guide to set up a new language module that supports CPD.
All you need to do is follow this few steps:
1. Create a new Maven module for your language. You can take [the Golang module](https://github.com/pmd/pmd/tree/master/pmd-go/pom.xml) as an example.
- Make sure to add your new module to the parent pom as `<module>` entry, so that it is built alongside the
other languages.
- Also add your new module to the dependencies list in "pmd-languages-deps/pom.xml", so that the new language
is automatically available in the binary distribution (pmd-dist).
1. Create a new module for your language, you can take [the Golang module](https://github.com/pmd/pmd/tree/master/pmd-go) as an example
* Make sure to add your new module to the parent pom as `<module>` entry, so that it is built alongside the
other languages.
* Also add your new module to the dependencies list in "pmd-languages-deps/pom.xml", so that the new language
is automatically available in the binary distribution (pmd-dist) as well as for the shell-completion
in the pmd-cli module.
2. Implement a {% jdoc core::cpd.Tokenizer %}.
- For Antlr grammars you can take the grammar from [antlr/grammars-v4](https://github.com/antlr/grammars-v4) and place it in `src/main/antlr4` followed by the package name of the language. You then need to call the appropriate ant wrapper to generate
the lexer from the grammar. To do so, edit `pom.xml` (eg like [the Golang module](https://github.com/pmd/pmd/tree/master/pmd-go/pom.xml)).
Once that is done, `mvn generate-sources` should generate the lexer sources for you.
2. Create a Tokenizer
- For Antlr grammars you can take the grammar from [here](https://github.com/antlr/grammars-v4) and
extend [AntlrTokenizer](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/AntlrTokenizer.java)
taking Go as an example
```java
public class GoTokenizer extends AntlrTokenizer {
@Override protected AntlrTokenManager getLexerForSource(SourceCode sourceCode) {
CharStream charStream = AntlrTokenizer.getCharStreamFromSourceCode(sourceCode);
return new AntlrTokenManager(new GolangLexer(charStream), sourceCode.getFileName());
}
}
You can now implement a tokenizer, for instance by extending {% jdoc core::cpd.impl.AntlrTokenizer %}. The following reproduces the Go implementation:
```java
// mind the package convention if you are going to make a PR
package net.sourceforge.pmd.lang.go.cpd;
public class GoTokenizer extends AntlrTokenizer {
@Override
protected Lexer getLexerForSource(CharStream charStream) {
return new GolangLexer(charStream);
}
}
```
- For JavaCC grammars you should subclass [JavaCCTokenizer](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/impl/JavaCCTokenizer.java)
which has many examples you could follow, you should also take the
[Python implementation](https://github.com/pmd/pmd/blob/master/pmd-python/src/main/java/net/sourceforge/pmd/cpd/PythonTokenizer.java) as reference
- For any other scenario you can use [AnyTokenizer](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/AnyTokenizer.java)
- For JavaCC grammars, place your grammar in `etc/grammar` and edit the `pom.xml` like the [Python implementation](https://github.com/pmd/pmd/blob/master/pmd-python/pom.xml) does.
You can then subclass {% jdoc core::cpd.impl.JavaCCTokenizer %} instead of AntlrTokenizer.
- For any other scenario just implement the interface however you can. Look at the Scala or Apex module for existing implementations.
If you're using Antlr or JavaCC, update the pom.xml of your submodule to use the appropriate ant wrapper. See `pmd-go/pom.xml` and `pmd-python/pom.xml` for examples.
3. Create your [Language](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/AbstractLanguage.java) class
3. Create a {% jdoc core::lang.Language %} implementation, and make it implement {% jdoc core::cpd.CpdCapableLanguage %}.
If your language only supports CPD, then you can subclass {% jdoc core::lang.impl.CpdOnlyLanguageModuleBase %} to get going:
```java
public class GoLanguage extends AbstractLanguage {
```java
// mind the package convention if you are going to make a PR
package net.sourceforge.pmd.lang.go;
public class GoLanguageModule extends CpdOnlyLanguageModuleBase {
public GoLanguage() {
super("Go", "go", new GoTokenizer(), ".go");
}
// A public noarg constructor is required.
public GoLanguageModule() {
super(LanguageMetadata.withId("go").name("Go").extensions("go"));
}
@Override
public Tokenizer createCpdTokenizer(LanguagePropertyBundle bundle) {
// This method should return an instance of the tokenizer you created.
return new GoTokenizer();
}
}
```
{% include callout.html content="**Pro Tip**: Yes, keep looking at Go!" type="primary" %}
**You are almost there!**
4. Update the list of supported languages
```
- Write the fully-qualified name of your Language class to the file `src/main/resources/META-INF/services/net.sourceforge.pmd.cpd.Language`
To make PMD find the language module at runtime, write the fully-qualified name of your language class into the file `src/main/resources/META-INF/services/net.sourceforge.pmd.lang.Language`.
- Update the test that asserts the list of supported languages by updating the `SUPPORTED_LANGUAGES` constant in [BinaryDistributionIT](https://github.com/pmd/pmd/blob/master/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java)
At this point the new language module should be available in {% jdoc core::lang.LanguageRegistry#CPD %} and usable by CPD like any other language.
5. Please don't forget to add some test, you can again.. look at Go implementation ;)
If you read this far, I'm keen to think you would also love to support some extra CPD configuration (ignore imports or crazy things like that)
If that's your case , you came to the right place!
6. You can add your custom properties using a Token filter
- For Antlr grammars all you need to do is implement your own [AntlrTokenFilter](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/AntlrTokenFilter.java)
And by now, I know where you are going to look...
**WRONG**
Why do you want GO to solve all your problems?
You should take a look to [Kotlin token filter implementation](https://github.com/pmd/pmd/blob/master/pmd-kotlin/src/main/java/net/sourceforge/pmd/cpd/KotlinTokenizer.java)
- For non-Antlr grammars you can use [BaseTokenFilter](https://github.com/pmd/pmd/blob/master/pmd-core/src/main/java/net/sourceforge/pmd/cpd/token/internal/BaseTokenFilter.java) directly or take a peek to [Java's token filter](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/cpd/JavaTokenizer.java)
4. Update the test that asserts the list of supported languages by updating the `SUPPORTED_LANGUAGES` constant in [BinaryDistributionIT](https://github.com/pmd/pmd/blob/master/pmd-dist/src/test/java/net/sourceforge/pmd/it/BinaryDistributionIT.java).
5. Add some tests for your tokenizer by following the [section below](#testing-your-implementation).
6. Finishing up your new language module by adding a page in the documentation. Create a new markdown file
`<langId>.md` in `docs/pages/pmd/languages/`. This file should have the following frontmatter:
```
---
title: <Language Name>
permalink: pmd_languages_<langId>.html
last_updated: <Month> <Year> (<PMD Version>)
tags: [languages, CpdCapableLanguage]
---
```
On this page, language specifics can be documented, e.g. when the language was first supported by PMD.
There is also the following Jekyll Include, that creates summary box for the language:
```
{% raw %}
{% include language_info.html name='<Language Name>' id='<langId>' implementation='<langId>::lang.<langId>.<langId>LanguageModule' supports_cpd=true %}
{% endraw %}
```
### Declaring tokenizer options
To make the tokenizer configurable, first define some property descriptors using
{% jdoc core::properties.PropertyFactory %}. Look at {% jdoc core::cpd.Tokenizer %}
for some predefined ones which you can reuse (prefer reusing property descriptors if you can).
You need to override {% jdoc core::Language#newPropertyBundle() %}
and call `definePropertyDescriptor` to register the descriptors.
After that you can access the values of the properties from the parameter
of {% jdoc core::cpd.CpdCapableLanguage#createCpdTokenizer(core::lang.LanguagePropertyBundle) %}.
To implement simple token filtering, you can use {% jdoc core::cpd.impl.BaseTokenFilter %}
as a base class, or another base class in {% jdoc_package core::cpd.impl %}.
Take a look at the [Kotlin token filter implementation](https://github.com/pmd/pmd/blob/master/pmd-kotlin/src/main/java/net/sourceforge/pmd/lang/kotlin/cpd/KotlinTokenizer.java), or the [Java one](https://github.com/pmd/pmd/blob/master/pmd-java/src/main/java/net/sourceforge/pmd/lang/java/cpd/JavaTokenizer.java).
### Testing your implementation
Add a Maven dependency on `pmd-lang-test` (scope `test`) in your `pom.xml`.
This contains utilities to test your Tokenizer.
For simple tests, create a test class extending from `CpdTextComparisonTest`.
That class is written in Kotlin, but you can extend it in Java as well.
This contains utilities to test your tokenizer.
Create a test class extending from {% jdoc lang-test::cpd.test.CpdTextComparisonTest %}.
To add tests, you need to write regular JUnit `@Test`-annotated methods, and
call the method `doTest` with the name of the test file.
For example, for the Dart language:
```java
package net.sourceforge.pmd.lang.dart.cpd;
public class DartTokenizerTest extends CpdTextComparisonTest {
@ -110,20 +137,15 @@ public class DartTokenizerTest extends CpdTextComparisonTest {
public DartTokenizerTest() {
super(".dart"); // the file extension for the dart language
super("dart", ".dart"); // the ID of the language, then the file extension used by test files
}
@Override
protected String getResourcePrefix() {
// If your class is in src/test/java /some/package
// you need to place the test files in src/test/resources/some/package/cpdData
return "cpdData";
}
@Override
public Tokenizer newTokenizer() {
// Override this abstract method to return the correct tokenizer
return new DartTokenizer();
// "testdata" is the default value, you don't need to override.
// This specifies that you should place the test files in
// src/test/resources/net/sourceforge/pmd/lang/dart/cpd/testdata
return "testdata";
}
/**************

View File

@ -1,15 +1,40 @@
---
title: Apex support
permalink: pmd_languages_apex.html
last_updated: September 2023 (7.0.0)
author: Clément Fournier
last_updated: March 2021 (7.0.0)
tags: [languages]
tags: [languages, PmdCapableLanguage, CpdCapableLanguage]
summary: "Apex-specific features and guidance"
---
{% include warning.html content="Todo for pmd 7" %}
> [Apex](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_dev_guide.htm) is a strongly
> typed, object-oriented programming language that allows developers to execute flow and
> transaction control statements on the Salesforce Platform server, in conjunction with calls to the API.
### Metrics framework
{% include language_info.html name='Apex' id='apex' implementation='apex::lang.apex.ApexLanguageModule' supports_pmd=true supports_cpd=true since='5.5.0' %}
In order to use code metrics in Java, use the metrics constants in {% jdoc apex::lang.apex.metrics.ApexMetrics %},
## Metrics framework
In order to use code metrics in Apex, use the metrics constants in {% jdoc apex::lang.apex.metrics.ApexMetrics %},
together with {% jdoc core::lang.metrics.MetricsUtil %}.
## Multifile Analysis
Integration happens in {% jdoc apex::lang.apex.multifile.ApexMultifileAnalysis %}. It uses
[ApexLink](https://github.com/nawforce/apex-link). For detailed information, see also [Apexlink POC #2830](https://github.com/pmd/pmd/pull/2830).
{% include note.html content="ApexLink's new home: <https://github.com/apex-dev-tools>" %}
Used for rule {% rule apex/design/UnusedMethod %}
## Language Properties
See [Apex language properties](pmd_languages_configuration.html#apex-language-properties)
## Parser
We use Jorje, the Apex parsers that is shipped within the Apex Language Server. This is part of
the [Salesforce Extensions for VS Code](https://github.com/forcedotcom/salesforcedx-vscode).
We take the binary from <https://github.com/forcedotcom/salesforcedx-vscode/tree/develop/packages/salesforcedx-vscode-apex/out>
and provide it as a maven dependency (see [pmd-apex-jorje](https://github.com/pmd/pmd/tree/master/pmd-apex-jorje)).

View File

@ -1,10 +1,15 @@
---
title: Coco
title: Coco support
permalink: pmd_languages_coco.html
last_updated: September 2023 (7.0.0)
tags: [languages, CpdCapableLanguage]
summary: "Coco features and guidance"
---
Coco is a modern programming language designed specifically for building event-driven software.
It is part of the Coco Platform from <https://cocotec.io/>.
> Coco is a modern programming language designed specifically for building event-driven software.
> It is part of the Coco Platform from <https://cocotec.io/>.
{% include language_info.html name='Coco' id='coco' implementation='coco::lang.coco.CocoLanguageModule' supports_cpd=true since='7.0.0' %}
## Support in PMD
Starting from version 7.0.0, Coco support was added to CPD.

View File

@ -0,0 +1,13 @@
---
title: C/C++ support
permalink: pmd_languages_cpp.html
last_updated: September 2023 (7.0.0)
tags: [languages, CpdCapableLanguage]
summary: "C/C++ features and guidance"
---
{% include language_info.html name='C++' id='cpp' implementation='cpp::lang.cpp.CppLanguageModule' supports_cpd=true since='3.5' %}
## Language Properties
See [Cpp language properties](pmd_languages_configuration.html#cpp-language-properties)

View File

@ -0,0 +1,9 @@
---
title: C# support
permalink: pmd_languages_cs.html
last_updated: September 2023 (7.0.0)
tags: [languages, CpdCapableLanguage]
summary: "C#-specific features and guidance"
---
{% include language_info.html name='C#' id='cs' implementation='cs::lang.cs.CsLanguageModule' supports_cpd=true since='4.3' %}

View File

@ -0,0 +1,11 @@
---
title: Dart support
permalink: pmd_languages_dart.html
last_updated: September 2023 (7.0.0)
tags: [languages, CpdCapableLanguage]
summary: "Dart-specific features and guidance"
---
> [Dart](https://dart.dev/) is a client-optimized language for fast apps on any platform.
{% include language_info.html name='Dart' id='dart' implementation='dart::lang.dart.DartLanguageModule' supports_cpd=true since='6.14.0' %}

Some files were not shown because too many files have changed in this diff Show More