diff -Nru checkstyle-6.15/.ci/check-only-javadoc-error.sh checkstyle-8.8/.ci/check-only-javadoc-error.sh --- checkstyle-6.15/.ci/check-only-javadoc-error.sh 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/.ci/check-only-javadoc-error.sh 2017-12-31 17:11:38.000000000 +0000 @@ -0,0 +1,26 @@ +#!/bin/bash + +#This script is used at distelli-manifest.yml +#Run "firefox target/site/checkstyle.html" after completion to review html report + +set -e + +uname -a +mvn --version +mvn -e clean install -Pno-validations +git clone https://github.com/checkstyle/contribution && cd contribution/checkstyle-tester +sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties +sed -i.'' 's/#spring-framework/spring-framework/' projects-to-test-on.properties +sed -i.'' 's/#nbia-dcm4che-tools/nbia-dcm4che-tools/' projects-to-test-on.properties +sed -i.'' 's/#findbugs/findbugs/' projects-to-test-on.properties +sed -i.'' 's/#pmd/pmd/' projects-to-test-on.properties +sed -i.'' 's/#apache-ant/apache-ant/' projects-to-test-on.properties +./launch.sh -Dcheckstyle.config.location=checks-only-javadoc-error.xml +if grep "Got an exception" target/site/checkstyle.html; then + echo "[ERROR] Exceptions detected" + exit 1 +else + echo "[INFO] Finished without exceptions" + exit 0 +fi + diff -Nru checkstyle-6.15/.ci/eclipse-compiler-javac.sh checkstyle-8.8/.ci/eclipse-compiler-javac.sh --- checkstyle-6.15/.ci/eclipse-compiler-javac.sh 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/.ci/eclipse-compiler-javac.sh 2017-10-26 12:59:58.000000000 +0000 @@ -0,0 +1,35 @@ +#!/bin/bash +set -e + +if [ -z "$1" ]; then + echo "No parameters supplied!" + echo " The classpath of the project and it's libraries to compile must be supplied." + exit 1 +fi + +ECJ_JAR="ecj-4.7.jar" +ECJ_MAVEN_VERSION="R-4.7-201706120950" +ECJ_PATH=~/.m2/repository/$ECJ_MAVEN_VERSION/$ECJ_JAR + +if [ ! -f $ECJ_PATH ]; then + echo "$ECJ_PATH is not found, downloading ..." + mkdir -p $(dirname "$ECJ_PATH") + wget http://ftp-stud.fht-esslingen.de/pub/Mirrors/eclipse/eclipse/downloads/drops4/$ECJ_MAVEN_VERSION/$ECJ_JAR -O $ECJ_PATH +fi + +mkdir -p target/classes +mkdir -p target/eclipse + +RESULT_FILE=target/eclipse/report.txt + +echo "Executing eclipse compiler, output is redirected to $RESULT_FILE..." +java -jar $ECJ_PATH -target 1.8 -source 1.8 -cp $1 \ + -nowarn:[./target/generated-sources/antlr] -d target/eclipse-compile \ + -enableJavadoc src/main/java src/test/java target/generated-sources/antlr -properties config/org.eclipse.jdt.core.prefs \ + > $RESULT_FILE 2>&1 | true + +echo "Checking for ERROR|WARNING|INFO in $RESULT_FILE ..." +if [[ $(grep -E "ERROR|WARNING|INFO" $RESULT_FILE | cat | wc -l) > 0 ]]; then + cat $RESULT_FILE + false +fi diff -Nru checkstyle-6.15/.ci/fast-forward-merge.sh checkstyle-8.8/.ci/fast-forward-merge.sh --- checkstyle-6.15/.ci/fast-forward-merge.sh 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/.ci/fast-forward-merge.sh 2017-10-26 12:59:58.000000000 +0000 @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +# GitHub does not support fast-forward merge. +# This script is intended to simplify merge of Pull Requests to keep history linear (fast-forwarded) +# All Pull Requests from GitHub to our project has to be applied to our code by this script. + +set -e + +if [ $# -eq 0 ] + then + echo "$(basename "$0") FORK_USER_NAME USER_BRANCH +example: + + ./$(basename "$0") konstantinos issue73 +" + exit 0; +fi + +GIT_REPO=checkstyle +FORK_USER_NAME=$1 +USER_BRANCH=$2 +REPO=${FORK_USER_NAME}-fork +LOCAL_USER_BRANCH=${FORK_USER_NAME}-${USER_BRANCH} + +echo "removing remote ${REPO} if present ..." +git remote rm ${REPO} | true + +echo "adding remote ..." +git remote add ${REPO} https://github.com/${FORK_USER_NAME}/${GIT_REPO}.git +git fetch ${REPO} + +echo "removing remote ${LOCAL_USER_BRANCH} if present ..." +git branch -D ${LOCAL_USER_BRANCH} | true + +echo "creating local branch ..." +git checkout -b ${LOCAL_USER_BRANCH} ${REPO}/${USER_BRANCH} + +echo "rebasing over master ..." +git rebase master + +echo "merge to master ..." +git checkout master +git merge ${LOCAL_USER_BRANCH} --ff-only + +echo "removing local branch ..." +git branch -D ${LOCAL_USER_BRANCH} + +echo "removing remote ..." +git remote rm ${REPO} diff -Nru checkstyle-6.15/.ci/idea_inspection.bat checkstyle-8.8/.ci/idea_inspection.bat --- checkstyle-6.15/.ci/idea_inspection.bat 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/.ci/idea_inspection.bat 2017-10-26 12:59:58.000000000 +0000 @@ -0,0 +1,46 @@ +@echo off + +::---------------------------------------------------------------------- +:: IntelliJ IDEA inspections for checkstyle. +:: +:: Example: +:: SET IDEA_PATH=C:\Program Files\JetBrains\IntelliJ IDEA Community Edition 2017.2.1\bin\idea.bat +:: .ci\idea_inspection.bat +::---------------------------------------------------------------------- + +SET PROJECT_DIR=%CD%\ +SET INSPECTIONS_PATH=%CD%\config\intellij-idea-inspections.xml +SET RESULTS_DIR=%CD%\target\inspection-results +SET NOISE_LVL=v1 +SET IDEA_LOCATION= +SET IDEA_PROPERTIES=%CD%\config\intellij-idea-inspections.properties + +::Check IDEA_PATH env variable +IF EXIST %IDEA_PATH% SET ( + SET IDEA_LOCATION=%IDEA_PATH% + goto run +) ELSE ( + echo IDEA_PATH variable not found. +) + +::Try to search in path +FOR /f "delims=" %%i IN ('"where idea.bat"') DO SET IDEA_LOCATION="%%i" +if [%IDEA_LOCATION%] NEQ [] ( + goto run +) ELSE ( + echo IntelliJ IDEA was not found in path. + exit /b +) + +:run +mkdir %RESULTS_DIR% +del %RESULTS_DIR%\*.* /s /q + +mkdir .idea\scopes +copy config\intellij-idea-inspection-scope.xml .idea\scopes + +::Execute compilation of Checkstyle to generate all source files +mvn compile + +::Launch inspections +"%IDEA_LOCATION%" inspect %PROJECT_DIR% %INSPECTIONS_PATH% %RESULTS_DIR% -%NOISE_LVL% diff -Nru checkstyle-6.15/.ci/idea_inspection.sh checkstyle-8.8/.ci/idea_inspection.sh --- checkstyle-6.15/.ci/idea_inspection.sh 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/.ci/idea_inspection.sh 2017-12-31 17:11:38.000000000 +0000 @@ -0,0 +1,54 @@ +#!/bin/bash -e + +################################################# +# IntelliJ IDEA inspections for checkstyle. +# +# Example Mac OS: +# IDEA_PATH="/Applications/IntelliJ IDEA.app/Contents/MacOS/idea" ./.ci/idea_inspection.sh +# +# Example Linux: +# IDEA_PATH=/opt/idea-IC-171.4694.70/bin/idea.sh ./.ci/idea_inspection.sh +################################################# + +PROJECT_DIR=$PWD/ +INSPECTIONS_PATH=$PWD/config/intellij-idea-inspections.xml +RESULTS_DIR=$PWD/target/inspection-results +NOISE_LVL=v1 +# we need to export this variable as it is required for idea.sh script +export IDEA_PROPERTIES=$PWD/config/intellij-idea-inspections.properties + +# Check IDEA_PATH env variable +if [[ -z $IDEA_PATH ]]; then + echo "IDEA_PATH variable not found." + # Try to search in path + IDEA_PATH="$(which idea)" + if [ -z $IDEA_PATH ]; then + echo "IntelliJ IDEA was not found in path." + exit -1 + fi +fi + +#Execute compilation of Checkstyle to generate all source files +mvn -e compile + +mkdir -p $RESULTS_DIR +rm -rf $RESULTS_DIR/* + +echo "Intellij Idea validation is about to start" +echo "Progress output will be flushed at end. Validation is in progress ..." +IDEA_OUTPUT=`exec "$IDEA_PATH" inspect $PROJECT_DIR $INSPECTIONS_PATH $RESULTS_DIR -$NOISE_LVL` +echo $IDEA_OUTPUT + +if [[ $IDEA_OUTPUT == "Already running" ]]; then + echo "It might be that Intellij Idea is running, please close it." + exit 1; +fi + +echo "Checking results ..." +if [[ $(grep -R " 0 ]]; then + echo "There are inspection problems. Review results at $RESULTS_DIR folder. Files:" + grep -Rl " response.json + +OUTPUT="$(cat response.json | jq '.total')" + +#print number of found issues +if [ ! "$OUTPUT" -eq "0" ]; then + jq '.' response.json + echo "Found issues - $OUTPUT" +fi diff -Nru checkstyle-6.15/.ci/sonar-wrapper.sh checkstyle-8.8/.ci/sonar-wrapper.sh --- checkstyle-6.15/.ci/sonar-wrapper.sh 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/.ci/sonar-wrapper.sh 2017-10-26 12:59:58.000000000 +0000 @@ -0,0 +1,18 @@ +#!/bin/sh + +#This file is for manual execution only + +set -e + +echo "Building docker image" +docker pull sonarqube +echo "Running docker container" +docker run -dit -p 9000:9000 --name sonar sonarqube:latest +echo "sleeping 60 sec to let sonar start up" +sleep "60" + +./.ci/sonar.sh + +#kill container +docker stop sonar +docker rm sonar diff -Nru checkstyle-6.15/.ci/travis/checkchmod.sh checkstyle-8.8/.ci/travis/checkchmod.sh --- checkstyle-6.15/.ci/travis/checkchmod.sh 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/.ci/travis/checkchmod.sh 2017-10-26 12:59:58.000000000 +0000 @@ -0,0 +1,27 @@ +#!/bin/bash + +set -e + +# On Travis, after clone, all files are with 644 permission, on local they are 664, so we check only executable bit +CHMOD=$(find -type f -not -path '*/\.git/*' -a -type f -not -name '*.sh' -a \( -type d -not -perm 775 -o -type f -executable \)) +if [[ ! -z $CHMOD ]]; then + echo "Expected mode for non '.sh' files is 664."; + echo "Files that violates this rule:" + for NAMEFILE in $CHMOD + do + echo $NAMEFILE; + done + exit 1; +fi + +# On Travis, after clone, all 'sh' files have executable bit +CHMOD=$(find -type f -not -path '*/\.git/*' -a -type f -name '*.sh' -a -not -executable) +if [[ ! -z $CHMOD ]]; then + echo "Expected mode for '.sh' files is 755."; + echo "Files that violates this rule:" + for NAMEFILE in $CHMOD + do + echo $NAMEFILE; + done + exit 1; +fi diff -Nru checkstyle-6.15/.ci/travis/travis.sh checkstyle-8.8/.ci/travis/travis.sh --- checkstyle-6.15/.ci/travis/travis.sh 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/.ci/travis/travis.sh 2017-12-31 17:11:38.000000000 +0000 @@ -0,0 +1,262 @@ +#!/bin/bash +# Attention, there is no "-x" to avoid problems on Travis +set -e + +case $1 in + +nondex) + mvn -e --fail-never clean nondex:nondex -DargLine='-Xms1024m -Xmx2048m' + cat `grep -RlE 'td class=.x' .nondex/ | cat` < /dev/null > output.txt + RESULT=$(cat output.txt | wc -c) + cat output.txt + echo 'Size of output:'$RESULT + if [[ $RESULT != 0 ]]; then sleep 5s; false; fi + ;; + +versions) + if [[ -v TRAVIS_EVENT_TYPE && $TRAVIS_EVENT_TYPE != "cron" ]]; then exit 0; fi + mvn -e clean versions:dependency-updates-report versions:plugin-updates-report + if [ $(grep "" target/*-updates-report.xml | cat | wc -l) -gt 0 ]; then + echo "Version reports (dependency-updates-report.xml):" + cat target/dependency-updates-report.xml + echo "Version reports (plugin-updates-report.xml):" + cat target/plugin-updates-report.xml + echo "New dependency versions:" + grep -B 7 -A 7 "" target/dependency-updates-report.xml | cat + echo "New plugin versions:" + grep -B 4 -A 7 "" target/plugin-updates-report.xml | cat + echo "Verification is failed." + sleep 5s + false + else + echo "No new versions found" + fi + ;; + +assembly-run-all-jar) + mvn -e clean package -Passembly + CS_POM_VERSION=$(mvn -e -q -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo version:$CS_POM_VERSION + java -jar target/checkstyle-$CS_POM_VERSION-all.jar -c /google_checks.xml \ + src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/InputNoLineWrapGood.java > output.log + if grep -vE '(Starting audit)|(warning)|(Audit done.)' output.log ; then exit 1; fi + if grep 'warning' output.log ; then exit 1; fi + ;; + +sonarqube) + # token could be generated at https://sonarcloud.io/account/security/ + # executon on local: SONAR_TOKEN=xxxxxxxxxx ./.ci/travis/travis.sh sonarqube + if [[ -v TRAVIS_PULL_REQUEST && $TRAVIS_PULL_REQUEST && $TRAVIS_PULL_REQUEST =~ ^([0-9]*)$ ]]; then exit 0; fi + if [[ -z $SONAR_TOKEN ]]; then echo "SONAR_TOKEN is not set"; sleep 5s; exit 1; fi + export MAVEN_OPTS='-Xmx2000m' + mvn -e clean package cobertura:cobertura sonar:sonar \ + -Dsonar.host.url=https://sonarcloud.io \ + -Dsonar.login=$SONAR_TOKEN \ + -Dcobertura.report.format=xml -Dmaven.test.failure.ignore=true \ + -Dcheckstyle.skip=true -Dpmd.skip=true -Dcheckstyle.ant.skip=true + ;; + +release-dry-run) + if [ $(git log -1 | grep -E "\[maven-release-plugin\] prepare release" | cat | wc -l) -lt 1 ]; then + mvn -e release:prepare -DdryRun=true --batch-mode -Darguments='-DskipTests -DskipITs \ + -Dcobertura.skip=true -Dpmd.skip=true -Dfindbugs.skip=true -Dxml.skip=true \ + -Dcheckstyle.ant.skip=true -Dcheckstyle.skip=true -Dgpg.skip=true' + fi + ;; + +releasenotes-gen) + .ci/travis/xtr_releasenotes-gen.sh + ;; + +pr-description) + .ci/travis/xtr_pr-description.sh + ;; + +check-chmod) + .ci/travis/checkchmod.sh + ;; + +all-sevntu-checks) + xmlstarlet sel --net --template -m .//module -v "@name" -n config/checkstyle_sevntu_checks.xml \ + | grep -vE "Checker|TreeWalker|Filter|Holder" | grep -v "^$" \ + | sed "s/com\.github\.sevntu\.checkstyle\.checks\..*\.//" \ + | sort | uniq | sed "s/Check$//" > file.txt + wget -q http://sevntu-checkstyle.github.io/sevntu.checkstyle/apidocs/allclasses-frame.html -O - \ + | grep "
  • " | cut -d '>' -f 3 | sed "s/<\/a//" \ + | grep -E "Check$" \ + | sort | uniq | sed "s/Check$//" > web.txt + diff -u web.txt file.txt + ;; + +no-error-test-sbe) + CS_POM_VERSION=$(mvn -e -q -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo version:$CS_POM_VERSION + mvn -e clean install -Pno-validations + git clone https://github.com/real-logic/simple-binary-encoding.git + cd simple-binary-encoding + git checkout 963814f8ca1456de9daaf67e78663e7d877871a9 + sed -i'' "s/'com.puppycrawl.tools:checkstyle:.*'/'com.puppycrawl.tools:checkstyle:$CS_POM_VERSION'/" build.gradle + ./gradlew build + ;; + +no-exception-test-checkstyle-sevntu-checkstyle) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#checkstyle/checkstyle/' projects-to-test-on.properties + sed -i.'' 's/#sevntu-checkstyle/sevntu-checkstyle/' projects-to-test-on.properties + cd ../../ + mvn -e clean install -Pno-validations + cd contribution/checkstyle-tester + export MAVEN_OPTS="-Xmx2048m" + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + ;; + +no-exception-test-guava) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#guava|/guava|/' projects-to-test-on.properties + cd ../../ + mvn -e clean install -Pno-validations + cd contribution/checkstyle-tester + export MAVEN_OPTS="-Xmx2048m" + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + ;; + +no-exception-test-guava-with-google-checks) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#guava|/guava|/' projects-to-test-on.properties + cd ../../ + mvn -e clean install -Pno-validations + sed -i.'' 's/warning/ignore/' src/main/resources/google_checks.xml + cd contribution/checkstyle-tester + export MAVEN_OPTS="-Xmx2048m" + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config ../../src/main/resources/google_checks.xml + ;; + +no-exception-test-hibernate) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#hibernate-orm/hibernate-orm/' projects-to-test-on.properties + cd ../../ + mvn -e clean install -Pno-validations + cd contribution/checkstyle-tester + export MAVEN_OPTS="-Xmx2048m" + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + ;; + +no-exception-test-findbugs) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#findbugs/findbugs/' projects-to-test-on.properties + cd ../../ + mvn -e clean install -Pno-validations + cd contribution/checkstyle-tester + export MAVEN_OPTS="-Xmx2048m" + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + ;; + +no-exception-test-spring-framework) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#spring-framework/spring-framework/' projects-to-test-on.properties + cd ../../ + mvn -e clean install -Pno-validations + cd contribution/checkstyle-tester + export MAVEN_OPTS="-Xmx2048m" + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + ;; + +no-exception-test-hbase) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#Hbase/Hbase/' projects-to-test-on.properties + cd ../../ + mvn -e clean install -Pno-validations + cd contribution/checkstyle-tester + export MAVEN_OPTS="-Xmx2048m" + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + ;; + +no-exception-test-Pmd-elasticsearch-lombok-ast) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#pmd/pmd/' projects-to-test-on.properties + sed -i.'' 's/#elasticsearch/elasticsearch/' projects-to-test-on.properties + sed -i.'' 's/#lombok-ast/lombok-ast/' projects-to-test-on.properties + cd ../../ + mvn -e clean install -Pno-validations + cd contribution/checkstyle-tester + export MAVEN_OPTS="-Xmx2048m" + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + ;; + +no-exception-test-alot-of-project1) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#RxJava/RxJava/' projects-to-test-on.properties + sed -i.'' 's/#java-design-patterns/java-design-patterns/' projects-to-test-on.properties + sed -i.'' 's/#MaterialDesignLibrary/MaterialDesignLibrary/' projects-to-test-on.properties + sed -i.'' 's/#apache-ant/apache-ant/' projects-to-test-on.properties + sed -i.'' 's/#apache-jsecurity/apache-jsecurity/' projects-to-test-on.properties + sed -i.'' 's/#android-launcher/android-launcher/' projects-to-test-on.properties + cd ../../ + mvn -e clean install -Pno-validations + cd contribution/checkstyle-tester + export MAVEN_OPTS="-Xmx2048m" + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + ;; + +cobertura-check) + set +e + echo "Output and Error output will be redirected to mvn-log.log file ..." + mvn -e clean compile cobertura:cobertura cobertura:check -DargLine='-Xms1024m -Xmx2048m' &> mvn-log.log + echo "Printing mvn-log.log file:" + cat mvn-log.log + sleep 5s + set -e + echo "Grep for hidden errors (due to quiet=true mode in pom.xml):" + grep -R " mvn-log-grep.log + cat mvn-log-grep.log + if [[ $(cat mvn-log-grep.log | wc -l) -gt 0 ]]; then + sleep 5s + false + fi + echo "Checking that all classes are covered:" + xmlstarlet sel -t -m "//class" -v "@name" -n target/site/cobertura/coverage.xml | sed "s/\./\//g" | sed "/^$/d" | sort | uniq > cobertura_classes.log + find target/classes -type f -name "*.class" | grep -vE ".*\\$.*" | sed "s/target\/classes\///g" | sed "s/.class//g" | sed "/^$/d" | sort | uniq > target_classes.log + xmlstarlet sel -N pom=http://maven.apache.org/POM/4.0.0 -t -m "//pom:instrumentation/pom:excludes" -v "pom:exclude" -n pom.xml | sed "s/*//g" | sed "s/.class//g" | sed "/^$/d" | sort | uniq > cobertura_excluded_classes.log + # xmlstarlet has an issue. It concatenates this line with the previous one and removes new line character, + # so we need to split them apart. We use the command till update of xmlstarlet to higher version. + sed -i'' "s/com\/puppycrawl\/tools\/checkstyle\/gui\/BaseCellEditor/\ncom\/puppycrawl\/tools\/checkstyle\/gui\/BaseCellEditor/" cobertura_excluded_classes.log + grep -Fxvf cobertura_classes.log target_classes.log > missed_classes_with_excludes.log + grep -Fvf cobertura_excluded_classes.log missed_classes_with_excludes.log > missed_classes_without_excludes.log | cat > output.log + echo "output.log content:" + cat output.log + + if [[ -s missed_classes_without_excludes.log ]] ; then + echo "Classes which are missed in Cobertura coverage report:" + cat missed_classes_without_excludes.log + sleep 5s + false + else + echo "All classes are present in Cobertura coverage report." + fi + ;; + +*) + echo "Unexpected argument: $1" + sleep 5s + false + ;; + +esac diff -Nru checkstyle-6.15/.ci/travis/xtr_pr-description.sh checkstyle-8.8/.ci/travis/xtr_pr-description.sh --- checkstyle-6.15/.ci/travis/xtr_pr-description.sh 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/.ci/travis/xtr_pr-description.sh 2017-09-04 20:01:01.000000000 +0000 @@ -0,0 +1,29 @@ +#!/bin/bash +# Attention, there is no "-x" to avoid problems on Travis +set -e + +if [[ ! $TRAVIS_PULL_REQUEST =~ ^([0-9]*)$ ]]; then exit 0; fi +LINK_COMMITS=https://api.github.com/repos/checkstyle/checkstyle/pulls/$TRAVIS_PULL_REQUEST/commits +COMMITS=$(curl -s -H "Authorization: token $READ_ONLY_TOKEN" $LINK_COMMITS | jq '.[0] | .commit.message') +echo 'Commit messages from github: '${COMMITS:0:60}... +ISSUE_NUMBER=$(echo $COMMITS | sed -e 's/^.*Issue //' | sed -e 's/:.*//') +echo 'Issue number: '$ISSUE_NUMBER && RESULT=0 +if [[ $ISSUE_NUMBER =~ ^#[0-9]+$ ]]; then + LINK_PR=https://api.github.com/repos/checkstyle/checkstyle/pulls/$TRAVIS_PULL_REQUEST + LINK_ISSUE=https://api.github.com/repos/checkstyle/checkstyle/issues/${ISSUE_NUMBER:1} + REGEXP=($ISSUE_NUMBER\|https://github.com/checkstyle/checkstyle/issues/${ISSUE_NUMBER:1}) + PR_DESC=$(curl -s -H "Authorization: token $READ_ONLY_TOKEN" $LINK_PR | jq '.body' | grep -E $REGEXP | cat ) + echo 'PR Description grepped:'${PR_DESC:0:80} + if [[ -z $PR_DESC ]]; then + echo 'Please put a reference to an Issue in the PR description, this will bind the Issue to your PR in Github' && RESULT=1; + fi + LABEL_APRV=$(curl -s -H "Authorization: token $READ_ONLY_TOKEN" $LINK_ISSUE | jq '.labels [] | .name' | grep approved | cat | wc -l ) + if [[ $LABEL_APRV == 0 ]]; then + echo 'You are providing a PR for an Issue that is not approved yet, please ask admins to approve your Issue first' && RESULT=1; + fi + fi +if [[ $RESULT == 0 ]]; then + echo 'PR validation succeeded.'; +else + echo 'PR validation failed.' && false; +fi diff -Nru checkstyle-6.15/.ci/travis/xtr_releasenotes-gen.sh checkstyle-8.8/.ci/travis/xtr_releasenotes-gen.sh --- checkstyle-6.15/.ci/travis/xtr_releasenotes-gen.sh 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/.ci/travis/xtr_releasenotes-gen.sh 2017-12-31 17:11:38.000000000 +0000 @@ -0,0 +1,51 @@ +#!/bin/bash +# Attention, there is no "-x" to avoid problem on Travis +set -e + +if [[ $TRAVIS_PULL_REQUEST =~ ^([0-9]*)$ ]]; then exit 0; fi +git clone https://github.com/checkstyle/contribution +cd contribution/releasenotes-builder +mvn -e clean compile package +cd ../../ +# we need to do full clone as Travis do "git clone --depth=50" +git clone https://github.com/checkstyle/checkstyle +cd checkstyle +LATEST_RELEASE_TAG=$(git describe $(git rev-list --tags --max-count=1)) +cd ../ +CS_RELEASE_VERSION=$(mvn -e -q -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec | sed 's/-SNAPSHOT//' ) +echo LATEST_RELEASE_TAG=$LATEST_RELEASE_TAG +echo CS_RELEASE_VERSION=$CS_RELEASE_VERSION +java -jar contribution/releasenotes-builder/target/releasenotes-builder-1.0-all.jar \ + -localRepoPath checkstyle -startRef $LATEST_RELEASE_TAG -releaseNumber $CS_RELEASE_VERSION \ + -githubAuthToken $READ_ONLY_TOKEN -generateAll -publishXdoc + +echo ============================================== +echo +echo "xdoc segment:" +echo ============================================== +cat xdoc.xml +echo ============================================== +echo +echo "twitter post:" +echo ============================================== +cat twitter.txt +echo ============================================== +echo +echo "google plus post:" +echo ============================================== +cat gplus.txt +echo ============================================== +echo +echo "RSS post:" +echo ============================================== +cat rss.txt +echo ============================================== +echo +echo "mailing list post:" +echo ============================================== +cat mailing_list.txt +echo ============================================== +cd checkstyle/src/xdocs +echo +echo "releasenotes.xml after commit:" +head -n 100 releasenotes.xml diff -Nru checkstyle-6.15/.ci/wercker.sh checkstyle-8.8/.ci/wercker.sh --- checkstyle-6.15/.ci/wercker.sh 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/.ci/wercker.sh 2018-01-22 14:58:53.000000000 +0000 @@ -0,0 +1,202 @@ +#!/bin/bash +# Attention, there is no "-x" to avoid problems on Wercker +set -e + +case $1 in + +no-error-pgjdbc) + CS_POM_VERSION=$(mvn -e -q -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo CS_version: ${CS_POM_VERSION} + for i in 1 2 3 4 5; do git clone https://github.com/pgjdbc/pgjdbc.git && break || sleep 15; done + cd pgjdbc/pgjdbc + mvn -e checkstyle:check -Dcheckstyle.version=${CS_POM_VERSION} + cd ../../ + rm -rf pgjdbc + ;; + +no-error-orekit) + CS_POM_VERSION=$(mvn -e -q -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo CS_version: ${CS_POM_VERSION} + for i in 1 2 3 4 5; do git clone https://github.com/Hipparchus-Math/hipparchus.git && break || sleep 15; done + cd hipparchus + git checkout 905006092493e350dcd68dd7b2ec1dedaf4983b7 + mvn -e clean install -DskipTests + cd ../ + for i in 1 2 3 4 5; do git clone https://github.com/CS-SI/Orekit.git && break || sleep 15; done + cd Orekit + # Orekit use 'develop' branch as target for PullRequest merges + git checkout develop + mvn -e compile checkstyle:check -Dorekit.checkstyle.version=${CS_POM_VERSION} + cd ../ + rm -rf hipparchus Orekit + ;; + +no-error-xwiki) + CS_POM_VERSION=$(mvn -e -q -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo CS_version: ${CS_POM_VERSION} + for i in 1 2 3 4 5; do git clone https://github.com/xwiki/xwiki-commons/ && break || sleep 15; done + cd xwiki-commons + git checkout 44b0c0048c516dae20cf5f8a71181af836549484 + mvn -e install -DskipTests -Dxwiki.clirr.skip=true checkstyle:check -Dcheckstyle.version=${CS_POM_VERSION} + cd ../../ + rm -rf xwiki-commons + ;; + +no-error-apex-core) + CS_POM_VERSION=$(mvn -e -q -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo CS_version: ${CS_POM_VERSION} + for i in 1 2 3 4 5; do git clone https://github.com/apache/incubator-apex-core/ && break || sleep 15; done + cd incubator-apex-core + mvn -e compile checkstyle:check -Dcheckstyle.version=${CS_POM_VERSION} + cd ../ + rm -rf incubator-apex-core + ;; + +no-error-hibernate-search) + CS_POM_VERSION=$(mvn -e -q -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo CS_version: ${CS_POM_VERSION} + for i in 1 2 3 4 5; do git clone https://github.com/hibernate/hibernate-search.git && break || sleep 15; done + cd hibernate-search + mvn -e -s settings-example.xml clean install -DskipTests=true -Dtest.elasticsearch.host.provided=true -Dpuppycrawl.checkstyle.version=${CS_POM_VERSION} + mvn -e -s settings-example.xml checkstyle:check -Dpuppycrawl.checkstyle.version=${CS_POM_VERSION} + cd ../ + rm -rf hibernate-search + ;; + +no-error-htmlunit) + CS_POM_VERSION=$(mvn -e -q -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo CS_version: ${CS_POM_VERSION} + echo "checkouting project sources ..." + svn -q export https://svn.code.sf.net/p/htmlunit/code/trunk/htmlunit@r14923 htmlunit + cd htmlunit + sed -i "s/ 2.28-SNAPSHOT/ 2.28-20171106.080245-12/" pom.xml + echo "Running checkstyle validation ..." + mvn -e compile checkstyle:check -Dcheckstyle.version=${CS_POM_VERSION} + cd ../ + rm -rf htmlunit + ;; + +no-error-checkstyles-sevntu) + set -e + CS_POM_VERSION=$(mvn -e -q -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo CS_version: ${CS_POM_VERSION} + mvn -e compile verify -Dmaven.sevntu-checkstyle-check.checkstyle.version=${CS_POM_VERSION} -Dmaven.test.skip=true -Dcheckstyle.ant.skip=true -Dpmd.skip=true -Dfindbugs.skip=true -Dcobertura.skip=true -Dforbiddenapis.skip=true -Dxml.skip=true + ;; + +no-error-sevntu-checks) + set -e + CS_POM_VERSION=$(mvn -e -q -Dexec.executable='echo' -Dexec.args='${project.version}' --non-recursive org.codehaus.mojo:exec-maven-plugin:1.3.1:exec) + echo CS_version: ${CS_POM_VERSION} + for i in 1 2 3 4 5; do git clone https://github.com/sevntu-checkstyle/sevntu.checkstyle && break || sleep 15; done + cd sevntu.checkstyle/sevntu-checks + mvn -e -Pno-validations verify -Dcheckstyle.skip=false -Dcheckstyle.version=${CS_POM_VERSION} -Dcheckstyle.configLocation=../../config/checkstyle_checks.xml + cd ../../ + rm -rf sevntu.checkstyle + ;; + +no-exception-struts) + for i in 1 2 3 4 5; do git clone https://github.com/checkstyle/contribution && break || sleep 15; done + cd contribution/checkstyle-tester + sed -i'' 's/^guava/#guava/' projects-for-wercker.properties + sed -i'' 's/#apache-struts/apache-struts/' projects-for-wercker.properties + groovy ./launch.groovy --listOfProjects projects-for-wercker.properties --config checks-nonjavadoc-error.xml + cd ../../ + rm -rf contribution + ;; + +no-exception-checkstyle-sevntu) + set -e + for i in 1 2 3 4 5; do git clone https://github.com/checkstyle/contribution && break || sleep 15; done + cd contribution/checkstyle-tester + sed -i'' 's/^guava/#guava/' projects-for-wercker.properties + sed -i'' 's/#checkstyle/checkstyle/' projects-for-wercker.properties + sed -i'' 's/#sevntu-checkstyle/sevntu-checkstyle/' projects-for-wercker.properties + groovy ./launch.groovy --listOfProjects projects-for-wercker.properties --config checks-nonjavadoc-error.xml + cd ../../ + rm -rf contribution + ;; + +no-exception-guava) + for i in 1 2 3 4 5; do git clone https://github.com/checkstyle/contribution && break || sleep 15; done + cd contribution/checkstyle-tester + sed -i'' 's/^guava/#guava/' projects-for-wercker.properties + sed -i'' 's/#guava/guava/' projects-for-wercker.properties + groovy ./launch.groovy --listOfProjects projects-for-wercker.properties --config checks-nonjavadoc-error.xml + cd ../../ + rm -rf contribution + ;; + +no-exception-hibernate-orm) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#hibernate-orm/hibernate-orm/' projects-to-test-on.properties + groovy ./launch.groovy --listOfProjects projects-for-wercker.properties --config checks-nonjavadoc-error.xml + cd ../../ + rm -rf contribution + ;; + +no-exception-findbugs) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#findbugs/findbugs/' projects-to-test-on.properties + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + cd ../../ + rm -rf contribution + ;; + +no-exception-spring-framework) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#spring-framework/spring-framework/' projects-to-test-on.properties + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + cd ../../ + rm -rf contribution + ;; + +no-exception-hbase) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#Hbase/Hbase/' projects-to-test-on.properties + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + cd ../../ + rm -rf contribution + ;; + +no-exception-Pmd-elasticsearch-lombok-ast) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#pmd/pmd/' projects-to-test-on.properties + sed -i.'' 's/#elasticsearch/elasticsearch/' projects-to-test-on.properties + sed -i.'' 's/#lombok-ast/lombok-ast/' projects-to-test-on.properties + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + cd ../../ + rm -rf contribution + ;; + +no-exception-alot-of-projects) + git clone https://github.com/checkstyle/contribution + cd contribution/checkstyle-tester + sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties + sed -i.'' 's/#RxJava/RxJava/' projects-to-test-on.properties + sed -i.'' 's/#java-design-patterns/java-design-patterns/' projects-to-test-on.properties + sed -i.'' 's/#MaterialDesignLibrary/MaterialDesignLibrary/' projects-to-test-on.properties + sed -i.'' 's/#apache-ant/apache-ant/' projects-to-test-on.properties + sed -i.'' 's/#apache-jsecurity/apache-jsecurity/' projects-to-test-on.properties + sed -i.'' 's/#android-launcher/android-launcher/' projects-to-test-on.properties + groovy ./launch.groovy --listOfProjects projects-to-test-on.properties --config checks-nonjavadoc-error.xml + cd ../../ + rm -rf contribution + ;; + +*) + echo "Unexpected argument: $1" + sleep 5s + false + ;; + +esac diff -Nru checkstyle-6.15/circle.yml checkstyle-8.8/circle.yml --- checkstyle-6.15/circle.yml 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/circle.yml 2017-12-31 17:11:38.000000000 +0000 @@ -2,44 +2,51 @@ post: - git clone https://github.com/checkstyle/contribution dependencies: - # we to override as 'mvn dependecy:go-ofline' does not download all dependencies + cache_directories: + - groovy-2.4.7 + pre: + - if [ ! -d groovy-2.4.7 ]; then wget https://dl.bintray.com/groovy/maven/apache-groovy-binary-2.4.7.zip && unzip apache-groovy-binary-2.4.7.zip; fi + + # we to override as 'mvn -e dependecy:go-ofline' does not download all dependencies override: - - mvn install -Passembly + - mvn -e install -Pno-validations - eval $TESTER_DEPENDENCIES machine: java: version: oraclejdk8 environment: CMD1: "cd contribution/checkstyle-tester" - DEP1: " && sed -i.'' 's/^guava/#guava/' projects-to-test-on.properties" + DEP1: " && sed -i'' 's/^guava/#guava/' projects-to-test-on.properties" # we need this to let pass 'mvn site' on no-projects mode to download all dependecies DEP2: " && echo 'class ClassEmpty{}' > src/main/java/EmptyClass.java" - DEP3: " && ./launch.sh -Dcheckstyle.config.location=my_check.xml" + DEP3: " && /home/ubuntu/checkstyle/groovy-2.4.7/bin/groovy launch.groovy --listOfProjects projects-to-test-on.properties --config my_check.xml" TESTER_DEPENDENCIES: $CMD1$DEP1$DEP2$DEP3 - CMD2: " && sed -i.'' 's/^openjdk/#openjdk/' projects-for-circle.properties" - CMD3: " && sed -i.'' s/projects-to-test-on.properties/projects-for-circle.properties/ launch.sh" - CMD4: " && ./launch.sh -Dcheckstyle.config.location=checks-nonjavadoc-error.xml" - OPENJDK: " && sed -i.'' 's/#openjdk/openjdk/' projects-for-circle.properties" - INFINISPAN: " && sed -i.'' 's/#infinispan/infinispan/' projects-for-circle.properties" - PROTONPACK: " && sed -i.'' 's/#protonpack/protonpack/' projects-for-circle.properties" - JOOL: " && sed -i.'' 's/#jOOL/jOOL/' projects-for-circle.properties" - TAPESTRY: " && sed -i.'' 's/#tapestry5/tapestry5/' projects-for-circle.properties" - COMMONS: " && sed -i.'' 's/#apache-commons/apache-commons/' projects-for-circle.properties" - LUCENE: " && sed -i.'' 's/#lucene-solr/lucene-solr/' projects-for-circle.properties" - STORM: " && sed -i.'' 's/#storm/storm/' projects-for-circle.properties" - HADOOP: " && sed -i.'' 's/#hadoop/hadoop/' projects-for-circle.properties" - CASSANDRA: " && sed -i.'' 's/#cassandra/cassandra/' projects-for-circle.properties" - SCOUTER: " && sed -i.'' 's/#scouter/scouter/' projects-for-circle.properties" - GROOVY: " && sed -i.'' 's/#groovy/groovy/' projects-for-circle.properties" - # Test over openjdk7 - TEST_1: $CMD1$CMD2$OPENJDK$CMD3$CMD4 - # Test over infinispan, protonpack, jOOL, lucene-solr - TEST_2: $CMD1$CMD2$INFINISPAN$PROTONPACK$JOOL$LUCENE$CMD3$CMD4 + CMD2: " && sed -i'' 's/^openjdk/#openjdk/' projects-for-circle.properties" + CMD3: " && /home/ubuntu/checkstyle/groovy-2.4.7/bin/groovy launch.groovy --listOfProjects projects-for-circle.properties --config checks-nonjavadoc-error.xml" + OPENJDK7: " && sed -i'' 's/#openjdk7/openjdk7/' projects-for-circle.properties" + OPENJDK8: " && sed -i'' 's/#openjdk8/openjdk8/' projects-for-circle.properties" + OPENJDK9: " && sed -i'' 's/#openjdk9/openjdk9/' projects-for-circle.properties" + INFINISPAN: " && sed -i'' 's/#infinispan/infinispan/' projects-for-circle.properties" + PROTONPACK: " && sed -i'' 's/#protonpack/protonpack/' projects-for-circle.properties" + JOOL: " && sed -i'' 's/#jOOL/jOOL/' projects-for-circle.properties" + TAPESTRY: " && sed -i'' 's/#tapestry-5/tapestry-5/' projects-for-circle.properties" + COMMONS: " && sed -i'' 's/#apache-commons/apache-commons/' projects-for-circle.properties" + LUCENE: " && sed -i'' 's/#lucene-solr/lucene-solr/' projects-for-circle.properties" + STORM: " && sed -i'' 's/#storm/storm/' projects-for-circle.properties" + HADOOP: " && sed -i'' 's/#hadoop/hadoop/' projects-for-circle.properties" + CASSANDRA: " && sed -i'' 's/#cassandra/cassandra/' projects-for-circle.properties" + SCOUTER: " && sed -i'' 's/#scouter/scouter/' projects-for-circle.properties" + GROOVY: " && sed -i'' 's/#groovy/groovy/' projects-for-circle.properties" + # Test over openjdk7,8 + TEST_1: $CMD1$CMD2$OPENJDK7$OPENJDK8$CMD3 + # Test over infinispan, protonpack, jOOL, lucene-solr, openjdk9 + TEST_2: $CMD1$CMD2$INFINISPAN$PROTONPACK$JOOL$LUCENE$OPENJDK9$CMD3 # Test over tapestry5, storm, cassandra - TEST_3: $CMD1$CMD2$TAPESTRY$STORM$CASSANDRA$CMD3$CMD4 + TEST_3: $CMD1$CMD2$TAPESTRY$STORM$CASSANDRA$CMD3 # Test over apache-commons, hadoop, scouter, groovy - TEST_4: $CMD1$CMD2$COMMONS$HADOOP$SCOUTER$GROOVY$CMD3$CMD4 + TEST_4: $CMD1$CMD2$COMMONS$HADOOP$SCOUTER$GROOVY$CMD3 + SKIP_FILES: ".github|appveyor.yml|.travis.yml|.ci|distelli-manifest.yml|fast-forward-merge.sh|LICENSE|LICENSE.apache20|README.md|release.sh|RIGHTS.antlr|shippable.yml|wercker.yml|wercker.sh|intellij-idea-inspections.xml|org.eclipse.jdt.core.prefs" test: override: - - case $CIRCLE_NODE_INDEX in 0) eval $TEST_1 ;; 1) eval $TEST_2 ;; 2) eval $TEST_3 ;; 3) eval $TEST_4 ;; esac: + - if [ $(git diff --name-only HEAD HEAD~1 | grep -vE $SKIP_FILES | wc -c) -gt 0 ] ; then case $CIRCLE_NODE_INDEX in 0) eval $TEST_1 ;; 1) eval $TEST_2 ;; 2) eval $TEST_3 ;; 3) eval $TEST_4 ;; esac; fi: parallel: true diff -Nru checkstyle-6.15/.classpath checkstyle-8.8/.classpath --- checkstyle-6.15/.classpath 2016-01-30 16:08:52.000000000 +0000 +++ checkstyle-8.8/.classpath 1970-01-01 00:00:00.000000000 +0000 @@ -1,58 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff -Nru checkstyle-6.15/config/ant-phase-verify.xml checkstyle-8.8/config/ant-phase-verify.xml --- checkstyle-6.15/config/ant-phase-verify.xml 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/config/ant-phase-verify.xml 2017-12-27 15:23:07.000000000 +0000 @@ -12,19 +12,18 @@ classpath="${mvn.runtime_classpath}" /> - - - Checkstyle started: ${STARTED} + Checkstyle started (checkstyle_checks.xml): ${STARTED} + + + + + + + + Checkstyle finished (checkstyle_checks.xml) : ${FINISHED} + + + + + Checkstyle started (checkstyle_non_main_files_checks.xml): ${STARTED} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - Checkstyle finished: ${FINISHED} + Checkstyle finished (checkstyle_non_main_files_checks.xml): ${FINISHED} - @@ -38,6 +37,7 @@ + diff -Nru checkstyle-6.15/config/catalog.xml checkstyle-8.8/config/catalog.xml --- checkstyle-6.15/config/catalog.xml 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/config/catalog.xml 2017-12-27 15:23:07.000000000 +0000 @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff -Nru checkstyle-6.15/config/checkstyle_checks.xml checkstyle-8.8/config/checkstyle_checks.xml --- checkstyle-6.15/config/checkstyle_checks.xml 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/config/checkstyle_checks.xml 2017-12-30 14:59:46.000000000 +0000 @@ -1,7 +1,7 @@ + "http://checkstyle.sourceforge.net/dtds/configuration_1_3.dtd"> + + + @@ -24,28 +31,18 @@ - - - - - - - + - - - + + @@ -67,7 +64,7 @@ - + @@ -93,6 +90,11 @@ + + + + + @@ -108,9 +110,9 @@ - + - + @@ -128,15 +130,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + @@ -144,24 +176,53 @@ + + + + + + + + + + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + - - + @@ -191,11 +252,25 @@ - - + + + + + + - - + + + + + + + + + + + @@ -223,16 +298,11 @@ - - - + + + + - @@ -241,21 +311,47 @@ + + + + + + + + + + + + + + + + - + + + + + + + + - + @@ -301,7 +397,9 @@ - + + + @@ -312,7 +410,6 @@ - - + @@ -391,7 +489,7 @@ - + @@ -402,12 +500,14 @@ + + @@ -416,13 +516,42 @@ + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -441,12 +570,21 @@ + + + + + + + + + diff -Nru checkstyle-6.15/config/checkstyle_non_main_files_checks.xml checkstyle-8.8/config/checkstyle_non_main_files_checks.xml --- checkstyle-6.15/config/checkstyle_non_main_files_checks.xml 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/config/checkstyle_non_main_files_checks.xml 2017-09-04 20:01:01.000000000 +0000 @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + diff -Nru checkstyle-6.15/config/checkstyle_non_main_files_suppressions.xml checkstyle-8.8/config/checkstyle_non_main_files_suppressions.xml --- checkstyle-6.15/config/checkstyle_non_main_files_suppressions.xml 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/config/checkstyle_non_main_files_suppressions.xml 2017-10-26 12:59:58.000000000 +0000 @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru checkstyle-6.15/config/checkstyle_sevntu_checks.xml checkstyle-8.8/config/checkstyle_sevntu_checks.xml --- checkstyle-6.15/config/checkstyle_sevntu_checks.xml 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/config/checkstyle_sevntu_checks.xml 2017-11-26 14:05:03.000000000 +0000 @@ -2,17 +2,25 @@ + "http://checkstyle.sourceforge.net/dtds/configuration_1_2.dtd"> + + + + + + + + @@ -25,10 +33,22 @@ - + - + + + @@ -59,9 +79,6 @@ - - - @@ -70,17 +87,15 @@ - + - - - + @@ -88,8 +103,38 @@ - - + + + + + + + + + + + + + + + @@ -97,7 +142,7 @@ - + @@ -141,5 +186,28 @@ + + + + + + + + + + + + + + + + + + + + + + + diff -Nru checkstyle-6.15/config/default_sonar_profile.xml checkstyle-8.8/config/default_sonar_profile.xml --- checkstyle-6.15/config/default_sonar_profile.xml 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/config/default_sonar_profile.xml 2017-10-26 12:59:58.000000000 +0000 @@ -0,0 +1,1803 @@ + + + + checksyle-profile + java + + + + + squid + AssignmentInSubExpressionCheck + MAJOR + + + + + + squid + ClassVariableVisibilityCheck + MINOR + + + + + + squid + EmptyStatementUsageCheck + MINOR + + + + squid + ForLoopCounterChangedCheck + MAJOR + + + + squid + HiddenFieldCheck + MAJOR + + + + squid + LabelsShouldNotBeUsedCheck + MAJOR + + + + + + + + + squid + ModifiersOrderCheck + MINOR + + + + squid + ObjectFinalizeCheck + MAJOR + + + + squid + ObjectFinalizeOverridenCallsSuperFinalizeCheck + CRITICAL + + + + squid + ObjectFinalizeOverridenCheck + MAJOR + + + + squid + RedundantThrowsDeclarationCheck + MINOR + + + + squid + S00100 + MINOR + + + format + ^[a-z][a-zA-Z0-9]*$ + + + + + squid + S00101 + MINOR + + + format + ^[A-Z][a-zA-Z0-9]*$ + + + + + + + squid + S00108 + MAJOR + + + + + + squid + S00114 + MINOR + + + format + ^[A-Z][a-zA-Z0-9]*$ + + + + + + + squid + S00116 + MINOR + + + format + ^[a-z][a-zA-Z0-9]*$ + + + + + squid + S00117 + MINOR + + + format + ^[a-z][a-zA-Z0-9]*$ + + + + + squid + S00119 + MINOR + + + format + ^[A-Z][0-9]?$ + + + + + squid + S00120 + MINOR + + + format + ^[a-z]+(\.[a-z][a-z0-9]*)*$ + + + + + + + squid + S1065 + MAJOR + + + + + + squid + S1068 + MAJOR + + + + squid + S1075 + MINOR + + + + squid + S1118 + MAJOR + + + + squid + S1125 + MINOR + + + + squid + S1126 + MINOR + + + + + + + + + + squid + S1141 + MAJOR + + + + squid + S1143 + MAJOR + + + + + + squid + S1149 + MAJOR + + + + squid + S1150 + MAJOR + + + + squid + S1153 + MINOR + + + + squid + S1155 + MINOR + + + + squid + S1157 + MINOR + + + + squid + S1158 + MINOR + + + + squid + S1161 + MAJOR + + + + squid + S1163 + CRITICAL + + + + squid + S1165 + MINOR + + + + squid + S1168 + MAJOR + + + + squid + S1170 + MINOR + + + + squid + S1171 + MAJOR + + + + + + squid + S1174 + CRITICAL + + + + squid + S1175 + CRITICAL + + + + + + squid + S1182 + MINOR + + + + squid + S1185 + MINOR + + + + squid + S1186 + CRITICAL + + + + squid + S1190 + BLOCKER + + + + + + squid + S1192 + CRITICAL + + + threshold + 3 + + + + + squid + S1193 + MAJOR + + + + squid + S1195 + MINOR + + + + squid + S1197 + MINOR + + + + squid + S1199 + MINOR + + + + squid + S1201 + MAJOR + + + + squid + S1206 + MINOR + + + + squid + S1210 + MINOR + + + + squid + S1214 + CRITICAL + + + + squid + S1215 + CRITICAL + + + + squid + S1217 + MAJOR + + + + squid + S1219 + BLOCKER + + + + squid + S1220 + MINOR + + + + squid + S1221 + MAJOR + + + + squid + S1223 + MAJOR + + + + squid + S1226 + MINOR + + + + squid + S1244 + MAJOR + + + + squid + S1264 + MINOR + + + + squid + S128 + BLOCKER + + + + squid + S1301 + MINOR + + + + squid + S1313 + MINOR + + + + squid + S1317 + MAJOR + + + + squid + S1319 + MINOR + + + + squid + S135 + MINOR + + + + squid + S1444 + MINOR + + + + squid + S1450 + MINOR + + + + squid + S1452 + CRITICAL + + + + squid + S1479 + MAJOR + + + maximum + 30 + + + + + squid + S1481 + MINOR + + + + squid + S1488 + MINOR + + + + squid + S1596 + MINOR + + + + squid + S1598 + CRITICAL + + + + + + squid + S1604 + MAJOR + + + + squid + S1607 + MAJOR + + + + squid + S1610 + MINOR + + + + squid + S1611 + MINOR + + + + + + squid + S1640 + MINOR + + + + squid + S1643 + MINOR + + + + squid + S1656 + MAJOR + + + + squid + S1659 + MINOR + + + + squid + S1700 + MAJOR + + + + squid + S1710 + MINOR + + + + squid + S1751 + MAJOR + + + + squid + S1764 + MAJOR + + + + squid + S1844 + MAJOR + + + + + + squid + S1849 + MAJOR + + + + squid + S1854 + MAJOR + + + + squid + S1858 + MINOR + + + + squid + S1860 + MAJOR + + + + squid + S1862 + MAJOR + + + + squid + S1871 + MAJOR + + + + squid + S1872 + MAJOR + + + + squid + S1905 + MINOR + + + + squid + S1940 + MINOR + + + + + + squid + S1989 + MINOR + + + + squid + S1994 + CRITICAL + + + + squid + S2055 + MINOR + + + + squid + S2060 + MAJOR + + + + squid + S2061 + MAJOR + + + + squid + S2062 + CRITICAL + + + + squid + S2065 + MINOR + + + + squid + S2066 + MINOR + + + + squid + S2068 + BLOCKER + + + + squid + S2077 + BLOCKER + + + + squid + S2092 + MINOR + + + + + + squid + S2094 + MINOR + + + + + + squid + S2097 + MINOR + + + + squid + S2109 + MAJOR + + + + squid + S2110 + MAJOR + + + + squid + S2111 + MAJOR + + + + squid + S2112 + MAJOR + + + + squid + S2114 + MAJOR + + + + squid + S2116 + MAJOR + + + + squid + S2118 + MAJOR + + + + squid + S2122 + CRITICAL + + + + squid + S2123 + MAJOR + + + + squid + S2127 + MAJOR + + + + squid + S2129 + MAJOR + + + + squid + S2130 + MINOR + + + + squid + S2131 + MAJOR + + + + squid + S2133 + MAJOR + + + + squid + S2134 + MAJOR + + + + squid + S2140 + MINOR + + + + squid + S2142 + MAJOR + + + + squid + S2147 + MINOR + + + + squid + S2151 + CRITICAL + + + + squid + S2153 + MINOR + + + + squid + S2154 + MAJOR + + + + squid + S2157 + MAJOR + + + + squid + S2159 + MAJOR + + + + + + squid + S2165 + MINOR + + + + squid + S2166 + MAJOR + + + + squid + S2167 + MINOR + + + + squid + S2168 + BLOCKER + + + + squid + S2175 + MAJOR + + + + squid + S2176 + CRITICAL + + + + squid + S2177 + MAJOR + + + + squid + S2178 + BLOCKER + + + + squid + S2183 + MINOR + + + + squid + S2184 + MINOR + + + + squid + S2185 + MAJOR + + + + squid + S2186 + CRITICAL + + + + squid + S2187 + BLOCKER + + + + squid + S2188 + BLOCKER + + + + squid + S2189 + BLOCKER + + + + squid + S2200 + MINOR + + + + + + squid + S2204 + MAJOR + + + + squid + S2209 + MAJOR + + + + squid + S2222 + CRITICAL + + + + squid + S2225 + MAJOR + + + + squid + S2226 + MAJOR + + + + squid + S2230 + MAJOR + + + + squid + S2232 + MAJOR + + + + squid + S2235 + CRITICAL + + + + squid + S2236 + BLOCKER + + + + squid + S2251 + MAJOR + + + + squid + S2252 + MAJOR + + + + squid + S2254 + CRITICAL + + + + + + squid + S2272 + MINOR + + + + squid + S2273 + MAJOR + + + + squid + S2274 + CRITICAL + + + + squid + S2275 + BLOCKER + + + + squid + S2276 + BLOCKER + + + + squid + S2277 + CRITICAL + + + + squid + S2278 + BLOCKER + + + + squid + S2293 + MINOR + + + + squid + S2326 + MAJOR + + + + squid + S2386 + MINOR + + + + squid + S2387 + BLOCKER + + + + squid + S2388 + MAJOR + + + + squid + S2390 + MAJOR + + + + squid + S2391 + BLOCKER + + + + squid + S2437 + BLOCKER + + + + squid + S2438 + MAJOR + + + + squid + S2440 + MAJOR + + + + squid + S2441 + MAJOR + + + + squid + S2442 + MAJOR + + + + squid + S2445 + MAJOR + + + + squid + S2446 + MAJOR + + + + squid + S2447 + CRITICAL + + + + squid + S2583 + MAJOR + + + + squid + S2589 + MAJOR + + + + squid + S2629 + MAJOR + + + + squid + S2637 + MINOR + + + + squid + S2638 + CRITICAL + + + + squid + S2639 + MAJOR + + + + squid + S2653 + CRITICAL + + + + squid + S2674 + MINOR + + + + squid + S2675 + MAJOR + + + + squid + S2676 + MINOR + + + + squid + S2677 + MAJOR + + + + squid + S2681 + MAJOR + + + + squid + S2692 + CRITICAL + + + + squid + S2695 + BLOCKER + + + + squid + S2696 + CRITICAL + + + + squid + S2718 + MAJOR + + + + squid + S2786 + MINOR + + + + squid + S2789 + MAJOR + + + + squid + S2864 + MAJOR + + + + squid + S2885 + MAJOR + + + + squid + S2886 + MAJOR + + + + squid + S2912 + MINOR + + + + squid + S2924 + MINOR + + + + + + squid + S2970 + BLOCKER + + + + squid + S2975 + BLOCKER + + + + squid + S2976 + CRITICAL + + + + squid + S3008 + MINOR + + + format + ^[a-z][a-zA-Z0-9]*$ + + + + + squid + S3010 + MAJOR + + + + squid + S3020 + MINOR + + + + squid + S3027 + MAJOR + + + + squid + S3034 + MAJOR + + + + squid + S3038 + MINOR + + + + squid + S3042 + MAJOR + + + + squid + S3046 + BLOCKER + + + + squid + S3066 + MINOR + + + + squid + S3067 + MAJOR + + + + squid + S3281 + BLOCKER + + + + squid + S3346 + MAJOR + + + + squid + S3355 + CRITICAL + + + + squid + S3358 + MAJOR + + + + + + squid + S3400 + MINOR + + + + squid + S3421 + MINOR + + + + squid + S3422 + CRITICAL + + + + squid + S3437 + MINOR + + + + squid + S3438 + MAJOR + + + + squid + S3457 + MAJOR + + + + squid + S3518 + CRITICAL + + + + squid + S3599 + MINOR + + + + squid + S3631 + MAJOR + + + + squid + S3655 + MAJOR + + + + squid + S3725 + MAJOR + + + + + + squid + S3923 + MAJOR + + + + squid + S899 + MINOR + + + + squid + SwitchLastCaseIsDefaultCheck + CRITICAL + + + + + + squid + UselessImportCheck + MINOR + + + + squid + UselessParenthesesCheck + MAJOR + + + + diff -Nru checkstyle-6.15/config/findbugs-exclude.xml checkstyle-8.8/config/findbugs-exclude.xml --- checkstyle-6.15/config/findbugs-exclude.xml 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/config/findbugs-exclude.xml 2017-12-30 15:32:18.000000000 +0000 @@ -39,12 +39,6 @@ - - - - - - @@ -66,18 +60,11 @@ - - - - - - - - - + + @@ -87,7 +74,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru checkstyle-6.15/config/import-control-test.xml checkstyle-8.8/config/import-control-test.xml --- checkstyle-6.15/config/import-control-test.xml 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/config/import-control-test.xml 2017-11-09 14:30:16.000000000 +0000 @@ -0,0 +1,12 @@ + + + + + + + + + + diff -Nru checkstyle-6.15/config/import-control.xml checkstyle-8.8/config/import-control.xml --- checkstyle-6.15/config/import-control.xml 2015-11-13 05:06:18.000000000 +0000 +++ checkstyle-8.8/config/import-control.xml 2018-01-28 04:16:51.000000000 +0000 @@ -1,76 +1,184 @@ + "-//Puppy Crawl//DTD Import Control 1.3//EN" + "http://checkstyle.sourceforge.net/dtds/import_control_1_3.dtd"> - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + - - + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + - + + + + - + + + + + + + + + - + + + + + + + + + + + + + + + + + + diff -Nru checkstyle-6.15/config/intellij-idea-inspection-scope.xml checkstyle-8.8/config/intellij-idea-inspection-scope.xml --- checkstyle-6.15/config/intellij-idea-inspection-scope.xml 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/config/intellij-idea-inspection-scope.xml 2017-10-26 12:59:58.000000000 +0000 @@ -1,4 +1,4 @@ - + diff -Nru checkstyle-6.15/config/intellij-idea-inspections.properties checkstyle-8.8/config/intellij-idea-inspections.properties --- checkstyle-6.15/config/intellij-idea-inspections.properties 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/config/intellij-idea-inspections.properties 2017-10-26 12:59:58.000000000 +0000 @@ -0,0 +1,2 @@ +# this file is used by .ci/idea_inspection.sh and .ci/idea_inspection.bat +idea.exclude.patterns=.idea/**;src/test/resources/**;src/site/resources/js/google-analytics.js;src/test/java/com/puppycrawl/tools/checkstyle/checks/javadoc/ParseTreeBuilder.java;src/test/java/com/puppycrawl/tools/checkstyle/grammars/javadoc/ParseTreeBuilder.java;config/intellij-idea-inspections.properties diff -Nru checkstyle-6.15/config/intellij-idea-inspections.xml checkstyle-8.8/config/intellij-idea-inspections.xml --- checkstyle-6.15/config/intellij-idea-inspections.xml 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/config/intellij-idea-inspections.xml 2018-01-14 13:38:20.000000000 +0000 @@ -3,13 +3,13 @@ + [,1.9) @@ -1244,17 +1482,38 @@ + + no-validations + + true + true + true + true + true + true + true + true + true + true + + + + + assembly true - true - true + true true true true - true + true + true true + true + true + true @@ -1280,7 +1539,6 @@ org.apache.maven.plugins maven-shade-plugin - 2.4.3 package @@ -1288,6 +1546,16 @@ shade + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + true all @@ -1303,7 +1571,6 @@ maven-assembly-plugin - 2.6 config/assembly-bin.xml @@ -1327,443 +1594,12 @@ - jacoco-check + sonar - org.jacoco - jacoco-maven-plugin - ${maven.jacoco.plugin.version} - - - default-instrument - - instrument - - test-compile - - - default-restore-instrumented-classes - - restore-instrumented-classes - - - - default-report - site - - report - - - - default-check - - check - - - ${project.build.directory}/jacoco/jacoco.exec - - com/puppycrawl/tools/checkstyle/ant/CheckstyleAntTask*.class - com/puppycrawl/tools/checkstyle/grammars/*.class - com/puppycrawl/tools/checkstyle/grammars/javadoc/*.class - com/puppycrawl/tools/checkstyle/gui/*.class - - - - BUNDLE - - - LINE - COVEREDRATIO - 0.99 - - - BRANCH - COVEREDRATIO - 0.99 - - - - - PACKAGE - - com.puppycrawl.tools.checkstyle - - - - LINE - COVEREDRATIO - 0.99 - - - BRANCH - COVEREDRATIO - 0.97 - - - - - PACKAGE - - com.puppycrawl.tools.checkstyle.checks - - - - LINE - COVEREDRATIO - 0.93 - - - BRANCH - COVEREDRATIO - 0.93 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.coding.DeclarationOrderCheck - - - - LINE - COVEREDRATIO - 0.93 - - - BRANCH - COVEREDRATIO - 0.82 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.header.AbstractHeaderCheck - - - - LINE - COVEREDRATIO - 0.90 - - - BRANCH - COVEREDRATIO - 0.90 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.Main - - - - LINE - COVEREDRATIO - 0.92 - - - BRANCH - COVEREDRATIO - 0.84 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.PropertyCacheFile - - - - LINE - COVEREDRATIO - 0.97 - - - BRANCH - COVEREDRATIO - 1.00 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.TreeWalker.AstState - - - - LINE - COVEREDRATIO - 0.76 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.DefaultLogger - - - - LINE - COVEREDRATIO - 0.97 - - - BRANCH - COVEREDRATIO - 1.00 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.TranslationCheck - - - - LINE - COVEREDRATIO - 0.82 - - - BRANCH - COVEREDRATIO - 0.81 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.SuppressWarningsHolder - - - - LINE - COVEREDRATIO - 0.88 - - - BRANCH - COVEREDRATIO - 0.76 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.AbstractTypeAwareCheck - - - - LINE - COVEREDRATIO - 0.88 - - - BRANCH - COVEREDRATIO - 0.94 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck - - - - LINE - COVEREDRATIO - 0.74 - - - BRANCH - COVEREDRATIO - 0.83 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.AbstractTypeAwareCheck.RegularClass - - - - LINE - COVEREDRATIO - 0.62 - - - BRANCH - COVEREDRATIO - 0.83 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.AbstractTypeAwareCheck.Token - - - - LINE - COVEREDRATIO - 0.62 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.ClassResolver - - - - LINE - COVEREDRATIO - 0.91 - - - BRANCH - COVEREDRATIO - 0.83 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.AbstractTypeAwareCheck.ClassAlias - - - - LINE - COVEREDRATIO - 0.39 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.UniquePropertiesCheck - - - - LINE - COVEREDRATIO - 0.96 - - - BRANCH - COVEREDRATIO - 1.00 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.AbstractTypeAwareCheck.AbstractClassInfo - - - - LINE - COVEREDRATIO - 0.69 - - - BRANCH - COVEREDRATIO - 0.50 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.AbstractDeclarationCollector - - - - LINE - COVEREDRATIO - 1.00 - - - BRANCH - COVEREDRATIO - 0.94 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.UniquePropertiesCheck.UniqueProperties - - - - LINE - COVEREDRATIO - 1.00 - - - BRANCH - COVEREDRATIO - 0.75 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocUtils - - - - LINE - COVEREDRATIO - 0.99 - - - BRANCH - COVEREDRATIO - 0.98 - - - - - CLASS - - com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocUtils.JavadocTagType - - - - LINE - COVEREDRATIO - 0.81 - - - - - - - + org.codehaus.mojo + sonar-maven-plugin @@ -1772,15 +1608,15 @@ cobertura-check - 1.8 + [1.8,) org.codehaus.mojo cobertura-maven-plugin - 2.7 + true xml html @@ -1789,23 +1625,52 @@ true 100 100 - 100 - 100 + 84 + 89 + + + com.puppycrawl.tools.checkstyle.grammars.GeneratedJavaRecognizer + 72 + 96 + + + com.puppycrawl.tools.checkstyle.grammars.GeneratedJavaLexer + 79 + 96 + + + com.puppycrawl.tools.checkstyle.grammars.javadoc.JavadocParser + 42 + 53 + + + com.puppycrawl.tools.checkstyle.grammars.javadoc.JavadocLexer + 64 + 84 + + - com/puppycrawl/tools/checkstyle/ant/CheckstyleAntTask*.class - com/puppycrawl/tools/checkstyle/grammars/*.class - com/puppycrawl/tools/checkstyle/grammars/javadoc/*.class - com/puppycrawl/tools/checkstyle/gui/*.class + + com/puppycrawl/tools/checkstyle/grammars/javadoc/JavadocParser$*.class + + com/puppycrawl/tools/checkstyle/gui/BaseCellEditor*.class + com/puppycrawl/tools/checkstyle/gui/CodeSelector.class + com/puppycrawl/tools/checkstyle/gui/TreeTable*.class + com/puppycrawl/tools/checkstyle/gui/ListToTreeSelectionModelWrapper*.class + com/puppycrawl/tools/checkstyle/gui/Main*.class + com/puppycrawl/tools/checkstyle/gui/MainFrame*.class + com/puppycrawl/tools/checkstyle/gui/ParseTreeTableModel*.class + com/puppycrawl/tools/checkstyle/gui/TreeTableCellRenderer*.class + com/puppycrawl/tools/checkstyle/gui/TreeTableModelAdapter*.class - com/puppycrawl/tools/checkstyle/checks/AbstractFormatCheck.class - com/puppycrawl/tools/checkstyle/checks/AbstractDeclarationCollector*.class - com/puppycrawl/tools/checkstyle/checks/AbstractOptionCheck.class - com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalCheck.class - com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalMethodCheck.class - com/puppycrawl/tools/checkstyle/checks/coding/AbstractNestedDepthCheck.class - com/puppycrawl/tools/checkstyle/checks/metrics/AbstractComplexityCheck.class com/puppycrawl/tools/checkstyle/checks/naming/AbstractTypeParameterNameCheck.class @@ -1822,5 +1687,771 @@ + + pitest-checks-misc + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.ArrayTypeStyleCheck + com.puppycrawl.tools.checkstyle.checks.AvoidEscapedUnicodeCharactersCheck + com.puppycrawl.tools.checkstyle.checks.DescendantTokenCheck + com.puppycrawl.tools.checkstyle.checks.FileSetCheckLifecycle + com.puppycrawl.tools.checkstyle.checks.FinalParametersCheck + com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck + com.puppycrawl.tools.checkstyle.checks.OuterTypeFilenameCheck + + + com.puppycrawl.tools.checkstyle.checks.TodoCommentCheck + com.puppycrawl.tools.checkstyle.checks.TrailingCommentCheck + com.puppycrawl.tools.checkstyle.checks.TranslationCheck + com.puppycrawl.tools.checkstyle.checks.UncommentedMainCheck + com.puppycrawl.tools.checkstyle.checks.UniquePropertiesCheck + com.puppycrawl.tools.checkstyle.checks.UpperEllCheck + + + com.puppycrawl.tools.checkstyle.checks.ArrayTypeStyleCheckTest + com.puppycrawl.tools.checkstyle.checks.AvoidEscapedUnicodeCharactersCheckTest + com.puppycrawl.tools.checkstyle.checks.DescendantTokenCheckTest + com.puppycrawl.tools.checkstyle.checks.FinalParametersCheckTest + com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheckTest + com.puppycrawl.tools.checkstyle.checks.OuterTypeFilenameCheckTest + com.puppycrawl.tools.checkstyle.checks.SuppressWarningsHolderTest + com.puppycrawl.tools.checkstyle.checks.TodoCommentCheckTest + com.puppycrawl.tools.checkstyle.checks.TrailingCommentCheckTest + com.puppycrawl.tools.checkstyle.checks.TranslationCheckTest + com.puppycrawl.tools.checkstyle.checks.UncommentedMainCheckTest + com.puppycrawl.tools.checkstyle.checks.UniquePropertiesCheckTest + com.puppycrawl.tools.checkstyle.checks.UpperEllCheckTest + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-annotation + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationLocationCheck + com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationOnSameLineCheck + com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationUseStyleCheck + com.puppycrawl.tools.checkstyle.checks.annotation.MissingDeprecatedCheck + com.puppycrawl.tools.checkstyle.checks.annotation.MissingOverrideCheck + com.puppycrawl.tools.checkstyle.checks.annotation.PackageAnnotationCheck + com.puppycrawl.tools.checkstyle.checks.annotation.SuppressWarningsCheck + + + com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationLocationCheckTest + com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationOnSameLineCheckTest + com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationUseStyleCheckTest + com.puppycrawl.tools.checkstyle.checks.annotation.MissingDeprecatedCheckTest + com.puppycrawl.tools.checkstyle.checks.annotation.MissingOverrideCheckTest + com.puppycrawl.tools.checkstyle.checks.annotation.PackageAnnotationCheckTest + com.puppycrawl.tools.checkstyle.checks.annotation.SuppressWarningsCheckTest + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-blocks + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.blocks.* + + + com.puppycrawl.tools.checkstyle.checks.blocks.* + + 100 + 97 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-coding + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.coding.* + + + com.puppycrawl.tools.checkstyle.checks.coding.* + + 100 + 98 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-design + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.design.* + + + com.puppycrawl.tools.checkstyle.checks.design.* + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-header + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.header.* + + + com.puppycrawl.tools.checkstyle.checks.header.* + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-imports + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.imports.* + + + com.puppycrawl.tools.checkstyle.checks.imports.* + + 100 + 96 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-indentation + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.indentation.* + + + com.puppycrawl.tools.checkstyle.checks.indentation.* + + 100 + 94 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-javadoc + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.javadoc.* + + + com.puppycrawl.tools.checkstyle.checks.javadoc.* + + 100 + 95 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-metrics + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.metrics.* + + + com.puppycrawl.tools.checkstyle.checks.metrics.* + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-modifier + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.modifier.* + + + com.puppycrawl.tools.checkstyle.checks.modifier.* + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-naming + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.naming.* + + + com.puppycrawl.tools.checkstyle.checks.naming.* + + + + com.puppycrawl.tools.checkstyle.checks.naming.AbstractTypeParameterNameCheck + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-regexp + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.regexp.* + + + com.puppycrawl.tools.checkstyle.checks.regexp.* + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-sizes + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.sizes.* + + + com.puppycrawl.tools.checkstyle.checks.sizes.* + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checks-whitespace + + true + + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.checks.whitespace.* + + + com.puppycrawl.tools.checkstyle.checks.whitespace.* + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + + pitest-checkstyle-common + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.AuditEventDefaultFormatter + com.puppycrawl.tools.checkstyle.ConfigurationLoader* + com.puppycrawl.tools.checkstyle.PackageNamesLoader + com.puppycrawl.tools.checkstyle.DefaultConfiguration + com.puppycrawl.tools.checkstyle.DefaultContext + com.puppycrawl.tools.checkstyle.DefaultLogger + com.puppycrawl.tools.checkstyle.Definitions + com.puppycrawl.tools.checkstyle.XMLLogger + com.puppycrawl.tools.checkstyle.PackageObjectFactory + com.puppycrawl.tools.checkstyle.PropertiesExpander + com.puppycrawl.tools.checkstyle.PropertyCacheFile + com.puppycrawl.tools.checkstyle.Checker + com.puppycrawl.tools.checkstyle.ant.* + com.puppycrawl.tools.checkstyle.doclets.* + com.puppycrawl.tools.checkstyle.ThreadModeSettings + + + com.puppycrawl.tools.checkstyle.AuditEventDefaultFormatterTest + com.puppycrawl.tools.checkstyle.ConfigurationLoaderTest + com.puppycrawl.tools.checkstyle.PackageNamesLoaderTest + com.puppycrawl.tools.checkstyle.DefaultConfigurationTest + com.puppycrawl.tools.checkstyle.DefaultLoggerTest + com.puppycrawl.tools.checkstyle.DefinitionsTest + com.puppycrawl.tools.checkstyle.XMLLoggerTest + com.puppycrawl.tools.checkstyle.PackageObjectFactoryTest + com.puppycrawl.tools.checkstyle.PropertiesExpanderTest + com.puppycrawl.tools.checkstyle.PropertyCacheFileTest + com.puppycrawl.tools.checkstyle.CheckerTest + com.puppycrawl.tools.checkstyle.ant.* + com.puppycrawl.tools.checkstyle.doclets.* + com.puppycrawl.tools.checkstyle.ThreadModeSettingsTest + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checkstyle-main + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.Main + + + com.puppycrawl.tools.checkstyle.MainTest + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checkstyle-tree-walker + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser + com.puppycrawl.tools.checkstyle.DetailNodeTreeStringPrinter + com.puppycrawl.tools.checkstyle.AstTreeStringPrinter + com.puppycrawl.tools.checkstyle.TreeWalker + + + com.puppycrawl.tools.checkstyle.DetailNodeTreeStringPrinterTest + com.puppycrawl.tools.checkstyle.AstTreeStringPrinterTest + com.puppycrawl.tools.checkstyle.TreeWalkerTest + com.puppycrawl.tools.checkstyle.checks.coding.PackageDeclarationCheckTest + com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest + com.puppycrawl.tools.checkstyle.checks.indentation.IndentationCheckTest + com.puppycrawl.tools.checkstyle.checks.javadoc.* + com.puppycrawl.tools.checkstyle.checks.metrics.ClassDataAbstractionCouplingCheckTest + com.puppycrawl.tools.checkstyle.checks.naming.TypeNameCheckTest + com.puppycrawl.tools.checkstyle.checks.regexp.RegexpSinglelineJavaCheckTest + com.puppycrawl.tools.checkstyle.checks.sizes.MethodCountCheckTest + com.puppycrawl.tools.checkstyle.checks.whitespace.SingleSpaceSeparatorCheckTest + com.puppycrawl.tools.checkstyle.checks.whitespace.EmptyLineSeparatorCheckTest + + + + destroy + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checkstyle-api + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.api.* + + + com.puppycrawl.tools.checkstyle.api.* + com.puppycrawl.tools.checkstyle.grammars.comments.CommentsTest + com.puppycrawl.tools.checkstyle.filefilters.* + com.puppycrawl.tools.checkstyle.filters.* + com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheckTest + com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheckTest + com.puppycrawl.tools.checkstyle.checks.javadoc.WriteTagCheckTest + com.puppycrawl.tools.checkstyle.checks.naming.ParameterNameCheckTest + com.puppycrawl.tools.checkstyle.ConfigurationLoaderTest + com.puppycrawl.tools.checkstyle.checks.TranslationCheckTest + + + + addFeaturesForVerySecureJavaInstallations + + + + com.puppycrawl.tools.checkstyle.XmlLoader$FeaturesForVerySecureJavaInstallations + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checkstyle-filters + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.filefilters.* + com.puppycrawl.tools.checkstyle.filters.* + + + com.puppycrawl.tools.checkstyle.filefilters.* + com.puppycrawl.tools.checkstyle.filters.* + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checkstyle-utils + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.utils.* + + + com.puppycrawl.tools.checkstyle.utils.* + + com.puppycrawl.tools.checkstyle.AstTreeStringPrinterTest + + com.puppycrawl.tools.checkstyle.DetailNodeTreeStringPrinterTest + + com.puppycrawl.tools.checkstyle.PackageObjectFactoryTest + + com.puppycrawl.tools.checkstyle.checks.javadoc.AbstractJavadocCheckTest + com.puppycrawl.tools.checkstyle.checks.javadoc.SingleLineJavadocCheckTest + com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocVariableCheckTest + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + pitest-checkstyle-gui + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.gui.* + + + com.puppycrawl.tools.checkstyle.gui.* + + 100 + 30 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + + + eclipse-compiler + + + org.eclipse.jdt + org.eclipse.jdt.annotation + 2.1.0 + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + .ci/eclipse-compiler-javac.sh + test + + + + + + + + + + pitest-checkstyle-xpath + + + + org.pitest + pitest-maven + ${pitest.plugin.version} + + + com.puppycrawl.tools.checkstyle.xpath.* + + + com.puppycrawl.tools.checkstyle.xpath.* + + 100 + 100 + ${pitest.plugin.timeout.factor} + ${pitest.plugin.timeout.constant} + ${pitest.plugin.threads} + + + + + diff -Nru checkstyle-6.15/.project checkstyle-8.8/.project --- checkstyle-6.15/.project 2016-01-30 16:05:33.000000000 +0000 +++ checkstyle-8.8/.project 1970-01-01 00:00:00.000000000 +0000 @@ -1,23 +0,0 @@ - - - checkstyle - - - - - - org.eclipse.jdt.core.javabuilder - - - - - org.eclipse.m2e.core.maven2Builder - - - - - - org.eclipse.jdt.core.javanature - org.eclipse.m2e.core.maven2Nature - - diff -Nru checkstyle-6.15/README.md checkstyle-8.8/README.md --- checkstyle-6.15/README.md 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/README.md 2018-01-22 14:58:53.000000000 +0000 @@ -3,21 +3,22 @@ [![][teamcity img]][teamcity] [![][codeship img]][codeship] [![][circleci img]][circleci] +[![][wercker img]][wercker] +[![][shippable img]][shippable] [![][coverage img]][coverage] [![][mavenbadge img]][mavenbadge] -[![][versioneye img]][versioneye] [![][sonar img]][sonar] -Members chat: [![][gitter img]][gitter] -Contributors chat: [![https://gitter.im/checkstyle/checkstyle](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/checkstyle/checkstyle?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +Members chat: [![][gitter_mem img]][gitter_mem] +Contributors chat: [![][gitter_con img]][gitter_con] ![](https://raw.githubusercontent.com/checkstyle/resources/master/img/checkstyle-logos/checkstyle-logo-260x99.png) Checkstyle is a tool for checking Java source code for adherence to a Code Standard or set of validation rules (best practices). -The latest release version can be found at [SourceForge downloads](http://sourceforge.net/projects/checkstyle/files/checkstyle/) or at [Maven repo](http://repo1.maven.org/maven2/com/puppycrawl/tools/checkstyle/). +The latest release version can be found at [SourceForge downloads](https://sourceforge.net/projects/checkstyle/files/checkstyle/) or at [Maven repo](http://repo1.maven.org/maven2/com/puppycrawl/tools/checkstyle/). Each-commit builds of maven artifacts can be found at [Maven Snapshot repository](https://oss.sonatype.org/content/repositories/snapshots/com/puppycrawl/tools/checkstyle/). @@ -27,6 +28,7 @@ ====================== Travis (Linux & MacOS build): [![][travis img]][travis] Appveyor (Windows build): [![][appveyor img]][appveyor] +[Distelli CI](https://www.distelli.com/checkstyle/builds) Quality reports: http://checkstyle.sourceforge.net/project-reports.html @@ -39,7 +41,7 @@ Questions and Answers from community: [![][stackoverflow img]][stackoverflow] -Bugs and Feature requests: https://github.com/checkstyle/checkstyle/issues +Bugs and Feature requests (not the questions): https://github.com/checkstyle/checkstyle/issues Licensing ========= @@ -49,7 +51,7 @@ This software is licensed under the terms in the file named "LICENSE" in this directory. -The software uses the ANTLR package (http://www.antlr.org). Its license terms +The software uses the ANTLR package (http://www.antlr.org/). Its license terms are in the file named "RIGHTS.antlr" in this directory. This product includes software developed by @@ -66,36 +68,33 @@ directory. [travis]:https://travis-ci.org/checkstyle/checkstyle/builds -[travis img]:https://secure.travis-ci.org/checkstyle/checkstyle.png +[travis img]:https://travis-ci.org/checkstyle/checkstyle.svg [appveyor]:https://ci.appveyor.com/project/checkstyle/checkstyle/history [appveyor img]:https://ci.appveyor.com/api/projects/status/rw6bw3dl9kph6ucc?svg=true -[sonar]:http://nemo.sonarqube.org/dashboard/index/com.puppycrawl.tools:checkstyle -[sonar img]:https://img.shields.io/sonar/http/nemo.sonarqube.org/com.puppycrawl.tools:checkstyle/tech_debt.svg?label=Sonarqube%20tech%20debt +[sonar]:https://sonarcloud.io/dashboard?id=com.puppycrawl.tools%3Acheckstyle +[sonar img]:https://sonarcloud.io/api/badges/measure?key=com.puppycrawl.tools:checkstyle&metric=sqale_debt_ratio [codacy]:https://www.codacy.com/app/checkstyle/checkstyle [codacy img]:https://api.codacy.com/project/badge/3adf12d434314ba8b38277ea46d3c44b -[coverage]:http://codecov.io/github/checkstyle/checkstyle?branch=master -[coverage img]:http://codecov.io/github/checkstyle/checkstyle/coverage.svg?branch=master +[coverage]:https://codecov.io/github/checkstyle/checkstyle?branch=master +[coverage img]:https://codecov.io/github/checkstyle/checkstyle/coverage.svg?branch=master [license]:LICENSE [license img]:https://img.shields.io/badge/license-GNU%20LGPL%20v2.1-blue.svg -[mavenbadge]:http://search.maven.org/#search|gav|1|g%3A%22com.puppycrawl.tools%22%20AND%20a%3A%22checkstyle%22 +[mavenbadge]:https://search.maven.org/#search|gav|1|g%3A%22com.puppycrawl.tools%22%20AND%20a%3A%22checkstyle%22 [mavenbadge img]:https://maven-badges.herokuapp.com/maven-central/com.puppycrawl.tools/checkstyle/badge.svg -[versioneye]:https://www.versioneye.com/user/projects/5504ca834a1064774400049a -[versioneye img]:https://www.versioneye.com/user/projects/5504ca834a1064774400049a/badge.svg +[gitter_mem]:https://gitter.im/checkstyle +[gitter_mem img]:https://img.shields.io/badge/gitter-JOIN%20CHAT-blue.svg -[gitter]:https://gitter.im/checkstyle -[gitter img]:http://img.shields.io/badge/gitter-JOIN%20CHAT-blue.svg +[gitter_con]:https://gitter.im/checkstyle/checkstyle +[gitter_con img]:https://badges.gitter.im/Join%20Chat.svg -[gitterpublic]:https://gitter.im/checkstyle/checkstyle -[gitterpublic img]:https://badges.gitter.im/Join%20Chat.svg) - -[stackoverflow]:http://stackoverflow.com/questions/tagged/checkstyle +[stackoverflow]:https://stackoverflow.com/questions/tagged/checkstyle [stackoverflow img]:https://img.shields.io/badge/stackoverflow-CHECKSTYLE-blue.svg [teamcity]:https://teamcity.jetbrains.com/viewType.html?buildTypeId=Checkstyle_IdeaInspectionsMaster @@ -106,3 +105,11 @@ [circleci]: https://circleci.com/gh/checkstyle/checkstyle/tree/master [circleci img]: https://circleci.com/gh/checkstyle/checkstyle/tree/master.svg?style=svg + +[wercker]: https://app.wercker.com/project/bykey/cd383127330ff96f89f1a78e8fd1a557 +[wercker img]: https://app.wercker.com/status/cd383127330ff96f89f1a78e8fd1a557/s/master + +[shippable]: https://app.shippable.com/projects/577032be3be4f4faa56adb38 +[shippable img]: https://img.shields.io/shippable/577032be3be4f4faa56adb38/master.svg?label=shippable + + diff -Nru checkstyle-6.15/release.sh checkstyle-8.8/release.sh --- checkstyle-6.15/release.sh 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/release.sh 2018-01-01 16:10:37.000000000 +0000 @@ -0,0 +1,68 @@ +#!/usr/bin/env bash +set -e + +# Make sure you prepared your PC for automative deployment +# https://github.com/checkstyle/checkstyle/wiki/How-to-make-a-release + +SF_USER=romanivanov +RELEASE=$(xmlstarlet sel -N pom=http://maven.apache.org/POM/4.0.0 -t -m pom:project -v pom:version pom.xml | sed "s/-SNAPSHOT//") +PREV_RELEASE=$(git describe $(git rev-list --tags --max-count=1) | sed "s/checkstyle-//") + +echo "PREVIOUS RELEASE version:"$PREV_RELEASE +echo "RELEASE version:"$RELEASE + +if [[ -z $RELEASE ]]; then + echo "Problem to calculate release version." + exit 1 +fi +if [[ -z $PREV_RELEASE ]]; then + echo "Problem to calculate previous release version." + exit 1 +fi + +############################# +echo "Please provide password for $SF_USER,checkstyle@shell.sourceforge.net" +echo "exit" | ssh -t $SF_USER,checkstyle@shell.sourceforge.net create + +# Version bump in pom.xml - https://github.com/checkstyle/checkstyle/commits/master +mvn -e -Pgpg release:prepare -B -Darguments="-DskipTests -DskipITs -Dpmd.skip=true -Dfindbugs.skip=true -Dcobertura.skip=true -Dcheckstyle.ant.skip=true -Dcheckstyle.skip=true -Dxml.skip=true" + +# deployment of jars to maven central and publication of site to http://checkstyle.sourceforge.net/new-site/ +mvn -e -Pgpg release:perform -Darguments='-Dcheckstyle.ant.skip=true -Dcheckstyle.skip=true' + +############################# + +ssh $SF_USER,checkstyle@shell.sourceforge.net << EOF + + +#Swap html content +cd /home/project-web/checkstyle +mv htdocs/new-site/ . +mv htdocs htdocs-$PREV_RELEASE +mv new-site htdocs +ln -s /home/project-web/checkstyle/reports htdocs/reports + +#Archiving +tar cfz htdocs-$PREV_RELEASE.tar.gz htdocs-$PREV_RELEASE/ +rm -rf htdocs-$PREV_RELEASE/ + +EOF + +############################## + +git checkout checkstyle-$RELEASE + +#Generate all binaries +mvn -e -Passembly clean package + +#Publish them to sourceforce +FRS_PATH=/home/frs/project/checkstyle/checkstyle/$RELEASE +ssh $SF_USER,checkstyle@shell.sourceforge.net "mkdir -p $FRS_PATH" +# !!! THIS WILL ASK A SOURCEFORGE PASSWORD !! +scp target/*.jar $SF_USER@frs.sourceforge.net:$FRS_PATH +scp target/*.tar.gz $SF_USER@frs.sourceforge.net:$FRS_PATH +scp target/*.zip $SF_USER@frs.sourceforge.net:$FRS_PATH + +git checkout master + +############################## diff -Nru checkstyle-6.15/shippable.yml checkstyle-8.8/shippable.yml --- checkstyle-6.15/shippable.yml 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/shippable.yml 2017-12-31 17:11:38.000000000 +0000 @@ -0,0 +1,91 @@ +language: java + + +jdk: + - oraclejdk8 + +env: + matrix: + - PROFILE="-Ppitest-checkstyle-xpath,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checkstyle-filters,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checks-javadoc,no-validations" + - PROFILE="-Ppitest-checks-imports,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checks-metrics,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checks-regexp,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checks-sizes,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checks-whitespace,no-validations"; POST_ACTION=check_survived + - PROFILE="-Ppitest-checks-misc,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checks-blocks,no-validations"; POST_ACTION=check_survived_blocks + - PROFILE="-Ppitest-checks-coding,no-validations"; POST_ACTION=check_survived_coding + - PROFILE="-Ppitest-checks-design,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checks-annotation,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checks-header,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checks-modifier,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checks-naming,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checks-indentation,no-validations" + - PROFILE="-Ppitest-checkstyle-tree-walker,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checkstyle-common,no-validations"; POST_ACTION=check_survived + - PROFILE="-Ppitest-checkstyle-main,no-validations"; POST_ACTION=check_survived_uncovered + - PROFILE="-Ppitest-checkstyle-api,no-validations"; POST_ACTION=check_survived + - PROFILE="-Ppitest-checkstyle-utils,no-validations"; POST_ACTION=check_survived + - PROFILE="-Ppitest-checkstyle-gui,no-validations" + +branches: + only: + - master + +build: + cache: true + cache_dir_list: + - /root/.m2 + + ci: + # we skip PRs and commits that are not for Issues, as pitest is too time consuming + - | + set -e + SKIP_FILES="appveyor.yml|circle.yml|distelli-manifest.yml|.travis.yml|wercker.yml|wercker.sh|fast-forward-merge.sh|LICENSE|LICENSE.apache20|README.md|release.sh|RIGHTS.antlr|intellij-idea-inspections.xml|org.eclipse.jdt.core.prefs" + SKIP_CI=$(if [[ $(git diff --name-only HEAD HEAD~1 | grep -vE "$SKIP_FILES" | cat | wc -c) > 0 ]]; then echo false; else echo true; fi;) + echo "SKIP_CI="$SKIP_CI + echo "POST_ACTION="$POST_ACTION + if [[ $SKIP_CI == 'false' ]]; + then + mvn -e $PROFILE clean verify org.pitest:pitest-maven:mutationCoverage; + + if [[ $POST_ACTION == 'check_survived_uncovered' \ + && ( $(grep -RE "class='survived'" target/ | cat | wc -l) > 0 \ + || $(grep -RE "class='uncovered'" target/ | cat | wc -l) > 0) ]]; then + echo "Survived items:"$(grep -RE "class='survived'" target/ | cat) + echo "Uncovered items:"$(grep -RE "class='uncovered'" target/ | cat) + echo "Survived/Uncovered items found in reports, build will be failed" + exit 1 + fi + if [[ $POST_ACTION == 'check_survived' && $(grep -RE "class='survived'" target/ | cat | wc -l) > 0 ]]; then + echo "Survived items:"$(grep -RE "class='survived'" target/ | cat) + echo "Survived items found in reports, build will be failed" + exit 1 + fi + if [[ $POST_ACTION == 'check_survived_blocks' && $(grep -RE "class='survived'" --exclude="LeftCurlyCheck.*" target/ | cat | wc -l) > 0 ]]; then + echo "Survived items:"$(grep -RE "class='survived'" --exclude="LeftCurlyCheck.*" target/ | cat) + echo "Survived items found in reports, build will be failed" + exit 1 + fi + if [[ $POST_ACTION == 'check_survived_coding' + && $(grep -RE "class='survived'" --exclude="EqualsAvoidNullCheck.*" \ + --exclude="FallThroughCheck.*" --exclude="HiddenFieldCheck.*" --exclude="IllegalInstantiationCheck.*" \ + --exclude="IllegalTypeCheck.*" \ + --exclude="MultipleVariableDeclarationsCheck.*" \ + --exclude="RequireThisCheck.*" \ + --exclude="UnnecessaryParenthesesCheck.*" --exclude="VariableDeclarationUsageDistanceCheck.*" target/ | cat | wc -l) > 0 ]]; then + echo "Survived items:"$(grep -RE "class='survived'" --exclude="EqualsAvoidNullCheck.*" \ + --exclude="FallThroughCheck.*" --exclude="HiddenFieldCheck.*" --exclude="IllegalInstantiationCheck.*" \ + --exclude="IllegalTypeCheck.*" \ + --exclude="MultipleVariableDeclarationsCheck.*" \ + --exclude="RequireThisCheck.*" \ + --exclude="UnnecessaryParenthesesCheck.*" --exclude="VariableDeclarationUsageDistanceCheck.*" target/ | cat) + echo "Survived items found in reports, build will be failed" + exit 1 + fi + else + echo "Build is skipped, changed files:" + git diff --name-only HEAD HEAD~1 + fi diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/AbstractIndentationTestSupport.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/AbstractIndentationTestSupport.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/AbstractIndentationTestSupport.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/AbstractIndentationTestSupport.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,221 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.google.checkstyle.test.base; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; + +public abstract class AbstractIndentationTestSupport extends AbstractModuleTestSupport { + + private static final int TAB_WIDTH = 4; + + private static final Pattern NONEMPTY_LINE_REGEX = + Pattern.compile(".*?\\S+.*?"); + + private static final Pattern LINE_WITH_COMMENT_REGEX = + Pattern.compile(".*?\\S+.*?(//indent:(\\d+) exp:((>=\\d+)|(\\d+(,\\d+)*?))( warn)?)"); + + private static final Pattern GET_INDENT_FROM_COMMENT_REGEX = + Pattern.compile("//indent:(\\d+).*?"); + + private static final Pattern MULTILEVEL_COMMENT_REGEX = + Pattern.compile("//indent:\\d+ exp:(\\d+(,\\d+)+?)( warn)?"); + + private static final Pattern SINGLE_LEVEL_COMMENT_REGEX = + Pattern.compile("//indent:\\d+ exp:(\\d+)( warn)?"); + + private static final Pattern NON_STRICT_LEVEL_COMMENT_REGEX = + Pattern.compile("//indent:\\d+ exp:>=(\\d+)( warn)?"); + + @Override + protected Integer[] getLinesWithWarn(String fileName) throws IOException { + return getLinesWithWarnAndCheckComments(fileName, TAB_WIDTH); + } + + private static Integer[] getLinesWithWarnAndCheckComments(String aFileName, + final int tabWidth) + throws IOException { + final List result = new ArrayList<>(); + try (BufferedReader br = new BufferedReader(new InputStreamReader( + new FileInputStream(aFileName), StandardCharsets.UTF_8))) { + int lineNumber = 1; + for (String line = br.readLine(); line != null; line = br.readLine()) { + final Matcher match = LINE_WITH_COMMENT_REGEX.matcher(line); + if (match.matches()) { + final String comment = match.group(1); + final int indentInComment = getIndentFromComment(comment); + final int actualIndent = getLineStart(line, tabWidth); + + if (actualIndent != indentInComment) { + throw new IllegalStateException(String.format(Locale.ROOT, + "File \"%1$s\" has incorrect indentation in comment." + + "Line %2$d: comment:%3$d, actual:%4$d.", + aFileName, + lineNumber, + indentInComment, + actualIndent)); + } + + if (isWarnComment(comment)) { + result.add(lineNumber); + } + + if (!isCommentConsistent(comment)) { + throw new IllegalStateException(String.format(Locale.ROOT, + "File \"%1$s\" has inconsistent comment on line %2$d", + aFileName, + lineNumber)); + } + } + else if (NONEMPTY_LINE_REGEX.matcher(line).matches()) { + throw new IllegalStateException(String.format(Locale.ROOT, + "File \"%1$s\" has no indentation comment or its format " + + "malformed. Error on line: %2$d(%3$s)", + aFileName, + lineNumber, + line)); + } + lineNumber++; + } + } + return result.toArray(new Integer[result.size()]); + } + + private static int getIndentFromComment(String comment) { + final Matcher match = GET_INDENT_FROM_COMMENT_REGEX.matcher(comment); + match.matches(); + return Integer.parseInt(match.group(1)); + } + + private static boolean isWarnComment(String comment) { + return comment.endsWith(" warn"); + } + + private static boolean isCommentConsistent(String comment) { + final int indentInComment = getIndentFromComment(comment); + final boolean isWarnComment = isWarnComment(comment); + + final boolean result; + final CommentType type = getCommentType(comment); + switch (type) { + case MULTILEVEL: + result = isMultiLevelCommentConsistent(comment, indentInComment, isWarnComment); + break; + + case SINGLE_LEVEL: + result = isSingleLevelCommentConsistent(comment, indentInComment, isWarnComment); + break; + + case NON_STRICT_LEVEL: + result = isNonStrictCommentConsistent(comment, indentInComment, isWarnComment); + break; + + case UNKNOWN: + throw new IllegalArgumentException("Cannot determine comment consistent"); + + default: + throw new IllegalStateException("Cannot determine comment is consistent"); + } + return result; + } + + private static boolean isNonStrictCommentConsistent(String comment, + int indentInComment, boolean isWarnComment) { + final Matcher nonStrictLevelMatch = NON_STRICT_LEVEL_COMMENT_REGEX.matcher(comment); + nonStrictLevelMatch.matches(); + final int expectedMinimalIndent = Integer.parseInt(nonStrictLevelMatch.group(1)); + + return indentInComment >= expectedMinimalIndent && !isWarnComment + || indentInComment < expectedMinimalIndent && isWarnComment; + } + + private static boolean isSingleLevelCommentConsistent(String comment, + int indentInComment, boolean isWarnComment) { + final Matcher singleLevelMatch = SINGLE_LEVEL_COMMENT_REGEX.matcher(comment); + singleLevelMatch.matches(); + final int expectedLevel = Integer.parseInt(singleLevelMatch.group(1)); + + return expectedLevel == indentInComment && !isWarnComment + || expectedLevel != indentInComment && isWarnComment; + } + + private static boolean isMultiLevelCommentConsistent(String comment, + int indentInComment, boolean isWarnComment) { + final Matcher multilevelMatch = MULTILEVEL_COMMENT_REGEX.matcher(comment); + multilevelMatch.matches(); + final String[] levels = multilevelMatch.group(1).split(","); + final String indentInCommentStr = String.valueOf(indentInComment); + final boolean containsActualLevel = + Arrays.asList(levels).contains(indentInCommentStr); + + return containsActualLevel && !isWarnComment + || !containsActualLevel && isWarnComment; + } + + private static CommentType getCommentType(String comment) { + CommentType result = CommentType.UNKNOWN; + final Matcher multilevelMatch = MULTILEVEL_COMMENT_REGEX.matcher(comment); + if (multilevelMatch.matches()) { + result = CommentType.MULTILEVEL; + } + else { + final Matcher singleLevelMatch = SINGLE_LEVEL_COMMENT_REGEX.matcher(comment); + if (singleLevelMatch.matches()) { + result = CommentType.SINGLE_LEVEL; + } + else { + final Matcher nonStrictLevelMatch = NON_STRICT_LEVEL_COMMENT_REGEX.matcher(comment); + if (nonStrictLevelMatch.matches()) { + result = CommentType.NON_STRICT_LEVEL; + } + } + } + return result; + } + + private static int getLineStart(String line, final int tabWidth) { + int lineStart = 0; + for (int index = 0; index < line.length(); ++index) { + if (!Character.isWhitespace(line.charAt(index))) { + lineStart = CommonUtils.lengthExpandedTabs(line, index, tabWidth); + break; + } + } + return lineStart; + } + + private enum CommentType { + + MULTILEVEL, SINGLE_LEVEL, NON_STRICT_LEVEL, UNKNOWN + + } + +} diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/AbstractModuleTestSupport.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/AbstractModuleTestSupport.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/AbstractModuleTestSupport.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/AbstractModuleTestSupport.java 2018-01-28 04:16:51.000000000 +0000 @@ -0,0 +1,416 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.google.checkstyle.test.base; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.LineNumberReader; +import java.nio.charset.StandardCharsets; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.regex.Pattern; + +import com.puppycrawl.tools.checkstyle.Checker; +import com.puppycrawl.tools.checkstyle.ConfigurationLoader; +import com.puppycrawl.tools.checkstyle.DefaultConfiguration; +import com.puppycrawl.tools.checkstyle.PropertiesExpander; +import com.puppycrawl.tools.checkstyle.TreeWalker; +import com.puppycrawl.tools.checkstyle.api.AbstractViolationReporter; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.internal.utils.BriefUtLogger; +import com.puppycrawl.tools.checkstyle.internal.utils.CheckUtil; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; +import com.puppycrawl.tools.checkstyle.utils.ModuleReflectionUtils; + +public abstract class AbstractModuleTestSupport extends AbstractPathTestSupport { + + /** + * Enum to specify options for checker creation. + */ + public enum ModuleCreationOption { + + /** + * Points that the module configurations + * has to be added under {@link TreeWalker}. + */ + IN_TREEWALKER, + /** + * Points that checker will be created as + * a root of default configuration. + */ + IN_CHECKER + + } + + private static final Pattern WARN_PATTERN = CommonUtils + .createPattern(".*[ ]*//[ ]*warn[ ]*|/[*]\\s?warn\\s?[*]/"); + + private static final String XML_NAME = "/google_checks.xml"; + + private static final Configuration CONFIGURATION; + + private static final Set> CHECKSTYLE_MODULES; + + private final ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + static { + try { + CONFIGURATION = ConfigurationLoader.loadConfiguration(XML_NAME, + new PropertiesExpander(System.getProperties())); + } + catch (CheckstyleException ex) { + throw new IllegalStateException(ex); + } + try { + CHECKSTYLE_MODULES = CheckUtil.getCheckstyleModules(); + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + /** + * Returns test logger. + * @return logger test logger + */ + public final BriefUtLogger getBriefUtLogger() { + return new BriefUtLogger(stream); + } + + /** + * Creates {@link DefaultConfiguration} instance for the given module class. + * @param clazz module class. + * @return {@link DefaultConfiguration} instance. + */ + private static DefaultConfiguration createModuleConfig(Class clazz) { + return new DefaultConfiguration(clazz.getName()); + } + + /** + * Creates {@link Checker} instance based on the given {@link Configuration} instance. + * @param moduleConfig {@link Configuration} instance. + * @return {@link Checker} instance based on the given {@link Configuration} instance. + * @throws Exception if an exception occurs during checker configuration. + */ + public final Checker createChecker(Configuration moduleConfig) + throws Exception { + final String name = moduleConfig.getName(); + ModuleCreationOption moduleCreationOption = ModuleCreationOption.IN_CHECKER; + + for (Class moduleClass : CHECKSTYLE_MODULES) { + if (moduleClass.getSimpleName().equals(name) + || moduleClass.getSimpleName().equals(name + "Check")) { + if (ModuleReflectionUtils.isCheckstyleTreeWalkerCheck(moduleClass) + || ModuleReflectionUtils.isTreeWalkerFilterModule(moduleClass)) { + moduleCreationOption = ModuleCreationOption.IN_TREEWALKER; + } + break; + } + } + + return createChecker(moduleConfig, moduleCreationOption); + } + + /** + * Creates {@link Checker} instance based on specified {@link Configuration}. + * @param moduleConfig {@link Configuration} instance. + * @param moduleCreationOption {@code IN_TREEWALKER} if the {@code moduleConfig} should be added + * under {@link TreeWalker}. + * @return {@link Checker} instance. + * @throws Exception if an exception occurs during checker configuration. + */ + protected final Checker createChecker(Configuration moduleConfig, + ModuleCreationOption moduleCreationOption) + throws Exception { + final DefaultConfiguration dc; + + if (moduleCreationOption == ModuleCreationOption.IN_TREEWALKER) { + dc = createTreeWalkerConfig(moduleConfig); + } + else { + dc = createRootConfig(moduleConfig); + } + + final Checker checker = new Checker(); + // make sure the tests always run with English error messages + // so the tests don't fail in supported locales like German + final Locale locale = Locale.ENGLISH; + checker.setLocaleCountry(locale.getCountry()); + checker.setLocaleLanguage(locale.getLanguage()); + checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); + checker.configure(dc); + checker.addListener(getBriefUtLogger()); + return checker; + } + + /** + * Creates {@link DefaultConfiguration} or the {@link Checker}. + * based on the given {@link Configuration}. + * @param config {@link Configuration} instance. + * @return {@link DefaultConfiguration} for the {@link Checker}. + */ + protected static DefaultConfiguration createTreeWalkerConfig(Configuration config) { + final DefaultConfiguration dc = + new DefaultConfiguration("configuration"); + final DefaultConfiguration twConf = createModuleConfig(TreeWalker.class); + // make sure that the tests always run with this charset + dc.addAttribute("charset", "iso-8859-1"); + dc.addChild(twConf); + twConf.addChild(config); + return dc; + } + + /** + * Creates {@link DefaultConfiguration} for the given {@link Configuration} instance. + * @param config {@link Configuration} instance. + * @return {@link DefaultConfiguration} for the given {@link Configuration} instance. + */ + protected static DefaultConfiguration createRootConfig(Configuration config) { + final DefaultConfiguration dc = new DefaultConfiguration("root"); + dc.addChild(config); + return dc; + } + + /** + * Performs verification of the file with given file name. Uses specified configuration. + * Expected messages are represented by the array of strings, warning line numbers are + * represented by the array of integers. + * This implementation uses overloaded + * {@link AbstractModuleTestSupport#verify(Checker, File[], String, String[], Integer...)} + * method inside. + * @param config configuration. + * @param fileName file name to verify. + * @param expected an array of expected messages. + * @param warnsExpected an array of expected warning numbers. + * @throws Exception if exception occurs during verification process. + */ + protected final void verify(Configuration config, String fileName, String[] expected, + Integer... warnsExpected) throws Exception { + verify(createChecker(config), + new File[] {new File(fileName)}, + fileName, expected, warnsExpected); + } + + /** + * Performs verification of files. Uses provided {@link Checker} instance. + * @param checker {@link Checker} instance. + * @param processedFiles files to process. + * @param messageFileName message file name. + * @param expected an array of expected messages. + * @param warnsExpected an array of expected warning line numbers. + * @throws Exception if exception occurs during verification process. + */ + protected final void verify(Checker checker, + File[] processedFiles, + String messageFileName, + String[] expected, + Integer... warnsExpected) + throws Exception { + stream.flush(); + final List theFiles = new ArrayList<>(); + Collections.addAll(theFiles, processedFiles); + final List theWarnings = new ArrayList<>(); + Collections.addAll(theWarnings, warnsExpected); + final int errs = checker.process(theFiles); + + // process each of the lines + final ByteArrayInputStream inputStream = + new ByteArrayInputStream(stream.toByteArray()); + try (LineNumberReader lnr = new LineNumberReader( + new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { + int previousLineNumber = 0; + for (int i = 0; i < expected.length; i++) { + final String expectedResult = messageFileName + ":" + expected[i]; + final String actual = lnr.readLine(); + assertEquals("error message " + i, expectedResult, actual); + + String parseInt = removeDeviceFromPathOnWindows(actual); + parseInt = parseInt.substring(parseInt.indexOf(':') + 1); + parseInt = parseInt.substring(0, parseInt.indexOf(':')); + final int lineNumber = Integer.parseInt(parseInt); + assertTrue("input file is expected to have a warning comment on line number " + + lineNumber, previousLineNumber == lineNumber + || theWarnings.remove((Integer) lineNumber)); + previousLineNumber = lineNumber; + } + + assertEquals("unexpected output: " + lnr.readLine(), + expected.length, errs); + assertEquals("unexpected warnings " + theWarnings, 0, theWarnings.size()); + } + + checker.destroy(); + } + + /** + * Gets the check message 'as is' from appropriate 'messages.properties' + * file. + * + * @param aClass The package the message is located in. + * @param messageKey the key of message in 'messages.properties' file. + * @param arguments the arguments of message in 'messages.properties' file. + * @return The message of the check with the arguments applied. + * @throws IOException if there is a problem loading the property file. + */ + protected static String getCheckMessage(Class aClass, + String messageKey, Object... arguments) throws IOException { + final Properties pr = new Properties(); + pr.load(aClass.getResourceAsStream("messages.properties")); + final MessageFormat formatter = new MessageFormat(pr.getProperty(messageKey), + Locale.ROOT); + return formatter.format(arguments); + } + + /** + * Gets the check message 'as is' from appropriate 'messages.properties' file. + * @param messages The map of messages to scan. + * @param messageKey the key of message in 'messages.properties' file. + * @param arguments the arguments of message in 'messages.properties' file. + * @return The message of the check with the arguments applied. + */ + protected static String getCheckMessage(Map messages, String messageKey, + Object... arguments) { + String checkMessage = null; + for (Map.Entry entry : messages.entrySet()) { + if (messageKey.equals(entry.getKey())) { + final MessageFormat formatter = new MessageFormat(entry.getValue(), Locale.ROOT); + checkMessage = formatter.format(arguments); + break; + } + } + return checkMessage; + } + + /** + * Returns {@link Configuration} instance for the given module name. + * This implementation uses {@link AbstractModuleTestSupport#getConfiguration()} method inside. + * @param moduleName module name. + * @return {@link Configuration} instance for the given module name. + */ + protected static Configuration getModuleConfig(String moduleName) { + return getModuleConfig(moduleName, null); + } + + /** + * Returns {@link Configuration} instance for the given module name. + * This implementation uses {@link AbstractModuleTestSupport#getConfiguration()} method inside. + * @param moduleName module name. + * @param moduleId module id. + * @return {@link Configuration} instance for the given module name. + * @throws CheckstyleException if exception occurs during configuration loading. + */ + protected static Configuration getModuleConfig(String moduleName, String moduleId) { + final Configuration result; + final List configs = getModuleConfigs(moduleName); + if (configs.size() == 1) { + result = configs.get(0); + } + else if (moduleId == null) { + throw new IllegalStateException("multiple instances of the same Module are detected"); + } + else { + result = configs.stream().filter(conf -> { + try { + return conf.getAttribute("id").equals(moduleId); + } + catch (CheckstyleException ex) { + throw new IllegalStateException("problem to get ID attribute from " + conf, ex); + } + }) + .findFirst().orElseGet(null); + } + + return result; + } + + /** + * Returns a list of all {@link Configuration} instances for the given module name. + * This implementation uses {@link AbstractModuleTestSupport#getConfiguration()} method inside. + * @param moduleName module name. + * @return {@link Configuration} instance for the given module name. + */ + protected static List getModuleConfigs(String moduleName) { + final List result = new ArrayList<>(); + for (Configuration currentConfig : CONFIGURATION.getChildren()) { + if ("TreeWalker".equals(currentConfig.getName())) { + for (Configuration moduleConfig : currentConfig.getChildren()) { + if (moduleName.equals(moduleConfig.getName())) { + result.add(moduleConfig); + } + } + } + else if (moduleName.equals(currentConfig.getName())) { + result.add(currentConfig); + } + } + return result; + } + + private static String removeDeviceFromPathOnWindows(String path) { + String fixedPath = path; + final String os = System.getProperty("os.name", "Unix"); + if (os.startsWith("Windows")) { + fixedPath = path.substring(path.indexOf(':') + 1); + } + return fixedPath; + } + + /** + * Returns an array of integers which represents the warning line numbers in the file + * with the given file name. + * @param fileName file name. + * @return an array of integers which represents the warning line numbers. + * @throws IOException if I/O exception occurs while reading the file. + */ + protected Integer[] getLinesWithWarn(String fileName) throws IOException { + final List result = new ArrayList<>(); + try (BufferedReader br = new BufferedReader(new InputStreamReader( + new FileInputStream(fileName), StandardCharsets.UTF_8))) { + int lineNumber = 1; + while (true) { + final String line = br.readLine(); + if (line == null) { + break; + } + if (WARN_PATTERN.matcher(line).find()) { + result.add(lineNumber); + } + lineNumber++; + } + } + return result.toArray(new Integer[result.size()]); + } + +} diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/AbstractPathTestSupport.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/AbstractPathTestSupport.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/AbstractPathTestSupport.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/AbstractPathTestSupport.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,47 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.google.checkstyle.test.base; + +import java.io.File; +import java.io.IOException; + +public abstract class AbstractPathTestSupport { + + /** + * Returns the exact location for the package where the file is present. + * @return path for the package name for the file. + */ + protected abstract String getPackageLocation(); + + /** + * Returns canonical path for the file with the given file name. + * The path is formed base on the root location. + * This implementation uses 'src/test/resources/' + * as a root location. + * @param filename file name. + * @return canonical path for the file name. + * @throws IOException if I/O exception occurs while forming the path. + */ + protected final String getPath(String filename) throws IOException { + return new File("src/it/resources/" + getPackageLocation() + "/" + filename) + .getCanonicalPath(); + } + +} diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/BaseCheckTestSupport.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/BaseCheckTestSupport.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/BaseCheckTestSupport.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/BaseCheckTestSupport.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,241 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.google.checkstyle.test.base; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.LineNumberReader; -import java.nio.charset.StandardCharsets; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Properties; -import java.util.regex.Pattern; - -import com.google.common.collect.Lists; -import com.puppycrawl.tools.checkstyle.BriefUtLogger; -import com.puppycrawl.tools.checkstyle.Checker; -import com.puppycrawl.tools.checkstyle.ConfigurationLoader; -import com.puppycrawl.tools.checkstyle.DefaultConfiguration; -import com.puppycrawl.tools.checkstyle.PropertiesExpander; -import com.puppycrawl.tools.checkstyle.TreeWalker; -import com.puppycrawl.tools.checkstyle.api.AbstractViolationReporter; -import com.puppycrawl.tools.checkstyle.api.CheckstyleException; -import com.puppycrawl.tools.checkstyle.api.Configuration; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; - -public class BaseCheckTestSupport { - private static final Pattern WARN_PATTERN = CommonUtils - .createPattern(".*[ ]*//[ ]*warn[ ]*|/[*]warn[*]/"); - - private static final String XML_NAME = "/google_checks.xml"; - - private static Configuration configuration; - - protected final ByteArrayOutputStream stream = new ByteArrayOutputStream(); - - protected static Configuration getConfiguration() throws CheckstyleException { - if (configuration == null) { - configuration = ConfigurationLoader.loadConfiguration(XML_NAME, new PropertiesExpander( - System.getProperties())); - } - - return configuration; - } - - protected static DefaultConfiguration createCheckConfig(Class clazz) { - return new DefaultConfiguration(clazz.getName()); - } - - protected Checker createChecker(Configuration checkConfig) - throws Exception { - final DefaultConfiguration dc = createCheckerConfig(checkConfig); - final Checker checker = new Checker(); - // make sure the tests always run with English error messages - // so the tests don't fail in supported locales like German - final Locale locale = Locale.ENGLISH; - checker.setLocaleCountry(locale.getCountry()); - checker.setLocaleLanguage(locale.getLanguage()); - checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); - checker.configure(dc); - checker.addListener(new BriefUtLogger(stream)); - return checker; - } - - protected DefaultConfiguration createCheckerConfig(Configuration config) { - final DefaultConfiguration dc = - new DefaultConfiguration("configuration"); - final DefaultConfiguration twConf = createCheckConfig(TreeWalker.class); - // make sure that the tests always run with this charset - dc.addAttribute("charset", "iso-8859-1"); - dc.addChild(twConf); - twConf.addChild(config); - return dc; - } - - protected String getPath(String fileName) throws IOException { - return new File("src/it/resources/com/google/checkstyle/test/" + fileName) - .getCanonicalPath(); - } - - protected void verify(Configuration config, String fileName, String[] expected, - Integer... warnsExpected) throws Exception { - verify(createChecker(config), - new File[] {new File(fileName)}, - fileName, expected, warnsExpected); - } - - protected void verify(Checker checker, - File[] processedFiles, - String messageFileName, - String[] expected, - Integer... warnsExpected) - throws Exception { - stream.flush(); - final List theFiles = Lists.newArrayList(); - Collections.addAll(theFiles, processedFiles); - final List theWarnings = Lists.newArrayList(); - Collections.addAll(theWarnings, warnsExpected); - final int errs = checker.process(theFiles); - - // process each of the lines - final ByteArrayInputStream inputStream = - new ByteArrayInputStream(stream.toByteArray()); - try (final LineNumberReader lnr = new LineNumberReader( - new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { - - int previousLineNumber = 0; - for (int i = 0; i < expected.length; i++) { - final String expectedResult = messageFileName + ":" + expected[i]; - final String actual = lnr.readLine(); - assertEquals("error message " + i, expectedResult, actual); - - String parseInt = removeDeviceFromPathOnWindows(actual); - parseInt = parseInt.substring(parseInt.indexOf(':') + 1); - parseInt = parseInt.substring(0, parseInt.indexOf(':')); - final int lineNumber = Integer.parseInt(parseInt); - assertTrue("input file is expected to have a warning comment on line number " - + lineNumber, theWarnings.remove((Integer) lineNumber) - || previousLineNumber == lineNumber); - previousLineNumber = lineNumber; - } - - assertEquals("unexpected output: " + lnr.readLine(), - expected.length, errs); - assertEquals("unexpected warnings " + theWarnings, 0, theWarnings.size()); - } - - checker.destroy(); - } - - /** - * Gets the check message 'as is' from appropriate 'messages.properties' - * file. - * - * @param messageKey the key of message in 'messages.properties' file. - * @param arguments the arguments of message in 'messages.properties' file. - */ - protected String getCheckMessage(Class aClass, - String messageKey, Object... arguments) { - final Properties pr = new Properties(); - try { - pr.load(aClass.getResourceAsStream("messages.properties")); - } - catch (IOException ex) { - return null; - } - final MessageFormat formatter = new MessageFormat(pr.getProperty(messageKey), - Locale.ROOT); - return formatter.format(arguments); - } - - /** - * Gets the check message 'as is' from appropriate 'messages.properties' file. - * @param messageKey the key of message in 'messages.properties' file. - * @param arguments the arguments of message in 'messages.properties' file. - */ - protected String getCheckMessage(Map messages, String messageKey, - Object... arguments) { - for (Map.Entry entry : messages.entrySet()) { - if (messageKey.equals(entry.getKey())) { - final MessageFormat formatter = new MessageFormat(entry.getValue(), Locale.ROOT); - return formatter.format(arguments); - } - } - return null; - } - - protected static Configuration getCheckConfig(String checkName) throws CheckstyleException { - Configuration result = null; - for (Configuration currentConfig : getConfiguration().getChildren()) { - if ("TreeWalker".equals(currentConfig.getName())) { - for (Configuration checkConfig : currentConfig.getChildren()) { - if (checkName.equals(checkConfig.getName())) { - result = checkConfig; - break; - } - } - } - else if (checkName.equals(currentConfig.getName())) { - result = currentConfig; - break; - } - } - return result; - } - - private static String removeDeviceFromPathOnWindows(String path) { - final String os = System.getProperty("os.name", "Unix"); - if (os.startsWith("Windows")) { - return path.substring(path.indexOf(':') + 1); - } - return path; - } - - protected Integer[] getLinesWithWarn(String fileName) throws IOException { - final List result = new ArrayList<>(); - try (BufferedReader br = new BufferedReader(new InputStreamReader( - new FileInputStream(fileName), StandardCharsets.UTF_8))) { - int lineNumber = 1; - while (true) { - final String line = br.readLine(); - if (line == null) { - break; - } - if (WARN_PATTERN.matcher(line).find()) { - result.add(lineNumber); - } - lineNumber++; - } - } - return result.toArray(new Integer[result.size()]); - } -} diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/BaseIndentationCheckSupport.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/BaseIndentationCheckSupport.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/BaseIndentationCheckSupport.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/BaseIndentationCheckSupport.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,216 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.google.checkstyle.test.base; - -import java.io.BufferedReader; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; - -public class BaseIndentationCheckSupport extends BaseCheckTestSupport { - private static final int TAB_WIDTH = 4; - - private static final Pattern NONEMPTY_LINE_REGEX = - Pattern.compile(".*?\\S+.*?"); - - private static final Pattern LINE_WITH_COMMENT_REGEX = - Pattern.compile(".*?\\S+.*?(//indent:(\\d+) exp:((>=\\d+)|(\\d+(,\\d+)*?))( warn)?)"); - - private static final Pattern GET_INDENT_FROM_COMMENT_REGEX = - Pattern.compile("//indent:(\\d+).*?"); - - private static final Pattern MULTILEVEL_COMMENT_REGEX = - Pattern.compile("//indent:\\d+ exp:(\\d+(,\\d+)+?)( warn)?"); - - private static final Pattern SINGLE_LEVEL_COMMENT_REGEX = - Pattern.compile("//indent:\\d+ exp:(\\d+)( warn)?"); - - private static final Pattern NON_STRICT_LEVEL_COMMENT_REGEX = - Pattern.compile("//indent:\\d+ exp:>=(\\d+)( warn)?"); - - @Override - protected Integer[] getLinesWithWarn(String fileName) throws IOException { - return getLinesWithWarnAndCheckComments(fileName, TAB_WIDTH); - } - - private enum CommentType { - MULTILEVEL, SINGLE_LEVEL, NON_STRICT_LEVEL, UNKNOWN - } - - private static Integer[] getLinesWithWarnAndCheckComments(String aFileName, - final int tabWidth) - throws IOException { - final List result = new ArrayList<>(); - try (BufferedReader br = new BufferedReader(new InputStreamReader( - new FileInputStream(aFileName), StandardCharsets.UTF_8))) { - int lineNumber = 1; - for (String line = br.readLine(); line != null; line = br.readLine()) { - final Matcher match = LINE_WITH_COMMENT_REGEX.matcher(line); - if (match.matches()) { - final String comment = match.group(1); - final int indentInComment = getIndentFromComment(comment); - final int actualIndent = getLineStart(line, tabWidth); - - if (actualIndent != indentInComment) { - throw new IllegalStateException(String.format(Locale.ROOT, - "File \"%1$s\" has incorrect indentation in comment." - + "Line %2$d: comment:%3$d, actual:%4$d.", - aFileName, - lineNumber, - indentInComment, - actualIndent)); - } - - if (isWarnComment(comment)) { - result.add(lineNumber); - } - - if (!isCommentConsistent(comment)) { - throw new IllegalStateException(String.format(Locale.ROOT, - "File \"%1$s\" has inconsistent comment on line %2$d", - aFileName, - lineNumber)); - } - } - else if (NONEMPTY_LINE_REGEX.matcher(line).matches()) { - throw new IllegalStateException(String.format(Locale.ROOT, - "File \"%1$s\" has no indentation comment or its format " - + "malformed. Error on line: %2$d(%3$s)", - aFileName, - lineNumber, - line)); - } - lineNumber++; - } - } - return result.toArray(new Integer[result.size()]); - } - - private static int getIndentFromComment(String comment) { - final Matcher match = GET_INDENT_FROM_COMMENT_REGEX.matcher(comment); - match.matches(); - return Integer.parseInt(match.group(1)); - } - - private static boolean isWarnComment(String comment) { - return comment.endsWith(" warn"); - } - - private static boolean isCommentConsistent(String comment) { - final int indentInComment = getIndentFromComment(comment); - final boolean isWarnComment = isWarnComment(comment); - - final boolean result; - final CommentType type = getCommentType(comment); - switch (type) { - case MULTILEVEL: - result = isMultiLevelCommentConsistent(comment, indentInComment, isWarnComment); - break; - - case SINGLE_LEVEL: - result = isSingleLevelCommentConsistent(comment, indentInComment, isWarnComment); - break; - - case NON_STRICT_LEVEL: - result = isNonStrictCommentConsistent(comment, indentInComment, isWarnComment); - break; - - case UNKNOWN: - throw new IllegalArgumentException("Cannot determine comment consistent"); - - default: - throw new IllegalStateException("Cannot determine comment is consistent"); - - } - return result; - } - - private static boolean isNonStrictCommentConsistent(String comment, - int indentInComment, boolean isWarnComment) { - final Matcher nonStrictLevelMatch = NON_STRICT_LEVEL_COMMENT_REGEX.matcher(comment); - nonStrictLevelMatch.matches(); - final int expectedMinimalIndent = Integer.parseInt(nonStrictLevelMatch.group(1)); - - return indentInComment >= expectedMinimalIndent && !isWarnComment - || indentInComment < expectedMinimalIndent && isWarnComment; - } - - private static boolean isSingleLevelCommentConsistent(String comment, - int indentInComment, boolean isWarnComment) { - final Matcher singleLevelMatch = SINGLE_LEVEL_COMMENT_REGEX.matcher(comment); - singleLevelMatch.matches(); - final int expectedLevel = Integer.parseInt(singleLevelMatch.group(1)); - - return expectedLevel == indentInComment && !isWarnComment - || expectedLevel != indentInComment && isWarnComment; - } - - private static boolean isMultiLevelCommentConsistent(String comment, - int indentInComment, boolean isWarnComment) { - final Matcher multilevelMatch = MULTILEVEL_COMMENT_REGEX.matcher(comment); - multilevelMatch.matches(); - final String[] levels = multilevelMatch.group(1).split(","); - final String indentInCommentStr = String.valueOf(indentInComment); - final boolean containsActualLevel = - Arrays.asList(levels).contains(indentInCommentStr); - - return containsActualLevel && !isWarnComment - || !containsActualLevel && isWarnComment; - } - - private static CommentType getCommentType(String comment) { - CommentType result = CommentType.UNKNOWN; - final Matcher multilevelMatch = MULTILEVEL_COMMENT_REGEX.matcher(comment); - if (multilevelMatch.matches()) { - result = CommentType.MULTILEVEL; - } - else { - final Matcher singleLevelMatch = SINGLE_LEVEL_COMMENT_REGEX.matcher(comment); - if (singleLevelMatch.matches()) { - result = CommentType.SINGLE_LEVEL; - } - else { - final Matcher nonStrictLevelMatch = NON_STRICT_LEVEL_COMMENT_REGEX.matcher(comment); - if (nonStrictLevelMatch.matches()) { - result = CommentType.NON_STRICT_LEVEL; - } - } - } - return result; - } - - private static int getLineStart(String line, final int tabWidth) { - for (int index = 0; index < line.length(); ++index) { - if (!Character.isWhitespace(line.charAt(index))) { - return CommonUtils.lengthExpandedTabs(line, index, tabWidth); - } - } - return 0; - } -} diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/ConfigValidationTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/ConfigValidationTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/base/ConfigValidationTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/base/ConfigValidationTest.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.google.checkstyle.test.base; - -import static org.apache.commons.lang3.ArrayUtils.EMPTY_INTEGER_OBJECT_ARRAY; -import static org.apache.commons.lang3.ArrayUtils.EMPTY_STRING_ARRAY; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; - -import org.junit.Test; - -import com.puppycrawl.tools.checkstyle.BriefUtLogger; -import com.puppycrawl.tools.checkstyle.Checker; -import com.puppycrawl.tools.checkstyle.api.Configuration; - -public class ConfigValidationTest extends BaseCheckTestSupport { - @Test - public void testGoogleChecks() throws Exception { - final Configuration checkerConfig = getConfiguration(); - final Checker checker = new Checker(); - final Locale locale = Locale.ROOT; - checker.setLocaleCountry(locale.getCountry()); - checker.setLocaleLanguage(locale.getLanguage()); - checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); - checker.configure(checkerConfig); - checker.addListener(new BriefUtLogger(stream)); - - final List files = new ArrayList<>(); - listFiles(files, new File("src/it/"), "java"); - - //runs over all input files; - //as severity level is "warning", no errors expected - verify(checker, files.toArray(new File[files.size()]), "", - EMPTY_STRING_ARRAY, EMPTY_INTEGER_OBJECT_ARRAY); - } - - private static void listFiles(final List files, final File folder, - final String extension) { - if (folder.canRead()) { - if (folder.isDirectory()) { - for (final File file : folder.listFiles()) { - listFiles(files, file, extension); - } - } - else if (folder.toString().endsWith("." + extension)) { - files.add(folder); - } - } - } -} diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule21filename/OuterTypeFilenameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule21filename/OuterTypeFilenameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule21filename/OuterTypeFilenameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule21filename/OuterTypeFilenameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,30 +21,25 @@ import static com.puppycrawl.tools.checkstyle.checks.OuterTypeFilenameCheck.MSG_KEY; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.OuterTypeFilenameCheck; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class OuterTypeFilenameTest extends BaseCheckTestSupport { +public class OuterTypeFilenameTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter2filebasic" + File.separator + "rule21filename" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter2filebasic/rule21filename"; } @Test - public void outerTypeFilenameTest1() throws Exception { - - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; + public void testOuterTypeFilename1() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final Configuration checkConfig = getCheckConfig("OuterTypeFilename"); + final Configuration checkConfig = getModuleConfig("OuterTypeFilename"); final String filePath = getPath("InputOuterTypeFilename1.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -52,11 +47,10 @@ } @Test - public void outerTypeFilenameTest2() throws Exception { - - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; + public void testOuterTypeFilename2() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final Configuration checkConfig = getCheckConfig("OuterTypeFilename"); + final Configuration checkConfig = getModuleConfig("OuterTypeFilename"); final String filePath = getPath("InputOuterTypeFilename2.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -64,16 +58,16 @@ } @Test - public void outerTypeFilenameTest3() throws Exception { - + public void testOuterTypeFilename3() throws Exception { final String[] expected = { "3: " + getCheckMessage(OuterTypeFilenameCheck.class, MSG_KEY), }; - final Configuration checkConfig = getCheckConfig("OuterTypeFilename"); + final Configuration checkConfig = getModuleConfig("OuterTypeFilename"); final String filePath = getPath("InputOuterTypeFilename3.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule231filetab/FileTabCharacterTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule231filetab/FileTabCharacterTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule231filetab/FileTabCharacterTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule231filetab/FileTabCharacterTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,36 +19,21 @@ package com.google.checkstyle.test.chapter2filebasic.rule231filetab; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; -import com.puppycrawl.tools.checkstyle.DefaultConfiguration; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.whitespace.FileTabCharacterCheck; -public class FileTabCharacterTest extends BaseCheckTestSupport { - - @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter2filebasic" + File.separator + "rule231filetab" - + File.separator + fileName); - } +public class FileTabCharacterTest extends AbstractModuleTestSupport { @Override - protected DefaultConfiguration createCheckerConfig( - Configuration aConfig) { - final DefaultConfiguration dc = new DefaultConfiguration("root"); - dc.addChild(aConfig); - return dc; + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter2filebasic/rule231filetab"; } @Test - public void fileTabTest() throws Exception { - - final DefaultConfiguration checkConfig = createConfig(true); + public void testFileTab() throws Exception { final String[] expected = { "8:25: " + getCheckMessage(FileTabCharacterCheck.class, "containsTab"), "51:5: " + getCheckMessage(FileTabCharacterCheck.class, "containsTab"), @@ -61,18 +46,11 @@ "134:3: " + getCheckMessage(FileTabCharacterCheck.class, "containsTab"), }; + final Configuration checkConfig = getModuleConfig("FileTabCharacter"); final String filePath = getPath("InputFileTabCharacter.java"); + final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } - /** - * Creates a configuration that is functionally close to that in the docs. - */ - private static DefaultConfiguration createConfig(boolean verbose) { - final DefaultConfiguration checkConfig = - createCheckConfig(FileTabCharacterCheck.class); - checkConfig.addAttribute("eachLine", Boolean.toString(verbose)); - return checkConfig; - } } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule232specialescape/IllegalTokenTextTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule232specialescape/IllegalTokenTextTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule232specialescape/IllegalTokenTextTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule232specialescape/IllegalTokenTextTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,98 +19,91 @@ package com.google.checkstyle.test.chapter2filebasic.rule232specialescape; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class IllegalTokenTextTest extends BaseCheckTestSupport { +public class IllegalTokenTextTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter2filebasic" + File.separator + "rule232specialescape" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter2filebasic/rule232specialescape"; } @Test - public void illegalTokensTest() throws Exception { + public void testIllegalTokens() throws Exception { + final String message = "Consider using special escape sequence instead of octal value or " + + "Unicode escaped value."; final String[] expected = { - "17:27: Avoid using corresponding octal or Unicode escape.", - "18:27: Avoid using corresponding octal or Unicode escape.", - "19:27: Avoid using corresponding octal or Unicode escape.", - "22:25: Avoid using corresponding octal or Unicode escape.", - "23:25: Avoid using corresponding octal or Unicode escape.", - "25:16: Avoid using corresponding octal or Unicode escape.", - "42:21: Avoid using corresponding octal or Unicode escape.", - "43:21: Avoid using corresponding octal or Unicode escape.", - "44:21: Avoid using corresponding octal or Unicode escape.", - "45:21: Avoid using corresponding octal or Unicode escape.", - "46:21: Avoid using corresponding octal or Unicode escape.", - "47:21: Avoid using corresponding octal or Unicode escape.", - "48:21: Avoid using corresponding octal or Unicode escape.", - "49:21: Avoid using corresponding octal or Unicode escape.", - "54:21: Avoid using corresponding octal or Unicode escape.", - "55:21: Avoid using corresponding octal or Unicode escape.", - "56:21: Avoid using corresponding octal or Unicode escape.", - "57:21: Avoid using corresponding octal or Unicode escape.", - "58:21: Avoid using corresponding octal or Unicode escape.", - "59:21: Avoid using corresponding octal or Unicode escape.", - "60:21: Avoid using corresponding octal or Unicode escape.", - "61:21: Avoid using corresponding octal or Unicode escape.", - "68:31: Avoid using corresponding octal or Unicode escape.", - "69:31: Avoid using corresponding octal or Unicode escape.", - "70:31: Avoid using corresponding octal or Unicode escape.", - "73:29: Avoid using corresponding octal or Unicode escape.", - "74:29: Avoid using corresponding octal or Unicode escape.", - "76:20: Avoid using corresponding octal or Unicode escape.", - "93:25: Avoid using corresponding octal or Unicode escape.", - "94:25: Avoid using corresponding octal or Unicode escape.", - "95:25: Avoid using corresponding octal or Unicode escape.", - "96:25: Avoid using corresponding octal or Unicode escape.", - "97:25: Avoid using corresponding octal or Unicode escape.", - "98:25: Avoid using corresponding octal or Unicode escape.", - "99:25: Avoid using corresponding octal or Unicode escape.", - "100:25: Avoid using corresponding octal or Unicode escape.", - "105:25: Avoid using corresponding octal or Unicode escape.", - "106:25: Avoid using corresponding octal or Unicode escape.", - "107:25: Avoid using corresponding octal or Unicode escape.", - "108:25: Avoid using corresponding octal or Unicode escape.", - "109:25: Avoid using corresponding octal or Unicode escape.", - "110:25: Avoid using corresponding octal or Unicode escape.", - "111:25: Avoid using corresponding octal or Unicode escape.", - "112:25: Avoid using corresponding octal or Unicode escape.", - "118:35: Avoid using corresponding octal or Unicode escape.", - "119:35: Avoid using corresponding octal or Unicode escape.", - "120:35: Avoid using corresponding octal or Unicode escape.", - "123:33: Avoid using corresponding octal or Unicode escape.", - "124:33: Avoid using corresponding octal or Unicode escape.", - "126:24: Avoid using corresponding octal or Unicode escape.", - "143:29: Avoid using corresponding octal or Unicode escape.", - "144:29: Avoid using corresponding octal or Unicode escape.", - "145:29: Avoid using corresponding octal or Unicode escape.", - "146:29: Avoid using corresponding octal or Unicode escape.", - "147:29: Avoid using corresponding octal or Unicode escape.", - "148:29: Avoid using corresponding octal or Unicode escape.", - "149:29: Avoid using corresponding octal or Unicode escape.", - "150:29: Avoid using corresponding octal or Unicode escape.", - "155:29: Avoid using corresponding octal or Unicode escape.", - "156:29: Avoid using corresponding octal or Unicode escape.", - "157:29: Avoid using corresponding octal or Unicode escape.", - "158:29: Avoid using corresponding octal or Unicode escape.", - "159:29: Avoid using corresponding octal or Unicode escape.", - "160:29: Avoid using corresponding octal or Unicode escape.", - "161:29: Avoid using corresponding octal or Unicode escape.", - "162:29: Avoid using corresponding octal or Unicode escape.", + "18:27: " + message, + "19:27: " + message, + "22:25: " + message, + "23:25: " + message, + "25:16: " + message, + "43:21: " + message, + "44:21: " + message, + "45:21: " + message, + "46:21: " + message, + "47:21: " + message, + "48:21: " + message, + "49:21: " + message, + "54:21: " + message, + "55:21: " + message, + "56:21: " + message, + "57:21: " + message, + "58:21: " + message, + "59:21: " + message, + "60:21: " + message, + "61:21: " + message, + "69:31: " + message, + "70:31: " + message, + "73:29: " + message, + "74:29: " + message, + "76:20: " + message, + "94:25: " + message, + "95:25: " + message, + "96:25: " + message, + "97:25: " + message, + "98:25: " + message, + "99:25: " + message, + "100:25: " + message, + "105:25: " + message, + "106:25: " + message, + "107:25: " + message, + "108:25: " + message, + "109:25: " + message, + "110:25: " + message, + "111:25: " + message, + "112:25: " + message, + "119:35: " + message, + "120:35: " + message, + "123:33: " + message, + "124:33: " + message, + "126:24: " + message, + "144:29: " + message, + "145:29: " + message, + "146:29: " + message, + "147:29: " + message, + "148:29: " + message, + "149:29: " + message, + "150:29: " + message, + "155:29: " + message, + "156:29: " + message, + "157:29: " + message, + "158:29: " + message, + "159:29: " + message, + "160:29: " + message, + "161:29: " + message, + "162:29: " + message, }; - final Configuration checkConfig = getCheckConfig("IllegalTokenText"); + final Configuration checkConfig = getModuleConfig("IllegalTokenText"); final String filePath = getPath("InputIllegalTokenText.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule233nonascii/AvoidEscapedUnicodeCharactersTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule233nonascii/AvoidEscapedUnicodeCharactersTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule233nonascii/AvoidEscapedUnicodeCharactersTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter2filebasic/rule233nonascii/AvoidEscapedUnicodeCharactersTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,26 +21,21 @@ import static com.puppycrawl.tools.checkstyle.checks.AvoidEscapedUnicodeCharactersCheck.MSG_KEY; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.AvoidEscapedUnicodeCharactersCheck; -public class AvoidEscapedUnicodeCharactersTest extends BaseCheckTestSupport { +public class AvoidEscapedUnicodeCharactersTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter2filebasic" + File.separator + "rule233nonascii" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter2filebasic/rule233nonascii"; } @Test - public void unicodeEscapesTest() throws Exception { - + public void testUnicodeEscapes() throws Exception { final String[] expected = { "5: " + getCheckMessage(AvoidEscapedUnicodeCharactersCheck.class, MSG_KEY), "15: " + getCheckMessage(AvoidEscapedUnicodeCharactersCheck.class, MSG_KEY), @@ -50,10 +45,11 @@ "36: " + getCheckMessage(AvoidEscapedUnicodeCharactersCheck.class, MSG_KEY), }; - final Configuration checkConfig = getCheckConfig("AvoidEscapedUnicodeCharacters"); + final Configuration checkConfig = getModuleConfig("AvoidEscapedUnicodeCharacters"); final String filePath = getPath("InputAvoidEscapedUnicodeCharacters.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule32packagestate/LineLengthTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule32packagestate/LineLengthTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule32packagestate/LineLengthTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule32packagestate/LineLengthTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter3filestructure.rule32packagestate; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck; -public class LineLengthTest extends BaseCheckTestSupport { +public class LineLengthTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter3filestructure" + File.separator + "rule32packagestate" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter3filestructure/rule32packagestate"; } @Test - public void lineLengthTest() throws Exception { - + public void testLineLength() throws Exception { final String[] expected = { "5: " + getCheckMessage(LineLengthCheck.class, "maxLineLen", 100, 112), "29: " + getCheckMessage(LineLengthCheck.class, "maxLineLen", 100, 183), @@ -50,10 +45,11 @@ "57: " + getCheckMessage(LineLengthCheck.class, "maxLineLen", 100, 116), }; - final Configuration checkConfig = getCheckConfig("LineLength"); + final Configuration checkConfig = getModuleConfig("LineLength"); final String filePath = getPath("InputLineLength.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule331nowildcard/AvoidStarImportTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule331nowildcard/AvoidStarImportTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule331nowildcard/AvoidStarImportTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule331nowildcard/AvoidStarImportTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,25 +19,20 @@ package com.google.checkstyle.test.chapter3filestructure.rule331nowildcard; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class AvoidStarImportTest extends BaseCheckTestSupport { +public class AvoidStarImportTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter3filestructure" + File.separator + "rule331nowildcard" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter3filestructure/rule331nowildcard"; } @Test - public void starImportTest() throws Exception { - + public void testStarImport() throws Exception { final String[] expected = { "3: Using the '.*' form of import should be avoided - java.io.*.", "4: Using the '.*' form of import should be avoided - java.lang.*.", @@ -45,10 +40,11 @@ "19: Using the '.*' form of import should be avoided - javax.swing.WindowConstants.*.", }; - final Configuration checkConfig = getCheckConfig("AvoidStarImport"); + final Configuration checkConfig = getModuleConfig("AvoidStarImport"); final String filePath = getPath("InputAvoidStarImport.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/NoLineWrapTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/NoLineWrapTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/NoLineWrapTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/NoLineWrapTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,34 +19,30 @@ package com.google.checkstyle.test.chapter3filestructure.rule332nolinewrap; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck; import com.puppycrawl.tools.checkstyle.checks.whitespace.NoLineWrapCheck; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class NoLineWrapTest extends BaseCheckTestSupport { +public class NoLineWrapTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter3filestructure" + File.separator + "rule332nolinewrap" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap"; } @Test - public void badLineWrapTest() throws Exception { - + public void testBadLineWrap() throws Exception { final String[] expected = { "1: " + getCheckMessage(NoLineWrapCheck.class, "no.line.wrap", "package"), "6: " + getCheckMessage(NoLineWrapCheck.class, "no.line.wrap", "import"), + "10: " + getCheckMessage(NoLineWrapCheck.class, "no.line.wrap", "import"), }; - final Configuration checkConfig = getCheckConfig("NoLineWrap"); + final Configuration checkConfig = getModuleConfig("NoLineWrap"); final String filePath = getPath("InputNoLineWrapBad.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -54,11 +50,10 @@ } @Test - public void goodLineWrapTest() throws Exception { - - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; + public void testGoodLineWrap() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final Configuration checkConfig = getCheckConfig("NoLineWrap"); + final Configuration checkConfig = getModuleConfig("NoLineWrap"); final String filePath = getPath("InputNoLineWrapGood.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -67,17 +62,17 @@ @Test public void goodLineLength() throws Exception { - final int maxLineLength = 100; final String[] expected = { "5: " + getCheckMessage(LineLengthCheck.class, "maxLineLen", maxLineLength, 112), "29: " + getCheckMessage(LineLengthCheck.class, "maxLineLen", maxLineLength, 113), }; - final Configuration checkConfig = getCheckConfig("LineLength"); + final Configuration checkConfig = getModuleConfig("LineLength"); final String filePath = getPath("InputLineLength.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/CustomImportOrderTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/CustomImportOrderTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/CustomImportOrderTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/CustomImportOrderTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,53 +19,46 @@ package com.google.checkstyle.test.chapter3filestructure.rule333orderingandspacing; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.imports.CustomImportOrderCheck; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class CustomImportOrderTest extends BaseCheckTestSupport { - - private static final String MSG_SEPARATOR = "custom.import.order.line.separator"; - private static final String MSG_LEX = "custom.import.order.lex"; - private static final String MSG_ORDER = "custom.import.order"; +public class CustomImportOrderTest extends AbstractModuleTestSupport { /** Shortcuts to make code more compact. */ - private static final String STD = CustomImportOrderCheck.STANDARD_JAVA_PACKAGE_RULE_GROUP; - private static final String SPECIAL = CustomImportOrderCheck.SPECIAL_IMPORTS_RULE_GROUP; + private static final String MSG_LINE_SEPARATOR = CustomImportOrderCheck.MSG_LINE_SEPARATOR; + private static final String MSG_LEX = CustomImportOrderCheck.MSG_LEX; + private static final String MSG_NONGROUP_EXPECTED = + CustomImportOrderCheck.MSG_NONGROUP_EXPECTED; + + private static final String STATIC = CustomImportOrderCheck.STATIC_RULE_GROUP; private final Class clazz = CustomImportOrderCheck.class; @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter3filestructure" + File.separator + "rule333orderingandspacing" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing"; } @Test - public void customImportTest1() throws Exception { - + public void testCustomImport1() throws Exception { final String[] expected = { "4: " + getCheckMessage(clazz, MSG_LEX, "java.awt.Button.ABORT", "java.io.File.createTempFile"), - "7: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.awt.Button"), - "8: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.awt.Frame"), - "9: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.awt.Dialog"), - "10: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.awt.event.ActionEvent"), - "11: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "javax.swing.JComponent"), - "12: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "javax.swing.JTable"), - "13: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.io.File"), - "14: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.io.IOException"), - "15: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.io.InputStream"), - "16: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.io.Reader"), + "6: " + getCheckMessage(clazz, MSG_LINE_SEPARATOR, "java.awt.Button"), + "8: " + getCheckMessage(clazz, MSG_LEX, "java.awt.Dialog", "java.awt.Frame"), + "12: " + getCheckMessage(clazz, MSG_LEX, "java.io.File", "javax.swing.JTable"), + "13: " + getCheckMessage(clazz, MSG_LEX, "java.io.IOException", "javax.swing.JTable"), + "14: " + getCheckMessage(clazz, MSG_LEX, "java.io.InputStream", "javax.swing.JTable"), + "15: " + getCheckMessage(clazz, MSG_LEX, "java.io.Reader", "javax.swing.JTable"), + "17: " + getCheckMessage(clazz, MSG_LEX, "com.google.common.base.Ascii", + "javax.swing.JTable"), }; - final Configuration checkConfig = getCheckConfig("CustomImportOrder"); + final Configuration checkConfig = getModuleConfig("CustomImportOrder"); final String filePath = getPath("InputCustomImportOrder1.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -73,24 +66,23 @@ } @Test - public void customImportTest2() throws Exception { - + public void testCustomImport2() throws Exception { final String[] expected = { "4: " + getCheckMessage(clazz, MSG_LEX, "java.awt.Button.ABORT", "java.io.File.createTempFile"), - "7: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.util.List"), - "8: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.util.StringTokenizer"), - "9: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.util.*"), - "10: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, + "9: " + getCheckMessage(clazz, MSG_LEX, "java.util.*", "java.util.StringTokenizer"), + "11: " + getCheckMessage(clazz, MSG_LEX, "java.util.concurrent.*", + "java.util.concurrent.AbstractExecutorService"), + "13: " + getCheckMessage(clazz, MSG_LEX, + "com.google.checkstyle.test.chapter2filebasic.rule21filename.*", + "java.util.concurrent.AbstractExecutorService"), + "14: " + getCheckMessage(clazz, MSG_LEX, "com.sun.xml.internal.xsom.impl.scd.Iterators", + "java.util.concurrent.AbstractExecutorService"), + "16: " + getCheckMessage(clazz, MSG_LEX, "com.google.common.reflect.*", "java.util.concurrent.AbstractExecutorService"), - "11: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.util.concurrent.*"), - "14: " + getCheckMessage(clazz, MSG_SEPARATOR, - "com.sun.xml.internal.xsom.impl.scd.Iterators"), - "16: " + getCheckMessage(clazz, MSG_ORDER, SPECIAL, STD, - "com.google.common.reflect.*"), }; - final Configuration checkConfig = getCheckConfig("CustomImportOrder"); + final Configuration checkConfig = getModuleConfig("CustomImportOrder"); final String filePath = getPath("InputCustomImportOrder2.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -98,23 +90,25 @@ } @Test - public void customImportTest3() throws Exception { - + public void testCustomImport3() throws Exception { final String[] expected = { - "4: " + getCheckMessage(clazz, MSG_LEX, "java.awt.Button.ABORT", + "4: " + getCheckMessage(clazz, MSG_LINE_SEPARATOR, "java.awt.Dialog"), + "5: " + getCheckMessage(clazz, MSG_NONGROUP_EXPECTED, STATIC, + "javax.swing.WindowConstants.*"), + "7: " + getCheckMessage(clazz, MSG_LEX, + "com.google.checkstyle.test.chapter2filebasic.rule21filename.*", "java.awt.Dialog"), + "8: " + getCheckMessage(clazz, MSG_LEX, "com.google.common.reflect.*", + "java.awt.Dialog"), + "9: " + getCheckMessage(clazz, MSG_LEX, "com.sun.xml.internal.xsom.impl.scd.Iterators", + "java.awt.Dialog"), + "11: " + getCheckMessage(clazz, MSG_NONGROUP_EXPECTED, STATIC, "java.io.File.createTempFile"), - "8: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.util.StringTokenizer"), - "9: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.util.*"), - "10: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, + "13: " + getCheckMessage(clazz, MSG_LEX, "java.util.*", "java.util.StringTokenizer"), + "15: " + getCheckMessage(clazz, MSG_LEX, "java.util.concurrent.*", "java.util.concurrent.AbstractExecutorService"), - "11: " + getCheckMessage(clazz, MSG_ORDER, STD, SPECIAL, "java.util.concurrent.*"), - "14: " + getCheckMessage(clazz, MSG_SEPARATOR, - "com.sun.xml.internal.xsom.impl.scd.Iterators"), - "16: " + getCheckMessage(clazz, MSG_ORDER, SPECIAL, STD, - "com.google.common.reflect.*"), }; - final Configuration checkConfig = getCheckConfig("CustomImportOrder"); + final Configuration checkConfig = getModuleConfig("CustomImportOrder"); final String filePath = getPath("InputCustomImportOrder3.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -122,14 +116,25 @@ } @Test - public void validTest() throws Exception { + public void testValid() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; - - final Configuration checkConfig = getCheckConfig("CustomImportOrder"); + final Configuration checkConfig = getModuleConfig("CustomImportOrder"); final String filePath = getPath("InputCustomImportOrderValid.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + + @Test + public void testValidGoogleStyleOrderOfImports() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; + + final Configuration checkConfig = getModuleConfig("CustomImportOrder"); + final String filePath = getPath("InputCustomImportOrderNoImports.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule341onetoplevel/OneTopLevelClassTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule341onetoplevel/OneTopLevelClassTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule341onetoplevel/OneTopLevelClassTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule341onetoplevel/OneTopLevelClassTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,27 +19,22 @@ package com.google.checkstyle.test.chapter3filestructure.rule341onetoplevel; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.design.OneTopLevelClassCheck; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class OneTopLevelClassTest extends BaseCheckTestSupport { +public class OneTopLevelClassTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter3filestructure" + File.separator + "rule341onetoplevel" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter3filestructure/rule341onetoplevel"; } @Test - public void badTest() throws Exception { - + public void testBad() throws Exception { final Class clazz = OneTopLevelClassCheck.class; final String messageKey = "one.top.level.class"; @@ -52,7 +47,7 @@ "77: " + getCheckMessage(clazz, messageKey, "AnotherClass"), }; - final Configuration checkConfig = getCheckConfig("OneTopLevelClass"); + final Configuration checkConfig = getModuleConfig("OneTopLevelClass"); final String filePath = getPath("InputOneTopLevelClassBasic.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -60,11 +55,10 @@ } @Test - public void goodTest() throws Exception { - - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; + public void testGood() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final Configuration checkConfig = getCheckConfig("OneTopLevelClass"); + final Configuration checkConfig = getModuleConfig("OneTopLevelClass"); final String filePath = getPath("InputOneTopLevelClassGood.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -72,8 +66,7 @@ } @Test - public void bad1Test() throws Exception { - + public void testBad1() throws Exception { final Class clazz = OneTopLevelClassCheck.class; final String messageKey = "one.top.level.class"; @@ -81,7 +74,7 @@ "4: " + getCheckMessage(clazz, messageKey, "FooEnum"), }; - final Configuration checkConfig = getCheckConfig("OneTopLevelClass"); + final Configuration checkConfig = getModuleConfig("OneTopLevelClass"); final String filePath = getPath("InputOneTopLevelClassBad1.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -89,8 +82,7 @@ } @Test - public void bad2Test() throws Exception { - + public void testBad2() throws Exception { final Class clazz = OneTopLevelClassCheck.class; final String messageKey = "one.top.level.class"; @@ -99,10 +91,11 @@ "7: " + getCheckMessage(clazz, messageKey, "FooClass"), }; - final Configuration checkConfig = getCheckConfig("OneTopLevelClass"); + final Configuration checkConfig = getModuleConfig("OneTopLevelClass"); final String filePath = getPath("InputOneTopLevelClassBad2.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule3421overloadsplit/OverloadMethodsDeclarationOrderTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule3421overloadsplit/OverloadMethodsDeclarationOrderTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule3421overloadsplit/OverloadMethodsDeclarationOrderTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule3421overloadsplit/OverloadMethodsDeclarationOrderTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter3filestructure.rule3421overloadsplit; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.coding.OverloadMethodsDeclarationOrderCheck; -public class OverloadMethodsDeclarationOrderTest extends BaseCheckTestSupport { +public class OverloadMethodsDeclarationOrderTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter3filestructure" + File.separator + "rule3421overloadsplit" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter3filestructure/rule3421overloadsplit"; } @Test - public void overloadMethodsTest() throws Exception { - + public void testOverloadMethods() throws Exception { final Class clazz = OverloadMethodsDeclarationOrderCheck.class; final String messageKey = "overload.methods.declaration"; @@ -50,10 +45,11 @@ "109: " + getCheckMessage(clazz, messageKey, 98), }; - final Configuration checkConfig = getCheckConfig("OverloadMethodsDeclarationOrder"); + final Configuration checkConfig = getModuleConfig("OverloadMethodsDeclarationOrder"); final String filePath = getPath("InputOverloadMethodsDeclarationOrder.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule3sourcefile/EmptyLineSeparatorTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule3sourcefile/EmptyLineSeparatorTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule3sourcefile/EmptyLineSeparatorTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter3filestructure/rule3sourcefile/EmptyLineSeparatorTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter3filestructure.rule3sourcefile; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.whitespace.EmptyLineSeparatorCheck; -public class EmptyLineSeparatorTest extends BaseCheckTestSupport { +public class EmptyLineSeparatorTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter3filestructure" + File.separator + "rule3sourcefile" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter3filestructure/rule3sourcefile"; } @Test - public void emptyLineSeparatorTest() throws Exception { - + public void testEmptyLineSeparator() throws Exception { final Class clazz = EmptyLineSeparatorCheck.class; final String messageKey = "empty.line.separator"; @@ -54,10 +49,11 @@ "119: " + getCheckMessage(clazz, messageKey, "VARIABLE_DEF"), }; - final Configuration checkConfig = getCheckConfig("EmptyLineSeparator"); + final Configuration checkConfig = getModuleConfig("EmptyLineSeparator"); final String filePath = getPath("InputEmptyLineSeparator.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule411bracesareused/NeedBracesTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule411bracesareused/NeedBracesTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule411bracesareused/NeedBracesTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule411bracesareused/NeedBracesTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter4formatting.rule411bracesareused; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.blocks.NeedBracesCheck; -public class NeedBracesTest extends BaseCheckTestSupport { +public class NeedBracesTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule411bracesareused" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule411bracesareused"; } @Test - public void needBracesTest() throws Exception { - + public void testNeedBraces() throws Exception { final Class clazz = NeedBracesCheck.class; final String messageKey = "needBraces"; @@ -83,10 +78,11 @@ "210: " + getCheckMessage(clazz, messageKey, "for"), }; - final Configuration checkConfig = getCheckConfig("NeedBraces"); + final Configuration checkConfig = getModuleConfig("NeedBraces"); final String filePath = getPath("InputNeedBraces.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/LeftCurlyTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/LeftCurlyTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/LeftCurlyTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/LeftCurlyTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,26 +21,21 @@ import static com.puppycrawl.tools.checkstyle.checks.blocks.LeftCurlyCheck.MSG_KEY_LINE_PREVIOUS; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.blocks.LeftCurlyCheck; -public class LeftCurlyTest extends BaseCheckTestSupport { +public class LeftCurlyTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule412nonemptyblocks" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks"; } @Test - public void leftCurlyBracesTest() throws Exception { - + public void testLeftCurlyBraces() throws Exception { final String[] expected = { "4:1: " + getCheckMessage(LeftCurlyCheck.class, MSG_KEY_LINE_PREVIOUS, "{", 1), "7:5: " + getCheckMessage(LeftCurlyCheck.class, MSG_KEY_LINE_PREVIOUS, "{", 5), @@ -51,7 +46,7 @@ "97:5: " + getCheckMessage(LeftCurlyCheck.class, MSG_KEY_LINE_PREVIOUS, "{", 5), }; - final Configuration checkConfig = getCheckConfig("LeftCurly"); + final Configuration checkConfig = getModuleConfig("LeftCurly"); final String filePath = getPath("InputLeftCurlyBraces.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -59,8 +54,7 @@ } @Test - public void leftCurlyAnnotationsTest() throws Exception { - + public void testLeftCurlyAnnotations() throws Exception { final String[] expected = { "10:1: " + getCheckMessage(LeftCurlyCheck.class, MSG_KEY_LINE_PREVIOUS, "{", 1), "14:5: " + getCheckMessage(LeftCurlyCheck.class, MSG_KEY_LINE_PREVIOUS, "{", 5), @@ -69,7 +63,7 @@ "50:5: " + getCheckMessage(LeftCurlyCheck.class, MSG_KEY_LINE_PREVIOUS, "{", 5), }; - final Configuration checkConfig = getCheckConfig("LeftCurly"); + final Configuration checkConfig = getModuleConfig("LeftCurly"); final String filePath = getPath("InputLeftCurlyAnnotations.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -77,8 +71,7 @@ } @Test - public void leftCurlyMethodsTest() throws Exception { - + public void testLeftCurlyMethods() throws Exception { final String[] expected = { "4:1: " + getCheckMessage(LeftCurlyCheck.class, MSG_KEY_LINE_PREVIOUS, "{", 1), "9:5: " + getCheckMessage(LeftCurlyCheck.class, MSG_KEY_LINE_PREVIOUS, "{", 5), @@ -97,10 +90,11 @@ "76:5: " + getCheckMessage(LeftCurlyCheck.class, MSG_KEY_LINE_PREVIOUS, "{", 5), }; - final Configuration checkConfig = getCheckConfig("LeftCurly"); + final Configuration checkConfig = getModuleConfig("LeftCurly"); final String filePath = getPath("InputLeftCurlyMethod.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/RightCurlyTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/RightCurlyTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/RightCurlyTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/RightCurlyTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,33 +20,67 @@ package com.google.checkstyle.test.chapter4formatting.rule412nonemptyblocks; import static com.puppycrawl.tools.checkstyle.checks.blocks.RightCurlyCheck.MSG_KEY_LINE_ALONE; +import static com.puppycrawl.tools.checkstyle.checks.blocks.RightCurlyCheck.MSG_KEY_LINE_BREAK_BEFORE; import static com.puppycrawl.tools.checkstyle.checks.blocks.RightCurlyCheck.MSG_KEY_LINE_NEW; +import static com.puppycrawl.tools.checkstyle.checks.blocks.RightCurlyCheck.MSG_KEY_LINE_SAME; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; -import com.puppycrawl.tools.checkstyle.DefaultConfiguration; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; +import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.blocks.RightCurlyCheck; -import com.puppycrawl.tools.checkstyle.checks.blocks.RightCurlyOption; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class RightCurlyTest extends BaseCheckTestSupport { +public class RightCurlyTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule412nonemptyblocks" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks"; + } + + @Test + public void testRightCurlyAlone() throws Exception { + final String[] expected = { + "20:17: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_SAME, "}", 17), + "32:13: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_SAME, "}", 13), + "79:27: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_BREAK_BEFORE, "}", 27), + }; + + final Configuration checkConfig = getModuleConfig("RightCurly", "RightCurlySame"); + final String filePath = getPath("InputRightCurlyOther.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); } @Test - public void rightCurlyTestAlone() throws Exception { - final DefaultConfiguration newCheckConfig = createCheckConfig(RightCurlyCheck.class); - newCheckConfig.addAttribute("option", RightCurlyOption.ALONE.toString()); - newCheckConfig.addAttribute("tokens", "CLASS_DEF, METHOD_DEF, CTOR_DEF"); + public void testRightCurlySame() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; + + final Configuration checkConfig = getModuleConfig("RightCurly", "RightCurlySame"); + final String filePath = getPath("InputRightCurlySame.java"); + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + + @Test + public void testRightCurlySameAndLiteralDoDefault() throws Exception { + final String[] expected = { + "62:9: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_SAME, "}", 9), + "67:13: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_SAME, "}", 13), + "83:9: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_SAME, "}", 9), + }; + + final Configuration checkConfig = getModuleConfig("RightCurly", "RightCurlySame"); + final String filePath = getPath("InputRightCurlyDoWhile.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + + @Test + public void testRightCurlyAloneOther() throws Exception { final String[] expected = { "97:5: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_ALONE, "}", 5), "97:6: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_NEW, "}", 6), @@ -55,20 +89,33 @@ "122:6: " + getCheckMessage(RightCurlyCheck.class, MSG_KEY_LINE_NEW, "}", 6), }; - final String filePath = getPath("InputRightCurlyOther.java"); + final Configuration checkConfig = getModuleConfig("RightCurly", "RightCurlyAlone"); + final String filePath = getPath("InputRightCurlyOtherAlone.java"); + final Integer[] warnList = getLinesWithWarn(filePath); - verify(newCheckConfig, filePath, expected, warnList); + verify(checkConfig, filePath, expected, warnList); } @Test - public void rightCurlyTestSame() throws Exception { - final DefaultConfiguration newCheckConfig = createCheckConfig(RightCurlyCheck.class); - newCheckConfig.addAttribute("option", RightCurlyOption.SAME.toString()); - - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; + public void testRightCurlyAloneSame() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; + final Configuration checkConfig = getModuleConfig("RightCurly", "RightCurlyAlone"); final String filePath = getPath("InputRightCurlySame.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + + @Test + public void testRightCurlyAloneSameAndLiteralDo() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; + + final Configuration checkConfig = getModuleConfig("RightCurly", "RightCurlyAlone"); + final String filePath = getPath("InputRightCurlyDoWhileAlone.java"); + final Integer[] warnList = getLinesWithWarn(filePath); - verify(newCheckConfig, filePath, expected, warnList); + verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/EmptyBlockTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/EmptyBlockTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/EmptyBlockTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/EmptyBlockTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter4formatting.rule413emptyblocks; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.blocks.EmptyBlockCheck; -public class EmptyBlockTest extends BaseCheckTestSupport { +public class EmptyBlockTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule413emptyblocks" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule413emptyblocks"; } @Test - public void emptyBlockTest() throws Exception { - + public void testEmptyBlock() throws Exception { final String[] expected = { "19:21: " + getCheckMessage(EmptyBlockCheck.class, "block.empty", "if"), "22:34: " + getCheckMessage(EmptyBlockCheck.class, "block.empty", "if"), @@ -75,7 +70,7 @@ "320:34: " + getCheckMessage(EmptyBlockCheck.class, "block.empty", "if"), }; - final Configuration checkConfig = getCheckConfig("EmptyBlock"); + final Configuration checkConfig = getModuleConfig("EmptyBlock"); final String filePath = getPath("InputEmptyBlockBasic.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -83,18 +78,18 @@ } @Test - public void emptyBlockTestCatch() throws Exception { - + public void testEmptyBlockCatch() throws Exception { final String[] expected = { "29:17: " + getCheckMessage(EmptyBlockCheck.class, "block.empty", "finally"), "50:21: " + getCheckMessage(EmptyBlockCheck.class, "block.empty", "finally"), "72:21: " + getCheckMessage(EmptyBlockCheck.class, "block.empty", "finally"), }; - final Configuration checkConfig = getCheckConfig("EmptyBlock"); + final Configuration checkConfig = getModuleConfig("EmptyBlock"); final String filePath = getPath("InputEmptyBlock.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/EmptyCatchBlockTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/EmptyCatchBlockTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/EmptyCatchBlockTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/EmptyCatchBlockTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,34 +19,31 @@ package com.google.checkstyle.test.chapter4formatting.rule413emptyblocks; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.blocks.EmptyCatchBlockCheck; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class EmptyCatchBlockTest extends BaseCheckTestSupport { +public class EmptyCatchBlockTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule413emptyblocks" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule413emptyblocks"; } @Test - public void emptyBlockTestCatch() throws Exception { - + public void testEmptyBlockCatch() throws Exception { final String[] expected = { "28: " + getCheckMessage(EmptyCatchBlockCheck.class, "catch.block.empty"), "49: " + getCheckMessage(EmptyCatchBlockCheck.class, "catch.block.empty"), "71: " + getCheckMessage(EmptyCatchBlockCheck.class, "catch.block.empty"), + "79: " + getCheckMessage(EmptyCatchBlockCheck.class, "catch.block.empty"), + "83: " + getCheckMessage(EmptyCatchBlockCheck.class, "catch.block.empty"), }; - final Configuration checkConfig = getCheckConfig("EmptyCatchBlock"); + final Configuration checkConfig = getModuleConfig("EmptyCatchBlock"); final String filePath = getPath("InputEmptyBlockCatch.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -55,10 +52,9 @@ @Test public void testNoViolations() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; - - final Configuration checkConfig = getCheckConfig("EmptyCatchBlock"); + final Configuration checkConfig = getModuleConfig("EmptyCatchBlock"); final String filePath = getPath("InputEmptyCatchBlockNoViolations.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -67,13 +63,12 @@ @Test public void testViolationsByComment() throws Exception { - final String[] expected = { "19: " + getCheckMessage(EmptyCatchBlockCheck.class, "catch.block.empty"), "27: " + getCheckMessage(EmptyCatchBlockCheck.class, "catch.block.empty"), }; - final Configuration checkConfig = getCheckConfig("EmptyCatchBlock"); + final Configuration checkConfig = getModuleConfig("EmptyCatchBlock"); final String filePath = getPath("InputEmptyCatchBlockViolationsByComment.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -89,10 +84,11 @@ "58: " + getCheckMessage(EmptyCatchBlockCheck.class, "catch.block.empty"), }; - final Configuration checkConfig = getCheckConfig("EmptyCatchBlock"); + final Configuration checkConfig = getModuleConfig("EmptyCatchBlock"); final String filePath = getPath("InputEmptyCatchBlockViolationsByVariableName.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule43onestatement/OneStatementPerLineTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule43onestatement/OneStatementPerLineTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule43onestatement/OneStatementPerLineTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule43onestatement/OneStatementPerLineTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,25 +20,22 @@ package com.google.checkstyle.test.chapter4formatting.rule43onestatement; import java.io.File; -import java.io.IOException; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.coding.OneStatementPerLineCheck; -public class OneStatementPerLineTest extends BaseCheckTestSupport { +public class OneStatementPerLineTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule43onestatement" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule43onestatement"; } @Test - public void oneStatementTest() throws Exception { - + public void testOneStatement() throws Exception { final String msg = getCheckMessage(OneStatementPerLineCheck.class, "multiple.statements.line"); @@ -66,7 +63,7 @@ "307:39: " + msg, }; - final Configuration checkConfig = getCheckConfig("OneStatementPerLine"); + final Configuration checkConfig = getModuleConfig("OneStatementPerLine"); final String filePath = getPath("InputOneStatementPerLine.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -74,26 +71,26 @@ } @Test - public void oneStatementNonCompilableInputTest() throws Exception { - + public void testOneStatementNonCompilableInput() throws Exception { final String msg = getCheckMessage(OneStatementPerLineCheck.class, "multiple.statements.line"); final String[] expected = { - "31:6: " + msg, - "36:58: " + msg, + "32:6: " + msg, "37:58: " + msg, - "37:74: " + msg, - "38:50: " + msg, - "42:91: " + msg, + "38:58: " + msg, + "38:74: " + msg, + "39:50: " + msg, + "43:91: " + msg, }; - final Configuration checkConfig = getCheckConfig("OneStatementPerLine"); + final Configuration checkConfig = getModuleConfig("OneStatementPerLine"); final String filePath = new File("src/test/resources-noncompilable/" - + "com/puppycrawl/tools/checkstyle/checks/coding/" + + "com/puppycrawl/tools/checkstyle/checks/coding/onestatementperline/" + "InputOneStatementPerLine.java").getCanonicalPath(); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule44columnlimit/LineLengthTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule44columnlimit/LineLengthTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule44columnlimit/LineLengthTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule44columnlimit/LineLengthTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,35 +19,31 @@ package com.google.checkstyle.test.chapter4formatting.rule44columnlimit; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck; -public class LineLengthTest extends BaseCheckTestSupport { +public class LineLengthTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule44columnlimit" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule44columnlimit"; } @Test - public void lineLengthTest() throws Exception { - + public void testLineLength() throws Exception { final String[] expected = { "5: " + getCheckMessage(LineLengthCheck.class, "maxLineLen", 100, 112), "29: " + getCheckMessage(LineLengthCheck.class, "maxLineLen", 100, 113), }; - final Configuration checkConfig = getCheckConfig("LineLength"); + final Configuration checkConfig = getModuleConfig("LineLength"); final String filePath = getPath("InputLineLength.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/MethodParamPadTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/MethodParamPadTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/MethodParamPadTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/MethodParamPadTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter4formatting.rule451wheretobreak; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.whitespace.MethodParamPadCheck; -public class MethodParamPadTest extends BaseCheckTestSupport { +public class MethodParamPadTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule451wheretobreak" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule451wheretobreak"; } @Test - public void operatorWrapTest() throws Exception { - + public void testOperatorWrap() throws Exception { final Class clazz = MethodParamPadCheck.class; final String messageKeyPrevious = "line.previous"; final String messageKeyPreceded = "ws.preceded"; @@ -50,10 +45,11 @@ "353:15: " + getCheckMessage(clazz, messageKeyPreceded, "("), "358:13: " + getCheckMessage(clazz, messageKeyPrevious, "("), }; - final Configuration checkConfig = getCheckConfig("MethodParamPad"); + final Configuration checkConfig = getModuleConfig("MethodParamPad"); final String filePath = getPath("InputMethodParamPad.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/OperatorWrapTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/OperatorWrapTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/OperatorWrapTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/OperatorWrapTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,110 +19,51 @@ package com.google.checkstyle.test.chapter4formatting.rule451wheretobreak; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; -import com.puppycrawl.tools.checkstyle.DefaultConfiguration; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.whitespace.OperatorWrapCheck; -import com.puppycrawl.tools.checkstyle.checks.whitespace.WrapOption; -public class OperatorWrapTest extends BaseCheckTestSupport { +public class OperatorWrapTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule451wheretobreak" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule451wheretobreak"; } @Test - public void operatorWrapTest() throws Exception { - + public void testOperatorWrap() throws Exception { final Class clazz = OperatorWrapCheck.class; final String messageKey = "line.new"; final String[] expected = { - "10:27: " + getCheckMessage(clazz, messageKey, "+"), - "11:28: " + getCheckMessage(clazz, messageKey, "-"), - "19:27: " + getCheckMessage(clazz, messageKey, "&&"), - "53:42: " + getCheckMessage(clazz, messageKey, "?"), - "57:27: " + getCheckMessage(clazz, messageKey, "!="), - "63:30: " + getCheckMessage(clazz, messageKey, "=="), - "69:27: " + getCheckMessage(clazz, messageKey, ">"), - "75:35: " + getCheckMessage(clazz, messageKey, "||"), - "98:46: " + getCheckMessage(clazz, messageKey, "?"), - "102:31: " + getCheckMessage(clazz, messageKey, "!="), - "108:34: " + getCheckMessage(clazz, messageKey, "=="), - "114:31: " + getCheckMessage(clazz, messageKey, ">"), - "120:39: " + getCheckMessage(clazz, messageKey, "||"), - "144:46: " + getCheckMessage(clazz, messageKey, "?"), - "148:31: " + getCheckMessage(clazz, messageKey, "!="), - "154:34: " + getCheckMessage(clazz, messageKey, "=="), - "160:31: " + getCheckMessage(clazz, messageKey, ">"), - "166:39: " + getCheckMessage(clazz, messageKey, "||"), - "185:38: " + getCheckMessage(clazz, messageKey, "?"), + "11:27: " + getCheckMessage(clazz, messageKey, "+"), + "12:28: " + getCheckMessage(clazz, messageKey, "-"), + "20:27: " + getCheckMessage(clazz, messageKey, "&&"), + "62:42: " + getCheckMessage(clazz, messageKey, "?"), + "66:27: " + getCheckMessage(clazz, messageKey, "!="), + "72:30: " + getCheckMessage(clazz, messageKey, "=="), + "78:27: " + getCheckMessage(clazz, messageKey, ">"), + "84:35: " + getCheckMessage(clazz, messageKey, "||"), + "107:46: " + getCheckMessage(clazz, messageKey, "?"), + "111:31: " + getCheckMessage(clazz, messageKey, "!="), + "117:34: " + getCheckMessage(clazz, messageKey, "=="), + "123:31: " + getCheckMessage(clazz, messageKey, ">"), + "129:39: " + getCheckMessage(clazz, messageKey, "||"), + "153:46: " + getCheckMessage(clazz, messageKey, "?"), + "157:31: " + getCheckMessage(clazz, messageKey, "!="), + "163:34: " + getCheckMessage(clazz, messageKey, "=="), + "169:31: " + getCheckMessage(clazz, messageKey, ">"), + "175:39: " + getCheckMessage(clazz, messageKey, "||"), + "194:38: " + getCheckMessage(clazz, messageKey, "?"), }; - final Configuration checkConfig = getCheckConfig("OperatorWrap"); + final Configuration checkConfig = getModuleConfig("OperatorWrap"); final String filePath = getPath("InputOperatorWrap.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } - @Test - public void operatorWrapTestAssign() throws Exception { - final DefaultConfiguration newCheckConfig = createCheckConfig(OperatorWrapCheck.class); - newCheckConfig.addAttribute("option", WrapOption.EOL.toString()); - newCheckConfig.addAttribute("tokens", "ASSIGN, DIV_ASSIGN, PLUS_ASSIGN, MINUS_ASSIGN," - + "STAR_ASSIGN, MOD_ASSIGN, SR_ASSIGN, BSR_ASSIGN, SL_ASSIGN, BXOR_ASSIGN," - + "BOR_ASSIGN, BAND_ASSIGN"); - final String messageKey = "line.previous"; - final Class clazz = OperatorWrapCheck.class; - - final String[] expected = { - "28:13: " + getCheckMessage(clazz, messageKey, "="), - "177:9: " + getCheckMessage(clazz, messageKey, "="), - "207:14: " + getCheckMessage(clazz, messageKey, "+="), - "211:14: " + getCheckMessage(clazz, messageKey, "-="), - "215:14: " + getCheckMessage(clazz, messageKey, "/="), - "219:14: " + getCheckMessage(clazz, messageKey, "*="), - "223:14: " + getCheckMessage(clazz, messageKey, "%="), - "227:14: " + getCheckMessage(clazz, messageKey, "^="), - "231:14: " + getCheckMessage(clazz, messageKey, "|="), - "235:14: " + getCheckMessage(clazz, messageKey, "&="), - "239:13: " + getCheckMessage(clazz, messageKey, ">>="), - "243:13: " + getCheckMessage(clazz, messageKey, ">>>="), - "247:13: " + getCheckMessage(clazz, messageKey, "<<="), - "257:18: " + getCheckMessage(clazz, messageKey, "+="), - "261:18: " + getCheckMessage(clazz, messageKey, "-="), - "265:18: " + getCheckMessage(clazz, messageKey, "/="), - "269:18: " + getCheckMessage(clazz, messageKey, "*="), - "273:18: " + getCheckMessage(clazz, messageKey, "%="), - "277:18: " + getCheckMessage(clazz, messageKey, "^="), - "281:18: " + getCheckMessage(clazz, messageKey, "|="), - "285:18: " + getCheckMessage(clazz, messageKey, "&="), - "289:17: " + getCheckMessage(clazz, messageKey, ">>="), - "293:17: " + getCheckMessage(clazz, messageKey, ">>>="), - "297:17: " + getCheckMessage(clazz, messageKey, "<<="), - "308:18: " + getCheckMessage(clazz, messageKey, "+="), - "312:18: " + getCheckMessage(clazz, messageKey, "-="), - "316:18: " + getCheckMessage(clazz, messageKey, "/="), - "320:18: " + getCheckMessage(clazz, messageKey, "*="), - "324:18: " + getCheckMessage(clazz, messageKey, "%="), - "328:18: " + getCheckMessage(clazz, messageKey, "^="), - "332:18: " + getCheckMessage(clazz, messageKey, "|="), - "336:18: " + getCheckMessage(clazz, messageKey, "&="), - "340:17: " + getCheckMessage(clazz, messageKey, ">>="), - "344:17: " + getCheckMessage(clazz, messageKey, ">>>="), - "348:17: " + getCheckMessage(clazz, messageKey, "<<="), - }; - - final String filePath = getPath("InputOperatorWrapAssign.java"); - final Integer[] warnList = getLinesWithWarn(filePath); - verify(newCheckConfig, filePath, expected, warnList); - } } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/SeparatorWrapTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/SeparatorWrapTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/SeparatorWrapTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/SeparatorWrapTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,34 +19,85 @@ package com.google.checkstyle.test.chapter4formatting.rule451wheretobreak; -import java.io.File; -import java.io.IOException; +import static com.puppycrawl.tools.checkstyle.checks.whitespace.SeparatorWrapCheck.MSG_LINE_NEW; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.whitespace.SeparatorWrapCheck; -public class SeparatorWrapTest extends BaseCheckTestSupport { +public class SeparatorWrapTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule451wheretobreak" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule451wheretobreak"; } @Test - public void separatorWrapTest() throws Exception { - + public void testSeparatorWrapDot() throws Exception { final String[] expected = { "28:30: " + getCheckMessage(SeparatorWrapCheck.class, "line.new", "."), }; - final Configuration checkConfig = getCheckConfig("SeparatorWrap"); + final Configuration checkConfig = getModuleConfig("SeparatorWrap", "SeparatorWrapDot"); final String filePath = getPath("InputSeparatorWrap.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + + @Test + public void testSeparatorWrapComma() throws Exception { + final String[] expected = { + "31:17: " + getCheckMessage(SeparatorWrapCheck.class, "line.previous", ","), + }; + + final Configuration checkConfig = getModuleConfig("SeparatorWrap", "SeparatorWrapComma"); + final String filePath = getPath("InputSeparatorWrapComma.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + + @Test + public void testSeparatorWrapMethodRef() throws Exception { + final String[] expected = { + "17:49: " + getCheckMessage(SeparatorWrapCheck.class, MSG_LINE_NEW, "::"), + }; + + final Configuration checkConfig = getModuleConfig("SeparatorWrap", + "SeparatorWrapMethodRef"); + final String filePath = getPath("InputSeparatorWrapMethodRef.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + + @Test + public void testEllipsis() throws Exception { + final String[] expected = { + "11:13: " + getCheckMessage(SeparatorWrapCheck.class, "line.previous", "..."), + }; + + final Configuration checkConfig = getModuleConfig("SeparatorWrap", "SeparatorWrapEllipsis"); + final String filePath = getPath("InputSeparatorWrapEllipsis.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + + @Test + public void testArrayDeclarator() throws Exception { + final String[] expected = { + "9:13: " + getCheckMessage(SeparatorWrapCheck.class, "line.previous", "["), + }; + final Configuration checkConfig = getModuleConfig("SeparatorWrap", + "SeparatorWrapArrayDeclarator"); + final String filePath = getPath("InputSeparatorWrapArrayDeclarator.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule461verticalwhitespace/EmptyLineSeparatorTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule461verticalwhitespace/EmptyLineSeparatorTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule461verticalwhitespace/EmptyLineSeparatorTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule461verticalwhitespace/EmptyLineSeparatorTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter4formatting.rule461verticalwhitespace; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.whitespace.EmptyLineSeparatorCheck; -public class EmptyLineSeparatorTest extends BaseCheckTestSupport { +public class EmptyLineSeparatorTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule461verticalwhitespace" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule461verticalwhitespace"; } @Test - public void emptyLineSeparatorTest() throws Exception { - + public void testEmptyLineSeparator() throws Exception { final Class clazz = EmptyLineSeparatorCheck.class; final String messageKey = "empty.line.separator"; @@ -54,10 +49,11 @@ "119: " + getCheckMessage(clazz, messageKey, "VARIABLE_DEF"), }; - final Configuration checkConfig = getCheckConfig("EmptyLineSeparator"); + final Configuration checkConfig = getModuleConfig("EmptyLineSeparator"); final String filePath = getPath("InputEmptyLineSeparator.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/GenericWhitespaceTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/GenericWhitespaceTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/GenericWhitespaceTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/GenericWhitespaceTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,28 +19,24 @@ package com.google.checkstyle.test.chapter4formatting.rule462horizontalwhitespace; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class GenericWhitespaceTest extends BaseCheckTestSupport { +public class GenericWhitespaceTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule462horizontalwhitespace" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace"; } @Test - public void whitespaceAroundGenericsTest() throws Exception { - + public void testWhitespaceAroundGenerics() throws Exception { final String msgPreceded = "ws.preceded"; final String msgFollowed = "ws.followed"; - final Configuration checkConfig = getCheckConfig("GenericWhitespace"); + final Configuration checkConfig = getModuleConfig("GenericWhitespace"); final String[] expected = { "12:16: " + getCheckMessage(checkConfig.getMessages(), msgPreceded, "<"), @@ -68,12 +64,12 @@ } @Test - public void genericWhitespaceTest() throws Exception { + public void testGenericWhitespace() throws Exception { final String msgPreceded = "ws.preceded"; final String msgFollowed = "ws.followed"; final String msgNotPreceded = "ws.notPreceded"; final String msgIllegalFollow = "ws.illegalFollow"; - final Configuration checkConfig = getCheckConfig("GenericWhitespace"); + final Configuration checkConfig = getModuleConfig("GenericWhitespace"); final String[] expected = { "16:13: " + getCheckMessage(checkConfig.getMessages(), msgPreceded, "<"), @@ -112,10 +108,10 @@ @Test public void genericEndsTheLine() throws Exception { - final Configuration checkConfig = getCheckConfig("GenericWhitespace"); - final String[] expected = { - }; + final Configuration checkConfig = getModuleConfig("GenericWhitespace"); + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checkConfig, getPath("InputGenericWhitespaceEndsTheLine.java"), expected); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/MethodParamPadTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/MethodParamPadTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/MethodParamPadTest.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/MethodParamPadTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,57 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.google.checkstyle.test.chapter4formatting.rule462horizontalwhitespace; + +import org.junit.Test; + +import com.google.checkstyle.test.base.AbstractModuleTestSupport; +import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.checks.whitespace.MethodParamPadCheck; + +public class MethodParamPadTest extends AbstractModuleTestSupport { + + @Override + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace"; + } + + @Test + public void testOperatorWrap() throws Exception { + final Class clazz = MethodParamPadCheck.class; + final String messageKeyPreceded = "ws.preceded"; + + final String[] expected = { + "11:32: " + getCheckMessage(clazz, messageKeyPreceded, "("), + "13:15: " + getCheckMessage(clazz, messageKeyPreceded, "("), + "20:24: " + getCheckMessage(clazz, messageKeyPreceded, "("), + "29:39: " + getCheckMessage(clazz, messageKeyPreceded, "("), + "35:16: " + getCheckMessage(clazz, messageKeyPreceded, "("), + "41:21: " + getCheckMessage(clazz, messageKeyPreceded, "("), + "47:18: " + getCheckMessage(clazz, messageKeyPreceded, "("), + "52:36: " + getCheckMessage(clazz, messageKeyPreceded, "("), + }; + final Configuration checkConfig = getModuleConfig("MethodParamPad"); + final String filePath = getPath("InputMethodParamPad.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + +} diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/NoWhitespaceBeforeTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/NoWhitespaceBeforeTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/NoWhitespaceBeforeTest.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/NoWhitespaceBeforeTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,52 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.google.checkstyle.test.chapter4formatting.rule462horizontalwhitespace; + +import org.junit.Test; + +import com.google.checkstyle.test.base.AbstractModuleTestSupport; +import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.checks.whitespace.NoWhitespaceBeforeCheck; + +public class NoWhitespaceBeforeTest extends AbstractModuleTestSupport { + + @Override + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace"; + } + + @Test + public void testEmptyForLoop() throws Exception { + final Class clazz = NoWhitespaceBeforeCheck.class; + final String messageKeyPreceded = "ws.preceded"; + + final String[] expected = { + "12:23: " + getCheckMessage(clazz, messageKeyPreceded, ";"), + "18:31: " + getCheckMessage(clazz, messageKeyPreceded, ";"), + }; + final Configuration checkConfig = getModuleConfig("NoWhitespaceBefore"); + final String filePath = getPath("InputNoWhitespaceBeforeEmptyForLoop.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + +} + diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/ParenPadTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/ParenPadTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/ParenPadTest.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/ParenPadTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,170 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.google.checkstyle.test.chapter4formatting.rule462horizontalwhitespace; + +import org.junit.Test; + +import com.google.checkstyle.test.base.AbstractModuleTestSupport; +import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.checks.whitespace.ParenPadCheck; + +public class ParenPadTest extends AbstractModuleTestSupport { + + @Override + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace"; + } + + @Test + public void testMethodParen() throws Exception { + final Class clazz = ParenPadCheck.class; + final String messageKeyPreceded = "ws.preceded"; + final String messageKeyFollowed = "ws.followed"; + + final String[] expected = { + "44:27: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "44:27: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "45:18: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "48:27: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "49:19: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "49:19: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "52:27: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "53:21: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "54:18: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "54:52: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "54:52: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "57:26: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "58:22: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "59:24: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "60:26: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "60:51: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "60:57: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "61:29: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "62:43: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "63:41: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "65:43: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "78:28: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "78:28: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "79:19: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "82:33: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "83:19: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "83:19: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "86:29: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "87:35: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "88:51: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "88:51: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "88:53: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "90:38: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "91:32: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "92:35: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "93:30: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "94:60: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "94:62: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "94:69: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "95:34: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "96:47: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "97:42: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "99:44: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "112:17: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "113:23: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "113:25: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "113:31: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "114:26: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "114:28: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "114:34: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "114:50: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "115:26: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "115:28: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "115:35: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "115:53: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "115:55: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "119:17: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "119:22: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "123:30: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "123:44: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "126:22: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "126:22: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "130:19: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "130:19: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "139:10: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "139:20: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "145:33: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "145:46: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "153:34: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "154:48: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "155:36: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "155:46: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "159:26: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "159:35: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "160:13: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "160:29: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "160:48: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "160:50: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "163:32: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "163:35: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "163:48: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "163:60: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "166:39: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "167:25: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "167:50: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "173:38: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "174:48: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "175:21: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "175:48: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "185:17: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "185:35: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "186:20: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "186:38: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "190:30: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "190:44: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "191:13: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "191:38: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "192:23: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "192:39: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "200:81: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "200:83: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "201:21: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "202:23: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "203:21: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "203:24: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "206:14: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "206:22: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "206:32: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "207:18: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "207:46: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "210:37: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "210:74: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "210:80: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "210:82: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "211:37: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "212:49: " + getCheckMessage(clazz, messageKeyFollowed, "("), + "212:51: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "212:53: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "220:36: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + "221:60: " + getCheckMessage(clazz, messageKeyPreceded, ")"), + }; + final Configuration checkConfig = getModuleConfig("ParenPad"); + final String filePath = getPath("InputParenPad.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + +} diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/WhitespaceAroundTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/WhitespaceAroundTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/WhitespaceAroundTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/WhitespaceAroundTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,27 +19,22 @@ package com.google.checkstyle.test.chapter4formatting.rule462horizontalwhitespace; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class WhitespaceAroundTest extends BaseCheckTestSupport { +public class WhitespaceAroundTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule462horizontalwhitespace" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace"; } @Test - public void whitespaceAroundBasicTest() throws Exception { - - final Configuration checkConfig = getCheckConfig("WhitespaceAround"); + public void testWhitespaceAroundBasic() throws Exception { + final Configuration checkConfig = getModuleConfig("WhitespaceAround"); final String msgPreceded = "ws.notPreceded"; final String msgFollowed = "ws.notFollowed"; @@ -64,6 +59,9 @@ "118:20: " + getCheckMessage(checkConfig.getMessages(), msgFollowed, "/"), "147:15: " + getCheckMessage(checkConfig.getMessages(), msgFollowed, "assert"), "150:20: " + getCheckMessage(checkConfig.getMessages(), msgPreceded, ":"), + "249:14: " + getCheckMessage(checkConfig.getMessages(), msgPreceded, "->"), + "250:17: " + getCheckMessage(checkConfig.getMessages(), msgFollowed, "->"), + "250:17: " + getCheckMessage(checkConfig.getMessages(), msgPreceded, "{"), }; final String filePath = getPath("InputWhitespaceAroundBasic.java"); @@ -73,14 +71,14 @@ } @Test - public void whitespaceAroundEmptyTypesCyclesTest() throws Exception { + public void testWhitespaceAroundEmptyTypesCycles() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; - - final Configuration checkConfig = getCheckConfig("WhitespaceAround"); + final Configuration checkConfig = getModuleConfig("WhitespaceAround"); final String filePath = getPath("InputWhitespaceAroundEmptyTypesAndCycles.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4821onevariableperline/MultipleVariableDeclarationsTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4821onevariableperline/MultipleVariableDeclarationsTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4821onevariableperline/MultipleVariableDeclarationsTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4821onevariableperline/MultipleVariableDeclarationsTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter4formatting.rule4821onevariableperline; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.coding.MultipleVariableDeclarationsCheck; -public class MultipleVariableDeclarationsTest extends BaseCheckTestSupport { +public class MultipleVariableDeclarationsTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule4821onevariableperline" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule4821onevariableperline"; } @Test - public void multipleVariableDeclarationsTest() throws Exception { - + public void testMultipleVariableDeclarations() throws Exception { final String msgComma = getCheckMessage(MultipleVariableDeclarationsCheck.class, "multiple.variable.declarations.comma"); final String msg = getCheckMessage(MultipleVariableDeclarationsCheck.class, @@ -67,10 +62,11 @@ "89:5: " + msgComma, }; - final Configuration checkConfig = getCheckConfig("MultipleVariableDeclarations"); + final Configuration checkConfig = getModuleConfig("MultipleVariableDeclarations"); final String filePath = getPath("InputMultipleVariableDeclarations.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4822variabledistance/VariableDeclarationUsageDistanceTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4822variabledistance/VariableDeclarationUsageDistanceTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4822variabledistance/VariableDeclarationUsageDistanceTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4822variabledistance/VariableDeclarationUsageDistanceTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter4formatting.rule4822variabledistance; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.coding.VariableDeclarationUsageDistanceCheck; -public class VariableDeclarationUsageDistanceTest extends BaseCheckTestSupport { +public class VariableDeclarationUsageDistanceTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule4822variabledistance" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule4822variabledistance"; } @Test - public void arrayTypeStyleTest() throws Exception { - + public void testArrayTypeStyle() throws Exception { final String msgExt = "variable.declaration.usage.distance.extend"; final Class clazz = VariableDeclarationUsageDistanceCheck.class; @@ -51,10 +46,11 @@ }; final Configuration checkConfig = - getCheckConfig("VariableDeclarationUsageDistance"); + getModuleConfig("VariableDeclarationUsageDistance"); final String filePath = getPath("InputVariableDeclarationUsageDistanceCheck.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4832nocstylearray/ArrayTypeStyleTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4832nocstylearray/ArrayTypeStyleTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4832nocstylearray/ArrayTypeStyleTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4832nocstylearray/ArrayTypeStyleTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,26 +21,21 @@ import static com.puppycrawl.tools.checkstyle.checks.ArrayTypeStyleCheck.MSG_KEY; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.ArrayTypeStyleCheck; -public class ArrayTypeStyleTest extends BaseCheckTestSupport { +public class ArrayTypeStyleTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule4832nocstylearray" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule4832nocstylearray"; } @Test - public void arrayTypeStyleTest() throws Exception { - + public void testArrayTypeStyle() throws Exception { final String[] expected = { "9:23: " + getCheckMessage(ArrayTypeStyleCheck.class, MSG_KEY), "15:44: " + getCheckMessage(ArrayTypeStyleCheck.class, MSG_KEY), @@ -50,10 +45,11 @@ "42:19: " + getCheckMessage(ArrayTypeStyleCheck.class, MSG_KEY), }; - final Configuration checkConfig = getCheckConfig("ArrayTypeStyle"); + final Configuration checkConfig = getModuleConfig("ArrayTypeStyle"); final String filePath = getPath("InputArrayTypeStyle.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4841indentation/IndentationTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4841indentation/IndentationTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4841indentation/IndentationTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4841indentation/IndentationTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,29 +19,24 @@ package com.google.checkstyle.test.chapter4formatting.rule4841indentation; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import com.google.checkstyle.test.base.BaseIndentationCheckSupport; +import com.google.checkstyle.test.base.AbstractIndentationTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class IndentationTest extends BaseIndentationCheckSupport { +public class IndentationTest extends AbstractIndentationTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule4841indentation" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule4841indentation"; } @Test - public void correctClassTest() throws Exception { - - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; + public void testCorrectClass() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final Configuration checkConfig = getCheckConfig("Indentation"); + final Configuration checkConfig = getModuleConfig("Indentation"); final String filePath = getPath("InputIndentationCorrectClass.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -49,11 +44,10 @@ } @Test - public void correctFieldTest() throws Exception { - - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; + public void testCorrectField() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final Configuration checkConfig = getCheckConfig("Indentation"); + final Configuration checkConfig = getModuleConfig("Indentation"); final String filePath = getPath("InputIndentationCorrectFieldAndParameter.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -61,11 +55,10 @@ } @Test - public void correctForTest() throws Exception { + public void testCorrectFor() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; - - final Configuration checkConfig = getCheckConfig("Indentation"); + final Configuration checkConfig = getModuleConfig("Indentation"); final String filePath = getPath("InputIndentationCorrectForAndParameter.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -73,11 +66,10 @@ } @Test - public void correctIfTest() throws Exception { - - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; + public void testCorrectIf() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final Configuration checkConfig = getCheckConfig("Indentation"); + final Configuration checkConfig = getModuleConfig("Indentation"); final String filePath = getPath("InputIndentationCorrectIfAndParameter.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -85,11 +77,10 @@ } @Test - public void correctTest() throws Exception { + public void testCorrect() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; - - final Configuration checkConfig = getCheckConfig("Indentation"); + final Configuration checkConfig = getModuleConfig("Indentation"); final String filePath = getPath("InputIndentationCorrect.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -97,11 +88,10 @@ } @Test - public void correctReturnTest() throws Exception { - - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; + public void testCorrectReturn() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final Configuration checkConfig = getCheckConfig("Indentation"); + final Configuration checkConfig = getModuleConfig("Indentation"); final String filePath = getPath("InputIndentationCorrectReturnAndParameter.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -109,14 +99,14 @@ } @Test - public void correctWhileTest() throws Exception { + public void testCorrectWhile() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; - - final Configuration checkConfig = getCheckConfig("Indentation"); + final Configuration checkConfig = getModuleConfig("Indentation"); final String filePath = getPath("InputIndentationCorrectWhileDoWhileAndParameter.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4842fallthrough/FallThroughTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4842fallthrough/FallThroughTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4842fallthrough/FallThroughTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4842fallthrough/FallThroughTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter4formatting.rule4842fallthrough; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.coding.FallThroughCheck; -public class FallThroughTest extends BaseCheckTestSupport { +public class FallThroughTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule4842fallthrough" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule4842fallthrough"; } @Test - public void fallThroughTest() throws Exception { - + public void testFallThrough() throws Exception { final String msg = getCheckMessage(FallThroughCheck.class, "fall.through"); final String[] expected = { @@ -55,10 +50,11 @@ "374:41: " + msg, }; - final Configuration checkConfig = getCheckConfig("FallThrough"); + final Configuration checkConfig = getModuleConfig("FallThrough"); final String filePath = getPath("InputFallThrough.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4843defaultcasepresent/MissingSwitchDefaultTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4843defaultcasepresent/MissingSwitchDefaultTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4843defaultcasepresent/MissingSwitchDefaultTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4843defaultcasepresent/MissingSwitchDefaultTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter4formatting.rule4843defaultcasepresent; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.coding.MissingSwitchDefaultCheck; -public class MissingSwitchDefaultTest extends BaseCheckTestSupport { +public class MissingSwitchDefaultTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule4843defaultcasepresent" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule4843defaultcasepresent"; } @Test - public void missingSwitchDefaultTest() throws Exception { - + public void testMissingSwitchDefault() throws Exception { final String msg = getCheckMessage(MissingSwitchDefaultCheck.class, "missing.switch.default"); @@ -51,10 +46,11 @@ "42: " + msg, }; - final Configuration checkConfig = getCheckConfig("MissingSwitchDefault"); + final Configuration checkConfig = getModuleConfig("MissingSwitchDefault"); final String filePath = getPath("InputMissingSwitchDefault.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule485annotations/AnnotationLocationTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule485annotations/AnnotationLocationTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule485annotations/AnnotationLocationTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule485annotations/AnnotationLocationTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,29 +19,25 @@ package com.google.checkstyle.test.chapter4formatting.rule485annotations; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationLocationCheck; -public class AnnotationLocationTest extends BaseCheckTestSupport { +public class AnnotationLocationTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule485annotations" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule485annotations"; } @Test - public void annotationTest() throws Exception { - + public void testAnnotation() throws Exception { final Class clazz = AnnotationLocationCheck.class; getCheckMessage(clazz, "annotation.location.alone"); - final Configuration checkConfig = getCheckConfig("AnnotationLocation"); + final Configuration checkConfig = getModuleConfig("AnnotationLocation", + "AnnotationLocationMostCases"); final String msgLocationAlone = "annotation.location.alone"; final String msgLocation = "annotation.location"; @@ -64,4 +60,23 @@ final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + + @Test + public void testAnnotationVariables() throws Exception { + final Class clazz = AnnotationLocationCheck.class; + getCheckMessage(clazz, "annotation.location.alone"); + final Configuration checkConfig = getModuleConfig("AnnotationLocation", + "AnnotationLocationVariables"); + + final String msgLocation = "annotation.location"; + final String[] expected = { + "63: " + getCheckMessage(clazz, msgLocation, "MyAnnotation2", "7", "4"), + }; + + final String filePath = getPath("InputAnnotationLocationVariables.java"); + + final Integer[] warnList = getLinesWithWarn(filePath); + verify(checkConfig, filePath, expected, warnList); + } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4861blockcommentstyle/CommentsIndentationTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4861blockcommentstyle/CommentsIndentationTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4861blockcommentstyle/CommentsIndentationTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule4861blockcommentstyle/CommentsIndentationTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,21 +19,17 @@ package com.google.checkstyle.test.chapter4formatting.rule4861blockcommentstyle; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.indentation.CommentsIndentationCheck; -public class CommentsIndentationTest extends BaseCheckTestSupport { +public class CommentsIndentationTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule4861blockcommentstyle" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule4861blockcommentstyle"; } @Test @@ -48,7 +44,7 @@ "47: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", 46, 15, 12), "49: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", - 48, 10, 8), + 45, 10, 8), "54: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", 53, 13, 8), "74: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", @@ -90,12 +86,12 @@ "322: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", 323, 0, 4), "336: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", - 337, 0, 4), + 333, 0, 8), "355: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", 352, 9, 8), }; - final Configuration checkConfig = getCheckConfig("CommentsIndentation"); + final Configuration checkConfig = getModuleConfig("CommentsIndentation"); final String filePath = getPath("InputCommentsIndentationCommentIsAtTheEndOfBlock.java"); @@ -106,6 +102,8 @@ @Test public void testCommentIsInsideSwitchBlock() throws Exception { final String[] expected = { + "19: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.block", + 20, 12, 16), "25: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", "24, 26", 19, "16, 12"), "31: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", @@ -131,16 +129,16 @@ "200: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", "199, 201", 4, "12, 12"), "203: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", - 204, 22, 20), + "202, 206", 22, "16, 12"), "204: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", - 205, 20, 17), + "202, 206", 20, "16, 12"), "205: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", "202, 206", 17, "16, 12"), "229: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", "228, 230", 6, "12, 12"), }; - final Configuration checkConfig = getCheckConfig("CommentsIndentation"); + final Configuration checkConfig = getModuleConfig("CommentsIndentation"); final String filePath = getPath("InputCommentsIndentationInSwitchBlock.java"); @@ -152,7 +150,7 @@ public void testCommentIsInsideEmptyBlock() throws Exception { final String[] expected = { "9: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", - 10, 19, 23), + 12, 19, 31), "10: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.block", 12, 23, 31), "33: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", @@ -163,7 +161,7 @@ 72, 0, 8), }; - final Configuration checkConfig = getCheckConfig("CommentsIndentation"); + final Configuration checkConfig = getModuleConfig("CommentsIndentation"); final String filePath = getPath("InputCommentsIndentationInEmptyBlock.java"); @@ -183,22 +181,23 @@ "28: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.block", 31, 16, 12), "50: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", - 51, 27, 23), + 53, 27, 36), "51: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.block", 53, 23, 36), "90: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", 91, 14, 8), "98: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", - 99, 13, 8), + 100, 13, 8), "108: " + getCheckMessage(CommentsIndentationCheck.class, "comments.indentation.single", 109, 33, 8), }; - final Configuration checkConfig = getCheckConfig("CommentsIndentation"); + final Configuration checkConfig = getModuleConfig("CommentsIndentation"); final String filePath = getPath("InputCommentsIndentationSurroundingCode.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule487modifiers/ModifierOrderTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule487modifiers/ModifierOrderTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule487modifiers/ModifierOrderTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule487modifiers/ModifierOrderTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter4formatting.rule487modifiers; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.modifier.ModifierOrderCheck; -public class ModifierOrderTest extends BaseCheckTestSupport { +public class ModifierOrderTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule487modifiers" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule487modifiers"; } @Test - public void modifierOrderTest() throws Exception { - + public void testModifierOrder() throws Exception { final Class clazz = ModifierOrderCheck.class; final String msgMod = "mod.order"; final String msgAnnotation = "annotation.order"; @@ -97,12 +92,14 @@ "215:28: " + getCheckMessage(clazz, msgMod, "synchronized"), "217:37: " + getCheckMessage(clazz, msgMod, "protected"), "219:22: " + getCheckMessage(clazz, msgAnnotation, "@MyAnnotation2"), + "245:14: " + getCheckMessage(clazz, msgMod, "default"), }; - final Configuration checkConfig = getCheckConfig("ModifierOrder"); + final Configuration checkConfig = getModuleConfig("ModifierOrder"); final String filePath = getPath("InputModifierOrder.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule488numericliterals/UpperEllTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule488numericliterals/UpperEllTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter4formatting/rule488numericliterals/UpperEllTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter4formatting/rule488numericliterals/UpperEllTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,25 +19,20 @@ package com.google.checkstyle.test.chapter4formatting.rule488numericliterals; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class UpperEllTest extends BaseCheckTestSupport { +public class UpperEllTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter4formatting" + File.separator + "rule488numericliterals" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter4formatting/rule488numericliterals"; } @Test - public void upperEllTest() throws Exception { - + public void testUpperEll() throws Exception { final String[] expected = { "6:36: Should use uppercase 'L'.", "12:27: Should use uppercase 'L'.", @@ -65,10 +60,11 @@ "100:22: Should use uppercase 'L'.", }; - final Configuration checkConfig = getCheckConfig("UpperEll"); + final Configuration checkConfig = getModuleConfig("UpperEll"); final String filePath = getPath("InputUpperEll.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule51identifiernames/CatchParameterNameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule51identifiernames/CatchParameterNameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule51identifiernames/CatchParameterNameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule51identifiernames/CatchParameterNameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,32 +19,31 @@ package com.google.checkstyle.test.chapter5naming.rule51identifiernames; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class CatchParameterNameTest extends BaseCheckTestSupport { +public class CatchParameterNameTest extends AbstractModuleTestSupport { + @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter5naming" + File.separator + "rule51identifiernames" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter5naming/rule51identifiernames"; } @Test - public void catchParameterNameTest() throws Exception { - final Configuration checkConfig = getCheckConfig("CatchParameterName"); + public void testCatchParameterName() throws Exception { final String msgKey = "name.invalidPattern"; - final String format = "^[a-z][a-z0-9][a-zA-Z0-9]*$"; + final Configuration checkConfig = getModuleConfig("CatchParameterName"); + final String format = checkConfig.getAttribute("format"); final String[] expected = { - "6:28: " + getCheckMessage(checkConfig.getMessages(), msgKey, "e", format), - "24:28: " + getCheckMessage(checkConfig.getMessages(), msgKey, "t", format), "47:28: " + getCheckMessage(checkConfig.getMessages(), msgKey, "iException", format), - "50:28: " + getCheckMessage(checkConfig.getMessages(), msgKey, "x", format), + "50:28: " + getCheckMessage(checkConfig.getMessages(), msgKey, "ex_1", format), + "53:28: " + getCheckMessage(checkConfig.getMessages(), msgKey, "eX", format), + "56:28: " + getCheckMessage(checkConfig.getMessages(), msgKey, "eXX", format), + "59:28: " + getCheckMessage(checkConfig.getMessages(), msgKey, "x_y_z", format), + "62:28: " + getCheckMessage(checkConfig.getMessages(), msgKey, "Ex", format), }; final String filePath = getPath("InputCatchParameterName.java"); @@ -52,4 +51,5 @@ final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule521packagenames/PackageNameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule521packagenames/PackageNameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule521packagenames/PackageNameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule521packagenames/PackageNameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,35 +22,29 @@ import java.io.File; import java.io.IOException; -import org.apache.commons.lang3.ArrayUtils; -import org.junit.BeforeClass; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; -import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class PackageNameTest extends BaseCheckTestSupport { +public class PackageNameTest extends AbstractModuleTestSupport { private static final String MSG_KEY = "name.invalidPattern"; - private static Configuration checkConfig; - private static String format; - protected String getPath(String packageName, String fileName) throws IOException { - return getPath("chapter5naming" + File.separator + "rule521" + packageName - + File.separator + fileName); + @Override + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter5naming"; } - @BeforeClass - public static void setConfigurationBuilder() throws CheckstyleException { - checkConfig = getCheckConfig("PackageName"); - format = checkConfig.getAttribute("format"); + private String getPath(String packageName, String fileName) throws IOException { + return getPath("rule521" + packageName + File.separator + fileName); } @Test - public void goodPackageNameTest() throws Exception { - - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; + public void testGoodPackageName() throws Exception { + final Configuration checkConfig = getModuleConfig("PackageName"); + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; final String filePath = getPath("packagenames", "InputPackageNameGood.java"); @@ -59,10 +53,11 @@ } @Test - public void badPackageNameTest() throws Exception { - + public void testBadPackageName() throws Exception { final String packagePath = "com.google.checkstyle.test.chapter5naming.rule521packageNamesCamelCase"; + final Configuration checkConfig = getModuleConfig("PackageName"); + final String format = checkConfig.getAttribute("format"); final String msg = getCheckMessage(checkConfig.getMessages(), MSG_KEY, packagePath, format); final String[] expected = { @@ -76,9 +71,10 @@ } @Test - public void badPackageName2Test() throws Exception { - + public void testBadPackageName2() throws Exception { final String packagePath = "com.google.checkstyle.test.chapter5naming.rule521_packagenames"; + final Configuration checkConfig = getModuleConfig("PackageName"); + final String format = checkConfig.getAttribute("format"); final String msg = getCheckMessage(checkConfig.getMessages(), MSG_KEY, packagePath, format); final String[] expected = { @@ -92,9 +88,10 @@ } @Test - public void badPackageName3Test() throws Exception { - + public void testBadPackageName3() throws Exception { final String packagePath = "com.google.checkstyle.test.chapter5naming.rule521$packagenames"; + final Configuration checkConfig = getModuleConfig("PackageName"); + final String format = checkConfig.getAttribute("format"); final String msg = getCheckMessage(checkConfig.getMessages(), MSG_KEY, packagePath, format); final String[] expected = { @@ -106,4 +103,5 @@ final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule522typenames/TypeNameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule522typenames/TypeNameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule522typenames/TypeNameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule522typenames/TypeNameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter5naming.rule522typenames; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class TypeNameTest extends BaseCheckTestSupport { +public class TypeNameTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter5naming" + File.separator + "rule522typenames" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter5naming/rule522typenames"; } @Test - public void typeNameTest() throws Exception { - - final Configuration checkConfig = getCheckConfig("TypeName"); + public void testTypeName() throws Exception { + final Configuration checkConfig = getModuleConfig("TypeName"); final String msgKey = "name.invalidPattern"; final String format = "^[A-Z][a-zA-Z0-9]*$"; @@ -86,4 +81,5 @@ final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule523methodnames/MethodNameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule523methodnames/MethodNameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule523methodnames/MethodNameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule523methodnames/MethodNameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,26 +19,21 @@ package com.google.checkstyle.test.chapter5naming.rule523methodnames; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class MethodNameTest extends BaseCheckTestSupport { +public class MethodNameTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter5naming" + File.separator + "rule523methodnames" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter5naming/rule523methodnames"; } @Test - public void methodNameTest() throws Exception { - - final Configuration checkConfig = getCheckConfig("MethodName"); + public void testMethodName() throws Exception { + final Configuration checkConfig = getModuleConfig("MethodName"); final String msgKey = "name.invalidPattern"; final String format = "^[a-z][a-z0-9][a-zA-Z0-9_]*$"; @@ -74,4 +69,5 @@ final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule525nonconstantfieldnames/MemberNameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule525nonconstantfieldnames/MemberNameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule525nonconstantfieldnames/MemberNameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule525nonconstantfieldnames/MemberNameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,37 +19,24 @@ package com.google.checkstyle.test.chapter5naming.rule525nonconstantfieldnames; -import java.io.File; -import java.io.IOException; - -import org.junit.BeforeClass; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; -import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class MemberNameTest extends BaseCheckTestSupport { +public class MemberNameTest extends AbstractModuleTestSupport { private static final String MSG_KEY = "name.invalidPattern"; - private static Configuration checkConfig; - private static String format; @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter5naming" + File.separator + "rule525nonconstantfieldnames" - + File.separator + fileName); - } - - @BeforeClass - public static void setConfigurationBuilder() throws CheckstyleException { - checkConfig = getCheckConfig("MemberName"); - format = checkConfig.getAttribute("format"); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter5naming/rule525nonconstantfieldnames"; } @Test - public void memberNameTest() throws Exception { - + public void testMemberName() throws Exception { + final Configuration checkConfig = getModuleConfig("MemberName"); + final String format = checkConfig.getAttribute("format"); final String[] expected = { "5:16: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "mPublic", format), "6:19: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "mProtected", format), @@ -73,8 +60,9 @@ } @Test - public void simpleTest() throws Exception { - + public void testSimple() throws Exception { + final Configuration checkConfig = getModuleConfig("MemberName"); + final String format = checkConfig.getAttribute("format"); final String[] expected = { "12:17: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "bad$Static", format), "17:17: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "bad_Member", format), @@ -115,4 +103,5 @@ final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule526parameternames/ParameterNameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule526parameternames/ParameterNameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule526parameternames/ParameterNameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule526parameternames/ParameterNameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,55 +19,43 @@ package com.google.checkstyle.test.chapter5naming.rule526parameternames; -import java.io.File; -import java.io.IOException; - -import org.junit.BeforeClass; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; -import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class ParameterNameTest extends BaseCheckTestSupport { +public class ParameterNameTest extends AbstractModuleTestSupport { private static final String MSG_KEY = "name.invalidPattern"; - private static String format; - private static Configuration checkConfig; @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter5naming" + File.separator + "rule526parameternames" - + File.separator + fileName); - } - - @BeforeClass - public static void setConfigurationBuilder() throws CheckstyleException { - checkConfig = getCheckConfig("ParameterName"); - format = checkConfig.getAttribute("format"); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter5naming/rule526parameternames"; } @Test - public void parameterNameTest() throws Exception { - + public void testGeneralParameterName() throws Exception { + final Configuration config = getModuleConfig("ParameterName"); + final String format = config.getAttribute("format"); final String[] expected = { - "8:21: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "$arg1", format), - "9:21: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "ar$g2", format), - "10:21: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "arg3$", format), - "11:21: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "a_rg4", format), - "12:21: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "_arg5", format), - "13:21: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "arg6_", format), - "14:21: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "aArg7", format), - "15:21: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "aArg8", format), - "16:21: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "aar_g", format), - "26:21: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "bB", format), - "49:22: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "llll_llll", format), - "50:21: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "bB", format), + "10:21: " + getCheckMessage(config.getMessages(), MSG_KEY, "bB", format), + "33:22: " + getCheckMessage(config.getMessages(), MSG_KEY, "llll_llll", format), + "34:21: " + getCheckMessage(config.getMessages(), MSG_KEY, "bB", format), + "64:13: " + getCheckMessage(config.getMessages(), MSG_KEY, "$arg1", format), + "65:13: " + getCheckMessage(config.getMessages(), MSG_KEY, "ar$g2", format), + "66:13: " + getCheckMessage(config.getMessages(), MSG_KEY, "arg3$", format), + "67:13: " + getCheckMessage(config.getMessages(), MSG_KEY, "a_rg4", format), + "68:13: " + getCheckMessage(config.getMessages(), MSG_KEY, "_arg5", format), + "69:13: " + getCheckMessage(config.getMessages(), MSG_KEY, "arg6_", format), + "70:13: " + getCheckMessage(config.getMessages(), MSG_KEY, "aArg7", format), + "71:13: " + getCheckMessage(config.getMessages(), MSG_KEY, "aArg8", format), + "72:13: " + getCheckMessage(config.getMessages(), MSG_KEY, "aar_g", format), }; - final String filePath = getPath("InputParameterNameSimple.java"); + final String filePath = getPath("InputParameterName.java"); final Integer[] warnList = getLinesWithWarn(filePath); - verify(checkConfig, filePath, expected, warnList); + verify(config, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/LocalVariableNameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/LocalVariableNameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/LocalVariableNameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/LocalVariableNameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,39 +19,25 @@ package com.google.checkstyle.test.chapter5naming.rule527localvariablenames; -import java.io.File; -import java.io.IOException; - -import org.junit.BeforeClass; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; -import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class LocalVariableNameTest extends BaseCheckTestSupport { +public class LocalVariableNameTest extends AbstractModuleTestSupport { private static final String MSG_KEY = "name.invalidPattern"; - private static Configuration checkConfig; - private static String format; @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter5naming" + File.separator + "rule527localvariablenames" - + File.separator + fileName); - } - - @BeforeClass - public static void setConfigurationBuilder() throws CheckstyleException { - checkConfig = getCheckConfig("LocalVariableName"); - format = checkConfig.getAttribute("format"); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter5naming/rule527localvariablenames"; } @Test - public void localVariableNameTest() throws Exception { - + public void testLocalVariableName() throws Exception { + final Configuration checkConfig = getModuleConfig("LocalVariableName"); + final String format = checkConfig.getAttribute("format"); final String[] expected = { - "26:13: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "a", format), "27:13: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "aA", format), "28:13: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "a1_a", format), "29:13: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "A_A", format), @@ -71,10 +57,10 @@ } @Test - public void oneCharTest() throws Exception { - + public void testOneChar() throws Exception { + final Configuration checkConfig = getModuleConfig("LocalVariableName"); + final String format = checkConfig.getAttribute("format"); final String[] expected = { - "15:13: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "i", format), "21:17: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "I_ndex", format), "45:17: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "i_ndex", format), "49:17: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "ii_i1", format), @@ -88,4 +74,5 @@ final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/ClassTypeParameterNameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/ClassTypeParameterNameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/ClassTypeParameterNameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/ClassTypeParameterNameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,27 +19,23 @@ package com.google.checkstyle.test.chapter5naming.rule528typevariablenames; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class ClassTypeParameterNameTest extends BaseCheckTestSupport { +public class ClassTypeParameterNameTest extends AbstractModuleTestSupport { private static final String MSG_KEY = "name.invalidPattern"; @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter5naming" + File.separator + "rule528typevariablenames" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter5naming/rule528typevariablenames"; } @Test public void testClassDefault() throws Exception { - final Configuration configuration = getCheckConfig("ClassTypeParameterName"); + final Configuration configuration = getModuleConfig("ClassTypeParameterName"); final String format = configuration.getAttribute("format"); final String[] expected = { @@ -53,4 +49,5 @@ final Integer[] warnList = getLinesWithWarn(filePath); verify(configuration, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/InterfaceTypeParameterNameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/InterfaceTypeParameterNameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/InterfaceTypeParameterNameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/InterfaceTypeParameterNameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,27 +19,23 @@ package com.google.checkstyle.test.chapter5naming.rule528typevariablenames; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class InterfaceTypeParameterNameTest extends BaseCheckTestSupport { +public class InterfaceTypeParameterNameTest extends AbstractModuleTestSupport { private static final String MSG_KEY = "name.invalidPattern"; @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter5naming" + File.separator + "rule528typevariablenames" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter5naming/rule528typevariablenames"; } @Test public void testInterfaceDefault() throws Exception { - final Configuration configuration = getCheckConfig("InterfaceTypeParameterName"); + final Configuration configuration = getModuleConfig("InterfaceTypeParameterName"); final String format = configuration.getAttribute("format"); final String[] expected = { diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/MethodTypeParameterNameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/MethodTypeParameterNameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/MethodTypeParameterNameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule528typevariablenames/MethodTypeParameterNameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,38 +19,31 @@ package com.google.checkstyle.test.chapter5naming.rule528typevariablenames; -import java.io.File; -import java.io.IOException; - import org.junit.BeforeClass; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Configuration; -public class MethodTypeParameterNameTest extends BaseCheckTestSupport { +public class MethodTypeParameterNameTest extends AbstractModuleTestSupport { private static final String MSG_KEY = "name.invalidPattern"; - private static Configuration configuration; private static String format; @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter5naming" + File.separator + "rule528typevariablenames" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter5naming/rule528typevariablenames"; } @BeforeClass public static void setConfigurationBuilder() throws CheckstyleException { - configuration = getCheckConfig("ClassTypeParameterName"); - format = configuration.getAttribute("format"); + format = getModuleConfig("ClassTypeParameterName").getAttribute("format"); } @Test public void testMethodDefault() throws Exception { - - final Configuration checkConfig = getCheckConfig("MethodTypeParameterName"); + final Configuration checkConfig = getModuleConfig("MethodTypeParameterName"); final String[] expected = { "9:6: " + getCheckMessage(checkConfig.getMessages(), MSG_KEY, "e_e", format), @@ -66,4 +59,5 @@ final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule53camelcase/AbbreviationAsWordInNameTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule53camelcase/AbbreviationAsWordInNameTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter5naming/rule53camelcase/AbbreviationAsWordInNameTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter5naming/rule53camelcase/AbbreviationAsWordInNameTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,30 +19,27 @@ package com.google.checkstyle.test.chapter5naming.rule53camelcase; -import java.io.File; import java.io.IOException; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.naming.AbbreviationAsWordInNameCheck; -public class AbbreviationAsWordInNameTest extends BaseCheckTestSupport { +public class AbbreviationAsWordInNameTest extends AbstractModuleTestSupport { private static final String MSG_KEY = "abbreviation.as.word"; private final Class clazz = AbbreviationAsWordInNameCheck.class; @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter5naming" + File.separator + "rule53camelcase" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter5naming/rule53camelcase"; } @Test - public void abbreviationAsWordInNameTest() throws Exception { - - final int maxCapitalCount = 1; + public void testAbbreviationAsWordInName() throws Exception { + final int maxCapitalCount = 2; final String[] expected = { "50: " + getWarningMessage("newCustomerID", maxCapitalCount), @@ -58,12 +55,14 @@ final String filePath = getPath("InputAbbreviationAsWordInTypeNameCheck.java"); - final Configuration checkConfig = getCheckConfig("AbbreviationAsWordInName"); + final Configuration checkConfig = getModuleConfig("AbbreviationAsWordInName"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } - private String getWarningMessage(String typeName, int expectedCapitalCount) { + private String getWarningMessage(String typeName, int expectedCapitalCount) + throws IOException { return getCheckMessage(clazz, MSG_KEY, typeName, expectedCapitalCount); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter6programpractice/rule62donotignoreexceptions/EmptyBlockTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter6programpractice/rule62donotignoreexceptions/EmptyBlockTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter6programpractice/rule62donotignoreexceptions/EmptyBlockTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter6programpractice/rule62donotignoreexceptions/EmptyBlockTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,36 +19,32 @@ package com.google.checkstyle.test.chapter6programpractice.rule62donotignoreexceptions; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.blocks.EmptyBlockCheck; -public class EmptyBlockTest extends BaseCheckTestSupport { +public class EmptyBlockTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter6programpractice" + File.separator - + "rule62donotignoreexceptions" + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter6programpractice/rule62donotignoreexceptions"; } @Test - public void emptyBlockTestCatch() throws Exception { - + public void testEmptyBlockCatch() throws Exception { final String[] expected = { "29:17: " + getCheckMessage(EmptyBlockCheck.class, "block.empty", "finally"), "50:21: " + getCheckMessage(EmptyBlockCheck.class, "block.empty", "finally"), "72:21: " + getCheckMessage(EmptyBlockCheck.class, "block.empty", "finally"), }; - final Configuration checkConfig = getCheckConfig("EmptyBlock"); + final Configuration checkConfig = getModuleConfig("EmptyBlock"); final String filePath = getPath("InputEmptyBlockCatch.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter6programpractice/rule64finalizers/NoFinalizerTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter6programpractice/rule64finalizers/NoFinalizerTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter6programpractice/rule64finalizers/NoFinalizerTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter6programpractice/rule64finalizers/NoFinalizerTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,33 +19,28 @@ package com.google.checkstyle.test.chapter6programpractice.rule64finalizers; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.coding.NoFinalizerCheck; -public class NoFinalizerTest extends BaseCheckTestSupport { +public class NoFinalizerTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter6programpractice" + File.separator + "rule64finalizers" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter6programpractice/rule64finalizers"; } @Test - public void noFinalizerBasicTest() throws Exception { - + public void testNoFinalizerBasic() throws Exception { final String msg = getCheckMessage(NoFinalizerCheck.class, "avoid.finalizer.method"); final String[] expected = { "5: " + msg, }; - final Configuration checkConfig = getCheckConfig("NoFinalizer"); + final Configuration checkConfig = getModuleConfig("NoFinalizer"); final String filePath = getPath("InputNoFinalizer.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -53,8 +48,7 @@ } @Test - public void noFinalizerExtendedTest() throws Exception { - + public void testNoFinalizerExtended() throws Exception { final String msg = getCheckMessage(NoFinalizerCheck.class, "avoid.finalizer.method"); final String[] expected = { @@ -69,10 +63,11 @@ "136: " + msg, }; - final Configuration checkConfig = getCheckConfig("NoFinalizer"); + final Configuration checkConfig = getModuleConfig("NoFinalizer"); final String filePath = getPath("InputNoFinalizeExtend.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule711generalform/SingleLineJavadocTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule711generalform/SingleLineJavadocTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule711generalform/SingleLineJavadocTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule711generalform/SingleLineJavadocTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,27 +19,21 @@ package com.google.checkstyle.test.chapter7javadoc.rule711generalform; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; -import com.puppycrawl.tools.checkstyle.DefaultConfiguration; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.javadoc.SingleLineJavadocCheck; -public class SingleLineJavadocTest extends BaseCheckTestSupport { +public class SingleLineJavadocTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter7javadoc" + File.separator + "rule711generalform" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter7javadoc/rule711generalform"; } @Test - public void singleLineJavadocTest() throws Exception { - + public void testSingleLineJavadoc() throws Exception { final String msg = getCheckMessage(SingleLineJavadocCheck.class, "singleline.javadoc"); final String[] expected = { @@ -52,26 +46,11 @@ "41: " + msg, }; - final DefaultConfiguration checkConfig = createCheckConfig(SingleLineJavadocCheck.class); - checkConfig.addAttribute("ignoreInlineTags", "false"); + final Configuration checkConfig = getModuleConfig("SingleLineJavadoc"); final String filePath = getPath("InputSingleLineJavadocCheck.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } - @Test(expected = Exception.class) - public void customInlineTagTest() throws Exception { - final String msg = getCheckMessage(SingleLineJavadocCheck.class, "singleline.javadoc"); - - final Configuration checkConfig = getCheckConfig("SingleLineJavadocCheck"); - final String filePath = getPath("InputSingleLineJavadocCheckError.java"); - - final String[] expected = { - "4: " + msg, - }; - - final Integer[] warnList = getLinesWithWarn(filePath); - verify(checkConfig, filePath, expected, warnList); - } } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule712paragraphs/JavadocParagraphTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule712paragraphs/JavadocParagraphTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule712paragraphs/JavadocParagraphTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule712paragraphs/JavadocParagraphTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,30 +19,25 @@ package com.google.checkstyle.test.chapter7javadoc.rule712paragraphs; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocParagraphCheck; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class JavadocParagraphTest extends BaseCheckTestSupport { +public class JavadocParagraphTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter7javadoc" + File.separator + "rule712paragraphs" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter7javadoc/rule712paragraphs"; } @Test - public void javadocParagraphCorrectTest() throws Exception { - - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; + public void testJavadocParagraphCorrect() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final Configuration checkConfig = getCheckConfig("JavadocParagraph"); + final Configuration checkConfig = getModuleConfig("JavadocParagraph"); final String filePath = getPath("InputCorrectJavadocParagraphCheck.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -50,8 +45,7 @@ } @Test - public void javadocParagraphIncorrectTest() throws Exception { - + public void testJavadocParagraphIncorrect() throws Exception { final String msgBefore = getCheckMessage(JavadocParagraphCheck.class, "javadoc.paragraph.line.before"); final String msgRed = getCheckMessage(JavadocParagraphCheck.class, @@ -92,10 +86,11 @@ "73: " + msgBefore, }; - final Configuration checkConfig = getCheckConfig("JavadocParagraph"); + final Configuration checkConfig = getModuleConfig("JavadocParagraph"); final String filePath = getPath("InputIncorrectJavadocParagraphCheck.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/AtclauseOrderTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/AtclauseOrderTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/AtclauseOrderTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/AtclauseOrderTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,30 +19,25 @@ package com.google.checkstyle.test.chapter7javadoc.rule713atclauses; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.javadoc.AtclauseOrderCheck; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class AtclauseOrderTest extends BaseCheckTestSupport { +public class AtclauseOrderTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter7javadoc" + File.separator + "rule713atclauses" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter7javadoc/rule713atclauses"; } @Test public void testCorrect() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; - - final Configuration checkConfig = getCheckConfig("AtclauseOrder"); + final Configuration checkConfig = getModuleConfig("AtclauseOrder"); final String filePath = getPath("InputCorrectAtClauseOrderCheck.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -84,10 +79,11 @@ "261: " + msg, }; - final Configuration checkConfig = getCheckConfig("AtclauseOrder"); + final Configuration checkConfig = getModuleConfig("AtclauseOrder"); final String filePath = getPath("InputIncorrectAtClauseOrderCheck.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/JavadocTagContinuationIndentationTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/JavadocTagContinuationIndentationTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/JavadocTagContinuationIndentationTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/JavadocTagContinuationIndentationTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,21 +19,17 @@ package com.google.checkstyle.test.chapter7javadoc.rule713atclauses; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocTagContinuationIndentationCheck; -public class JavadocTagContinuationIndentationTest extends BaseCheckTestSupport { +public class JavadocTagContinuationIndentationTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter7javadoc" + File.separator + "rule713atclauses" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter7javadoc/rule713atclauses"; } @Test @@ -56,10 +52,11 @@ "322: " + msg, }; - final Configuration checkConfig = getCheckConfig("JavadocTagContinuationIndentation"); + final Configuration checkConfig = getModuleConfig("JavadocTagContinuationIndentation"); final String filePath = getPath("InputJavaDocTagContinuationIndentation.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/NonEmptyAtclauseDescriptionTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/NonEmptyAtclauseDescriptionTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/NonEmptyAtclauseDescriptionTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/NonEmptyAtclauseDescriptionTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,21 +19,17 @@ package com.google.checkstyle.test.chapter7javadoc.rule713atclauses; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.javadoc.NonEmptyAtclauseDescriptionCheck; -public class NonEmptyAtclauseDescriptionTest extends BaseCheckTestSupport { +public class NonEmptyAtclauseDescriptionTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter7javadoc" + File.separator + "rule713atclauses" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter7javadoc/rule713atclauses"; } @Test @@ -55,7 +51,7 @@ "52: " + msg, }; - final Configuration checkConfig = getCheckConfig("NonEmptyAtclauseDescription"); + final Configuration checkConfig = getModuleConfig("NonEmptyAtclauseDescription"); final String filePath = getPath("InputNonEmptyAtclauseDescriptionCheck.java"); final Integer[] warnList = getLineNumbersFromExpected(expected); @@ -76,7 +72,7 @@ "40: " + msg, }; - final Configuration checkConfig = getCheckConfig("NonEmptyAtclauseDescription"); + final Configuration checkConfig = getModuleConfig("NonEmptyAtclauseDescription"); final String filePath = getPath("InputNonEmptyAtclauseDescriptionCheckSpaceSeq.java"); final Integer[] warnList = getLineNumbersFromExpected(expected); @@ -90,11 +86,12 @@ * @param expected an array with expected messages. * @return Integer array with numbers of lines with violations. */ - private static Integer[] getLineNumbersFromExpected(String[] expected) { + private static Integer[] getLineNumbersFromExpected(String... expected) { final Integer[] result = new Integer[expected.length]; for (int i = 0; i < expected.length; i++) { result[i] = Integer.valueOf(expected[i].substring(0, expected[i].indexOf(':'))); } return result; } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/SummaryJavadocTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/SummaryJavadocTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/SummaryJavadocTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/SummaryJavadocTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,30 +19,25 @@ package com.google.checkstyle.test.chapter7javadoc.rule72thesummaryfragment; -import java.io.File; -import java.io.IOException; - -import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.javadoc.SummaryJavadocCheck; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -public class SummaryJavadocTest extends BaseCheckTestSupport { +public class SummaryJavadocTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter7javadoc" + File.separator + "rule72thesummaryfragment" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment"; } @Test public void testCorrect() throws Exception { + final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; - final String[] expected = ArrayUtils.EMPTY_STRING_ARRAY; - - final Configuration checkConfig = getCheckConfig("SummaryJavadoc"); + final Configuration checkConfig = getModuleConfig("SummaryJavadoc"); final String filePath = getPath("InputCorrectSummaryJavaDocCheck.java"); final Integer[] warnList = getLinesWithWarn(filePath); @@ -51,26 +46,30 @@ @Test public void testIncorrect() throws Exception { - final String msgFirstSentence = getCheckMessage(SummaryJavadocCheck.class, "summary.first.sentence"); final String msgForbiddenFragment = getCheckMessage(SummaryJavadocCheck.class, "summary.javaDoc"); + final String msgMissingDoc = getCheckMessage(SummaryJavadocCheck.class, + "summary.javaDoc.missing"); final String[] expected = { - "14: " + msgFirstSentence, + "14: " + msgMissingDoc, + "32: " + msgMissingDoc, "37: " + msgFirstSentence, "47: " + msgForbiddenFragment, - "58: " + msgForbiddenFragment, - "69: " + msgFirstSentence, + "53: " + msgMissingDoc, + "58: " + msgMissingDoc, + "69: " + msgMissingDoc, "83: " + msgForbiddenFragment, - "103: " + msgFirstSentence, + "103: " + msgMissingDoc, }; - final Configuration checkConfig = getCheckConfig("SummaryJavadoc"); + final Configuration checkConfig = getModuleConfig("SummaryJavadoc"); final String filePath = getPath("InputIncorrectSummaryJavaDocCheck.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule731selfexplanatory/JavadocMethodTest.java checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule731selfexplanatory/JavadocMethodTest.java --- checkstyle-6.15/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule731selfexplanatory/JavadocMethodTest.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/it/java/com/google/checkstyle/test/chapter7javadoc/rule731selfexplanatory/JavadocMethodTest.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,36 +19,32 @@ package com.google.checkstyle.test.chapter7javadoc.rule731selfexplanatory; -import java.io.File; -import java.io.IOException; - import org.junit.Test; -import com.google.checkstyle.test.base.BaseCheckTestSupport; +import com.google.checkstyle.test.base.AbstractModuleTestSupport; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocMethodCheck; -public class JavadocMethodTest extends BaseCheckTestSupport { +public class JavadocMethodTest extends AbstractModuleTestSupport { @Override - protected String getPath(String fileName) throws IOException { - return super.getPath("chapter7javadoc" + File.separator + "rule731selfexplanatory" - + File.separator + fileName); + protected String getPackageLocation() { + return "com/google/checkstyle/test/chapter7javadoc/rule731selfexplanatory"; } @Test - public void javadocMethodTest() throws Exception { - + public void testJavadocMethod() throws Exception { final String msg = getCheckMessage(JavadocMethodCheck.class, "javadoc.missing"); final String[] expected = { "57:5: " + msg, }; - final Configuration checkConfig = getCheckConfig("JavadocMethod"); + final Configuration checkConfig = getModuleConfig("JavadocMethod"); final String filePath = getPath("InputJavadocMethodCheck.java"); final Integer[] warnList = getLinesWithWarn(filePath); verify(checkConfig, filePath, expected, warnList); } + } diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter2filebasic/rule232specialescape/InputIllegalTokenText.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter2filebasic/rule232specialescape/InputIllegalTokenText.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter2filebasic/rule232specialescape/InputIllegalTokenText.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter2filebasic/rule232specialescape/InputIllegalTokenText.java 2017-10-29 12:46:46.000000000 +0000 @@ -14,7 +14,7 @@ public String wrongEscapeSequences() { - final String r1 = "\u0008"; //warn + final String r1 = "\u0008"; //ok final String r2 = "\u0009"; //warn final String r3 = "\u000csssdfsd"; //warn final String r4 = "\u1111sdfsd\444"; // ok @@ -39,7 +39,7 @@ public void specialCharsWithWarn() { - String r1 = "\\u0008"; // warn + String r1 = "\\u0008"; //ok String r2 = "\\u0009"; // warn String r3 = "\\u000a"; // warn String r4 = "\\u000c"; // warn @@ -65,7 +65,7 @@ { public String wrongEscapeSequences() { - final String r1 = "\u0008"; //warn + final String r1 = "\u0008"; //ok final String r2 = "\u0009"; //warn final String r3 = "\u000csssdfsd"; //warn final String r4 = "\u1111sdfsd\444"; //ok @@ -90,7 +90,7 @@ public void specialCharsWithWarn() { - String r1 = "\\u0008"; // warn + String r1 = "\\u0008"; //ok String r2 = "\\u0009"; // warn String r3 = "\\u000a"; // warn String r4 = "\\u000c"; // warn @@ -115,7 +115,7 @@ Inner anoInner = new Inner(){ public String wrongEscapeSequences() { - final String r1 = "\u0008"; //warn + final String r1 = "\u0008"; //ok final String r2 = "\u0009"; //warn final String r3 = "\u000csssdfsd"; //warn final String r4 = "\u1111sdfsd\444"; //ok @@ -140,7 +140,7 @@ public void specialCharsWithWarn() { - String r1 = "\\u0008"; // warn + String r1 = "\\u0008"; //ok String r2 = "\\u0009"; // warn String r3 = "\\u000a"; // warn String r4 = "\\u000c"; // warn diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter2filebasic/rule233nonascii/InputAvoidEscapedUnicodeCharacters.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter2filebasic/rule233nonascii/InputAvoidEscapedUnicodeCharacters.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter2filebasic/rule233nonascii/InputAvoidEscapedUnicodeCharacters.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter2filebasic/rule233nonascii/InputAvoidEscapedUnicodeCharacters.java 2017-10-29 12:46:46.000000000 +0000 @@ -17,7 +17,7 @@ String fakeUnicode = "asd\tsasd"; String fakeUnicode2 = "\\u23\\u123i\\u"; String content = ""; - return "\ufeff" + content ; // byte order mark ok + /*byte order mark ok*/return "\ufeff" + content ; } public Object fooChar() @@ -25,7 +25,7 @@ /*warn*/char unitAbbrev2 = '\u03bc'; char unitAbbrev3 = '\u03bc'; // Greek letter mu, "s" ok String content = ""; - return '\ufeff' + content; // byte order mark ok + /*byte order mark ok*/return '\ufeff' + content; } public void multiplyString() diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/InputNoLineWrapBad.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/InputNoLineWrapBad.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/InputNoLineWrapBad.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/InputNoLineWrapBad.java 2017-10-29 12:46:46.000000000 +0000 @@ -1,15 +1,18 @@ package com.google.checkstyle.test. //warn chapter3filestructure.rule332nolinewrap; -import com.google.common.annotations.Beta; //ok +import com.puppycrawl.tools.checkstyle.checks.design.FinalClassCheck; //ok import javax.accessibility. //warn AccessibleAttributeSequence; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; //ok +import static java.math. //warn + BigInteger.ONE; + public class InputNoLineWrapBad { - + public void fooMethod() { final int @@ -24,4 +27,3 @@ interface InterFoo {} - diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/InputNoLineWrapGood.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/InputNoLineWrapGood.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/InputNoLineWrapGood.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule332nolinewrap/InputNoLineWrapGood.java 2017-10-29 12:46:46.000000000 +0000 @@ -1,12 +1,14 @@ package com.google.checkstyle.test.chapter3filestructure.rule332nolinewrap; //ok -import com.google.common.annotations.Beta; //ok - +import static java.math.BigInteger.ZERO; //ok + +import com.puppycrawl.tools.checkstyle.checks.design.FinalClassCheck; //ok + import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; //ok import javax.accessibility.AccessibleAttributeSequence; //ok public class InputNoLineWrapGood { - + public void fooMethod() { // } diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder1.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder1.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder1.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder1.java 2017-10-29 12:46:46.000000000 +0000 @@ -3,20 +3,17 @@ import static java.io.File.createTempFile; import static java.awt.Button.ABORT; //warn import static javax.swing.WindowConstants.*; - import java.awt.Button; //warn -import java.awt.Frame; //warn +import java.awt.Frame; import java.awt.Dialog; //warn -import java.awt.event.ActionEvent; //warn -import javax.swing.JComponent; //warn -import javax.swing.JTable; //warn +import java.awt.event.ActionEvent; +import javax.swing.JComponent; +import javax.swing.JTable; import java.io.File; //warn import java.io.IOException; //warn import java.io.InputStream; //warn import java.io.Reader; //warn - - -import com.google.common.base.Ascii; +import com.google.common.base.Ascii; //warn public class InputCustomImportOrder1 {} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder2.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder2.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder2.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder2.java 2017-10-29 12:46:46.000000000 +0000 @@ -4,13 +4,13 @@ import static java.awt.Button.ABORT; //warn import static javax.swing.WindowConstants.*; -import java.util.List; //warn -import java.util.StringTokenizer; //warn +import java.util.List; +import java.util.StringTokenizer; import java.util.*; //warn -import java.util.concurrent.AbstractExecutorService; //warn +import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.*; //warn -import com.google.checkstyle.test.chapter2filebasic.rule21filename.*; +import com.google.checkstyle.test.chapter2filebasic.rule21filename.*; //warn import com.sun.xml.internal.xsom.impl.scd.Iterators; //warn import com.google.common.reflect.*; //warn diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder3.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder3.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder3.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrder3.java 2017-10-29 12:46:46.000000000 +0000 @@ -1,19 +1,18 @@ package com.google.checkstyle.test.chapter3filestructure.rule333orderingandspacing; -import static java.io.File.createTempFile; -import static java.awt.Button.ABORT; //warn -import static javax.swing.WindowConstants.*; +import static java.awt.Button.ABORT; +import java.awt.Dialog; //warn +import static javax.swing.WindowConstants.*; //warn - -import java.util.StringTokenizer; //warn +import com.google.checkstyle.test.chapter2filebasic.rule21filename.*; //warn +import com.google.common.reflect.*; //warn +import com.sun.xml.internal.xsom.impl.scd.Iterators; //warn +import java.io.File; +import static java.io.File.createTempFile; //warn +import java.util.StringTokenizer; import java.util.*; //warn -import java.util.concurrent.AbstractExecutorService; //warn +import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.*; //warn -import com.google.checkstyle.test.chapter2filebasic.rule21filename.*; -import com.sun.xml.internal.xsom.impl.scd.Iterators; //warn - -import com.google.common.reflect.*; //warn - public class InputCustomImportOrder3 { } diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrderNoImports.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrderNoImports.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrderNoImports.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrderNoImports.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,4 @@ +package com.google.checkstyle.test.chapter3filestructure.rule333orderingandspacing; + +public class InputCustomImportOrderNoImports { +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrderValid.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrderValid.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrderValid.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule333orderingandspacing/InputCustomImportOrderValid.java 2017-10-29 12:46:46.000000000 +0000 @@ -1,21 +1,19 @@ package com.google.checkstyle.test.chapter3filestructure.rule333orderingandspacing; -import static com.google.common.base.Preconditions.checkArgument; -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.annotations.Beta; -import com.google.common.annotations.GwtCompatible; -import com.google.common.annotations.GwtIncompatible; +import static com.puppycrawl.tools.checkstyle.utils.AnnotationUtility.containsAnnotation; +import static com.puppycrawl.tools.checkstyle.utils.AnnotationUtility.getAnnotation; +import com.puppycrawl.tools.checkstyle.checks.design.FinalClassCheck; +import com.puppycrawl.tools.checkstyle.checks.design.ThrowsCountCheck; +import com.puppycrawl.tools.checkstyle.checks.design.VisibilityModifierCheck; import com.sun.accessibility.internal.resources.*; -import org.apache.commons.beanutils.converters.ArrayConverter; - import java.util.Arrays; import java.util.BitSet; import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; import javax.accessibility.Accessible; +import org.apache.commons.beanutils.converters.ArrayConverter; public class InputCustomImportOrderValid { } diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule3sourcefile/InputEmptyLineSeparator.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule3sourcefile/InputEmptyLineSeparator.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule3sourcefile/InputEmptyLineSeparator.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter3filestructure/rule3sourcefile/InputEmptyLineSeparator.java 2017-10-29 12:46:46.000000000 +0000 @@ -24,8 +24,8 @@ import java.util.Map; import java.util.concurrent.Callable; import java.util.Collections; -import com.google.common.base.CharMatcher; -import com.google.common.io.CharSource; +import com.puppycrawl.tools.checkstyle.Checker; +import com.puppycrawl.tools.checkstyle.ConfigurationLoader; import javax.swing.AbstractAction; diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyDoWhileAlone.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyDoWhileAlone.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyDoWhileAlone.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyDoWhileAlone.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,93 @@ +package com.google.checkstyle.test.chapter4formatting.rule412nonemptyblocks; + +import java.util.Scanner; + +/** + * Test input for GitHub issue #3090. + * https://github.com/checkstyle/checkstyle/issues/3090 + */ +public class InputRightCurlyDoWhileAlone { + + public void foo1() { + do { + } while (true); + } + + public void foo2() { + int i = 1; + while (i < 5) { + String.CASE_INSENSITIVE_ORDER.equals(i + " "); + i++; + } + } + + public void foo3() { + int i = 1; + do { + i++; + String.CASE_INSENSITIVE_ORDER.equals(i + " "); + } while (i < 5); + } + + public void foo4() { + int prog, user; + prog = (int)(Math.random() * 10) + 1; + Scanner input = new Scanner(System.in, "utf-8"); + if( input.hasNextInt() ) { + do { + user = input.nextInt(); + if(user == prog) { + String.CASE_INSENSITIVE_ORDER.equals("Good!"); + } else { + if (user > 0 && user <= 10) { + String.CASE_INSENSITIVE_ORDER.equals("Bad! "); + if( prog < user ) { + String.CASE_INSENSITIVE_ORDER.equals("My number is less than yours."); + } else { + String.CASE_INSENSITIVE_ORDER.equals("My number is greater than yours."); + } + } else { + String.CASE_INSENSITIVE_ORDER.equals("Error!"); + } + } + } while( user != prog ); + } else { + String.CASE_INSENSITIVE_ORDER.equals("Error!"); + } + String.CASE_INSENSITIVE_ORDER.equals("Goodbye!"); + } + + public void foo5() { + do { + } // ok - for alone + while (true); + } + + public void foo6() { + do {} // ok - for alone + while (true); + } + + public void foo7() { + do + { + + } while (true); + } + + public void foo8() { + do + + { + + } // ok - for alone + + while + + (true); + } + + public void foo9() { + do {} while (true); + } +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyDoWhile.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyDoWhile.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyDoWhile.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyDoWhile.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,93 @@ +package com.google.checkstyle.test.chapter4formatting.rule412nonemptyblocks; + +import java.util.Scanner; + +/** + * Test input for GitHub issue #3090. + * https://github.com/checkstyle/checkstyle/issues/3090 + */ +public class InputRightCurlyDoWhile { + + public void foo1() { + do { + } while (true); + } + + public void foo2() { + int i = 1; + while (i < 5) { + String.CASE_INSENSITIVE_ORDER.equals(i + " "); + i++; + } + } + + public void foo3() { + int i = 1; + do { + i++; + String.CASE_INSENSITIVE_ORDER.equals(i + " "); + } while (i < 5); + } + + public void foo4() { + int prog, user; + prog = (int)(Math.random() * 10) + 1; + Scanner input = new Scanner(System.in, "utf-8"); + if( input.hasNextInt() ) { + do { + user = input.nextInt(); + if(user == prog) { + String.CASE_INSENSITIVE_ORDER.equals("Good!"); + } else { + if (user > 0 && user <= 10) { + String.CASE_INSENSITIVE_ORDER.equals("Bad! "); + if( prog < user ) { + String.CASE_INSENSITIVE_ORDER.equals("My number is less than yours."); + } else { + String.CASE_INSENSITIVE_ORDER.equals("My number is greater than yours."); + } + } else { + String.CASE_INSENSITIVE_ORDER.equals("Error!"); + } + } + } while( user != prog ); + } else { + String.CASE_INSENSITIVE_ORDER.equals("Error!"); + } + String.CASE_INSENSITIVE_ORDER.equals("Goodbye!"); + } + + public void foo5() { + do { + } // warn + while (true); + } + + public void foo6() { + do {} // warn + while (true); + } + + public void foo7() { + do + { + + } while (true); + } + + public void foo8() { + do + + { + + } // warn + + while + + (true); + } + + public void foo9() { + do {} while (true); + } +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyOtherAlone.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyOtherAlone.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyOtherAlone.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyOtherAlone.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,145 @@ +package com.google.checkstyle.test.chapter4formatting.rule412nonemptyblocks; + +class InputRightCurlyOtherAlone +{ + /** @see test method **/ + int foo() throws InterruptedException + { + int x = 1; + int a = 2; + while (true) + { + try + { + if (x > 0) + { + break; + } else if (x < 0) { //ok + + ; + } //ok - for alone config + else + { + break; + }//ok + switch (a) + { + case 0: + break; + default: + break; + } //ok + } //ok - for alone config + catch (Exception e) + { + break; + }//ok + }//ok + + synchronized (this) + { + do + { + x = 2; + } while (x == 2); //ok + }//ok + + this.wait(666 + ); // Bizarre, but legal + + for (int k = 0; k < 1; k++) + { + String innerBlockVariable = ""; + }//ok + + + if (System.currentTimeMillis() > 1000) + return 1; + else + return 2; + }//ok + + + static + { + int x = 1; + }//ok + + public enum GreetingsEnum + { + HELLO, + GOODBYE + }; //ok + + void method2() + { + boolean flag = true; + if (flag) { + System.identityHashCode("heh"); + flag = !flag; } System. //ok for alone config + identityHashCode("Xe-xe"); + + + if (flag) { System.identityHashCode("some foo"); } + } //ok +} //ok + +/** + * Test input for closing brace if that brace terminates + * a statement or the body of a constructor. + */ +class FooCtorAlone +{ + int i; + public FooCtorAlone() + { + i = 1; + }} //warn + +/** +* Test input for closing brace if that brace terminates +* a statement or the body of a method. +*/ +class FooMethodAlone +{ + public void fooMethod() + { + int i = 1; + }} //warn + +/** +* Test input for closing brace if that brace terminates +* a statement or the body of a named class. +*/ +class FooInnerAlone +{ + class InnerFoo + { + public void fooInnerMethod () + { + + } + }} //warn + +class EnumContainerAlone { + private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS } // ok +} + +class WithArraysAlone { + String[] s = {""}; // ok + String[] empty = {}; // ok + String[] s1 = { + "foo", "foo", + }; // ok + String[] s2 = + { + "foo", "foo", + }; // ok + String[] s3 = + { + "foo", + "foo", + }; // ok + String[] s4 = + {"foo", "foo"}; // ok +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyOther.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyOther.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyOther.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule412nonemptyblocks/InputRightCurlyOther.java 2017-10-29 12:46:46.000000000 +0000 @@ -17,7 +17,7 @@ } else if (x < 0) { //ok ; - } + } //warn else { break; @@ -29,7 +29,7 @@ default: break; } //ok - } + } //warn catch (Exception e) { break; @@ -76,7 +76,7 @@ boolean flag = true; if (flag) { System.identityHashCode("heh"); - flag = !flag; } System. + flag = !flag; } System. //warn identityHashCode("Xe-xe"); @@ -94,7 +94,7 @@ public FooCtor() { i = 1; - }} //warn + }} //ok /** * Test input for closing brace if that brace terminates @@ -105,7 +105,7 @@ public void fooMethod() { int i = 1; - }} //warn + }} //ok /** * Test input for closing brace if that brace terminates @@ -119,7 +119,7 @@ { } - }} //warn + }} //ok class EnumContainer { private enum Suit { CLUBS, HEARTS, SPADES, DIAMONDS } // ok diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/InputEmptyBlockBasic.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/InputEmptyBlockBasic.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/InputEmptyBlockBasic.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/InputEmptyBlockBasic.java 2017-10-29 12:46:46.000000000 +0000 @@ -325,3 +325,12 @@ }; } } + +class Example { + + void doNothing() {} // ok + + void doNothingElse() { // ok + + } +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/InputEmptyBlockCatch.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/InputEmptyBlockCatch.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/InputEmptyBlockCatch.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule413emptyblocks/InputEmptyBlockCatch.java 2017-10-29 12:46:46.000000000 +0000 @@ -72,4 +72,16 @@ finally {} } }; + + void foo3() { + try { + foo(); + } catch (Exception e) {} //warn + + try { + foo(); + } catch (Exception e) /*warn*/ { + + } + } } diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectFieldAndParameter.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectFieldAndParameter.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectFieldAndParameter.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectFieldAndParameter.java 2017-10-29 12:46:46.000000000 +0000 @@ -123,4 +123,4 @@ return new SecondFieldClassWithVeryVeryVeryLongName("VeryLoooooooooo" //indent:4 exp:4 + "oongString"); //indent:8 exp:8 } //indent:2 exp:2 -} //indent:0 exp:0 \ No newline at end of file +} //indent:0 exp:0 diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectForAndParameter.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectForAndParameter.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectForAndParameter.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectForAndParameter.java 2017-10-29 12:46:46.000000000 +0000 @@ -109,4 +109,4 @@ public Iterator iterator() { //indent:2 exp:2 return null; //indent:4 exp:4 } //indent:2 exp:2 -} //indent:0 exp:0 \ No newline at end of file +} //indent:0 exp:0 diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectIfAndParameter.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectIfAndParameter.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectIfAndParameter.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule42blockindentaion/InputIndentationCorrectIfAndParameter.java 2017-10-29 12:46:46.000000000 +0000 @@ -140,4 +140,4 @@ return new SecondClassWithVeryVeryVeryLongName("VeryLoooooooooo" //indent:4 exp:4 + "oongString"); //indent:8 exp:8 } //indent:2 exp:2 -} //indent:0 exp:0 \ No newline at end of file +} //indent:0 exp:0 diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputOperatorWrapAssign.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputOperatorWrapAssign.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputOperatorWrapAssign.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputOperatorWrapAssign.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,351 +0,0 @@ -package com.google.checkstyle.test.chapter4formatting.rule451wheretobreak; - -import java.util.HashMap; -import java.util.Map; - -class InputOperatorWrapAssign -{ - void test() - { - int x = 1 + - 2 - - 3 - - - 4; - x = x + 2; - boolean y = true - && - false; - y = true && - false; - y = false - && true; - } - - void testAssignment() - { - int x - = 0; //warn - int y = - 0; - } - - < - T extends Comparable & - java.io.Serializable - > - void testGenerics1() - { - Comparable - < - String - > - c = new String(); - Map map = new HashMap(); - - boolean flag = false; - - int init = 9; - - for (Map.Entry entry : - map.entrySet()) - { - int i = flag == true ? - 1 : 2; - } - - if (init != - 9) - { - - } - - while (init == - 10) - { - - } - - if (init > - 10) - { - - } else {} - - while (init < 10 || - !flag) { - - } - } - - class Inner { - void testGenerics1 - () - { - Comparable - < - String - > - c = new String(); - Map map = new HashMap(); - boolean flag = false; - - int init = 9; - - /*ok*/ for (Map.Entry entry : - map.entrySet()) - { - int i = flag == true ? - 1 : 2; - } - - if (init != - 9) - { - - } - - while (init == - 10) - { - - } - - if (init > - 10) - { - - } else {} - - while (init < 10 || - !flag) { - - } - } - } - - Inner anon = new Inner - (){ - void testGenerics1 - () - { - Comparable - < - String - > - c = new String(); - Map map = new HashMap(); - boolean flag = false; - int init = 9; - - /*ok*/ for (Map.Entry entry : - map.entrySet()) - { - int i = flag == true ? - 1 : 2; - } - - if (init != - 9) - { - - } - - while (init == - 10) - { - - } - - if (init > - 10) - { - - } else {} - - while (init < 10 || - !flag) { - - } - } - }; -} - -class AsInput3 { - int abc = 0; - String string - = "string"; // warn - double PI = // ok - 3.1415; -} - -class Ternary4 { - void foo() { - boolean flag = true; - int i = flag == true ? - 1 : - 2; - int i2 = flag == true - ? - 1 - : - 2; - int i3 = flag == true - ? 1 - : 2; - - } -} - -class AssignClass5 { - void foo() { - int i = 0; - int j = 0; - i += - 1; - j - += 2; //warn - i -= - 1; - j - -= 2; //warn - i /= - 1; - j - /= 2; //warn - i *= - 1; - j - *= 2; //warn - i %= - 1; - j - %= 2; //warn - i ^= - 1; - j - ^= 2; //warn - i |= - 1; - j - |= 2; //warn - i &= - 1; - j - &= 2; //warn - i >>= - 1; - j - >>= 2; //warn - i >>>= - 1; - j - >>>= 2; //warn - i <<= - 1; - j - <<= 2; //warn - } - - class InnerClass { - void foo() { - int i = 0; - int j = 0; - i += - 1; - j - += 2; //warn - i -= - 1; - j - -= 2; //warn - i /= - 1; - j - /= 2; //warn - i *= - 1; - j - *= 2; //warn - i %= - 1; - j - %= 2; //warn - i ^= - 1; - j - ^= 2; //warn - i |= - 1; - j - |= 2; //warn - i &= - 1; - j - &= 2; //warn - i >>= - 1; - j - >>= 2; //warn - i >>>= - 1; - j - >>>= 2; //warn - i <<= - 1; - j - <<= 2; //warn - } - } - - InnerClass anon = new InnerClass() { - void foo() { - int i = 0; - int j = 0; - i += - 1; - j - += 2; //warn - i -= - 1; - j - -= 2; //warn - i /= - 1; - j - /= 2; //warn - i *= - 1; - j - *= 2; //warn - i %= - 1; - j - %= 2; //warn - i ^= - 1; - j - ^= 2; //warn - i |= - 1; - j - |= 2; //warn - i &= - 1; - j - &= 2; //warn - i >>= - 1; - j - >>= 2; //warn - i >>>= - 1; - j - >>>= 2; //warn - i <<= - 1; - j - <<= 2; //warn - } - }; -} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputOperatorWrap.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputOperatorWrap.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputOperatorWrap.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputOperatorWrap.java 2017-10-29 12:46:46.000000000 +0000 @@ -1,5 +1,6 @@ package com.google.checkstyle.test.chapter4formatting.rule451wheretobreak; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -20,6 +21,14 @@ false; y = false && true; + /* Note: The three tests below will be used when issue #3381 is closed */ + Arrays.sort(null, String + :: + compareToIgnoreCase); + Arrays.sort(null, String:: /*(warn)*/ + compareToIgnoreCase); + Arrays.sort(null, String + ::compareToIgnoreCase); } void testAssignment() diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapArrayDeclarator.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapArrayDeclarator.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapArrayDeclarator.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapArrayDeclarator.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,12 @@ +package com.google.checkstyle.test.chapter4formatting.rule451wheretobreak; + +class InputSeparatorWrapArrayDeclarator { + + protected int[] arrayDeclarationWithGoodWrapping = new int[ + ] {1, 2}; // ok + + protected int[] arrayDeclarationWithBadWrapping = new int + [] {1, 2}; // warn + +} + diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapComma.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapComma.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapComma.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapComma.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,45 @@ +package com.google.checkstyle.test.chapter4formatting.rule451wheretobreak; + +public class InputSeparatorWrapComma { + public void goodCase() + { + int i = 0; + String s = "ffffooooString"; + s + .isEmpty(); //ok + s.isEmpty(); + + foo(i, + s); //ok + } + public static void foo(int i, String s) + { + + } +} + +class badCaseComma { + + public void goodCase(int... aFoo) + { + int i = 0; + + String s = "ffffooooString"; + boolean b = s. + isEmpty(); + foo(i + ,s); //warn + int[] j; + } + public static String foo(int i, String s) + { + String maxLength = "123"; + int truncationLength = 1; + CharSequence seq = null; + Object truncationIndicator = null; + return new StringBuilder(maxLength ) + .append(seq, 0, truncationLength ) + .append(truncationIndicator) + .toString(); + } +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapEllipsis.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapEllipsis.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapEllipsis.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapEllipsis.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,16 @@ +package com.google.checkstyle.test.chapter4formatting.rule451wheretobreak; + +class InputSeparatorWrapEllipsis { + + public void testMethodWithGoodWrapping(String... // ok + parameters) { + + } + + public void testMethodWithBadWrapping(String + ...parameters) { // warn + + } + +} + diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapMethodRef.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapMethodRef.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapMethodRef.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule451wheretobreak/InputSeparatorWrapMethodRef.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,20 @@ +package com.google.checkstyle.test.chapter4formatting.rule451wheretobreak; + +import java.util.Arrays; + +public class InputSeparatorWrapMethodRef { + + void goodCase() { + String[] stringArray = { "Barbara", "James", "Mary", "John", + "Patricia", "Robert", "Michael", "Linda" }; + Arrays.sort(stringArray, String + ::compareToIgnoreCase); + } + + void badCase() { + String[] stringArray = { "Barbara", "James", "Mary", "John", + "Patricia", "Robert", "Michael", "Linda" }; + /*warn*/ Arrays.sort(stringArray, String:: + compareToIgnoreCase); + } +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectFieldAndParameter.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectFieldAndParameter.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectFieldAndParameter.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectFieldAndParameter.java 2017-10-29 12:46:46.000000000 +0000 @@ -123,4 +123,4 @@ return new SecondFieldClassWithVeryVeryVeryLongName("VeryLoooooooooo" //indent:4 exp:4 + "oongString"); //indent:8 exp:8 } //indent:2 exp:2 -} //indent:0 exp:0 \ No newline at end of file +} //indent:0 exp:0 diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectForAndParameter.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectForAndParameter.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectForAndParameter.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectForAndParameter.java 2017-10-29 12:46:46.000000000 +0000 @@ -109,4 +109,4 @@ public Iterator iterator() { //indent:2 exp:2 return null; //indent:4 exp:4 } //indent:2 exp:2 -} //indent:0 exp:0 \ No newline at end of file +} //indent:0 exp:0 diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectIfAndParameter.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectIfAndParameter.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectIfAndParameter.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule452indentcontinuationlines/InputIndentationCorrectIfAndParameter.java 2017-10-29 12:46:46.000000000 +0000 @@ -140,4 +140,4 @@ return new SecondClassWithVeryVeryVeryLongName("VeryLoooooooooo" //indent:4 exp:4 + "oongString"); //indent:8 exp:8 } //indent:2 exp:2 -} //indent:0 exp:0 \ No newline at end of file +} //indent:0 exp:0 diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule461verticalwhitespace/InputEmptyLineSeparator.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule461verticalwhitespace/InputEmptyLineSeparator.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule461verticalwhitespace/InputEmptyLineSeparator.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule461verticalwhitespace/InputEmptyLineSeparator.java 2017-10-29 12:46:46.000000000 +0000 @@ -24,8 +24,8 @@ import java.util.Map; import java.util.concurrent.Callable; import java.util.Collections; -import com.google.common.base.CharMatcher; -import com.google.common.io.CharSource; +import com.puppycrawl.tools.checkstyle.Checker; +import com.puppycrawl.tools.checkstyle.ConfigurationLoader; import javax.swing.AbstractAction; diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputGenericWhitespaceEndsTheLine.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputGenericWhitespaceEndsTheLine.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputGenericWhitespaceEndsTheLine.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputGenericWhitespaceEndsTheLine.java 2017-10-29 12:46:46.000000000 +0000 @@ -4,4 +4,4 @@ public boolean returnsGenericObjectAtEndOfLine(Object otherObject) { return otherObject instanceof Enum; } -} \ No newline at end of file +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputMethodParamPad.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputMethodParamPad.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputMethodParamPad.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputMethodParamPad.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,63 @@ +package com.google.checkstyle.test.chapter4formatting.rule462horizontalwhitespace; +import java.util.Vector; +/** Test input for MethodDefPadCheck */ +public class InputMethodParamPad +{ + public InputMethodParamPad() + { + super(); + } + + public InputMethodParamPad (int aParam) // warn + { + super (); // warn + } + + public void method() + { + } + + public void method (int aParam) // warn + { + } + + public void + method(double aParam) + { + // invoke constructor + InputMethodParamPad pad = new InputMethodParamPad(); + pad = new InputMethodParamPad (); // warn + pad = new + InputMethodParamPad(); + + // call method + method(); + method (); // warn + } + + public void dottedCalls() + { + this.method(); + this.method (); // warn + this. + method(); + + InputMethodParamPad p = new InputMethodParamPad(); + p.method(); + p.method (); // warn + p. + method(); + + java.lang.Integer.parseInt("0"); + java.lang.Integer.parseInt ("0"); // warn + java.lang.Integer. + parseInt("0"); + } + + public void newArray() + { + int[] a = new int[]{0, 1}; + java.util.Vector v = new java.util.Vector(); + java.util.Vector v1 = new Vector(); + } +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputNoWhitespaceBeforeEmptyForLoop.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputNoWhitespaceBeforeEmptyForLoop.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputNoWhitespaceBeforeEmptyForLoop.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputNoWhitespaceBeforeEmptyForLoop.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,22 @@ +package com.google.checkstyle.test.chapter4formatting.rule462horizontalwhitespace; + +public class InputNoWhitespaceBeforeEmptyForLoop { + + public static void f() { + for (; ; ) { // ok + break; + } + for (int x = 0; ; ) { // ok + break; + } + for (int x = 0 ; ; ) { // warning + break; + } + for (int x = 0; x < 10; ) { // ok + break; + } + for (int x = 0; x < 10 ; ) { // warning + break; + } + } +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputParenPad.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputParenPad.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputParenPad.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputParenPad.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,223 @@ +package com.google.checkstyle.test.chapter4formatting.rule462horizontalwhitespace; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; + +public class InputParenPad +{ + class ParenPadNoSpace { + ParenPadNoSpace() { + this(0); + } + + ParenPadNoSpace(int i) { + super(); + } + + @SuppressWarnings("") + void method(boolean status) { + try (Writer writer = new StringWriter()) { + do { + writer.append("a"); + } while (status); + } catch (IOException e) { + while (status) { + for (int i = 0; i < (long) (2 * (4 / 2)); i++) { + if (i > 2) { + synchronized (this) { + switch (i) { + case 3: + case (4): + case 5: + break; + } + } + } + } + } + } + } + } + + class ParenPadSpaceLeft { + ParenPadSpaceLeft( ) { // warning + this( 0); // warning + } + + ParenPadSpaceLeft( int i) { // warning + super( ); // warning + } + + @SuppressWarnings( "") // warning + void method( boolean status) { // warning + try ( Writer writer = new StringWriter( )) { // warning + do { + writer.append("a"); + } while ( status); // warning + } catch ( IOException e) { // warning + while ( status) { // warning + for ( int i = 0; i < ( long) ( 2 * ( 4 / 2)); i++) { // warning + if ( i > 2) { // warning + synchronized ( this) { // warning + switch ( i) { // warning + case 3: + case ( 4): // warning + case 5: + break; + } + } + } + } + } + } + } + } + + class ParenPadSpaceRight { + ParenPadSpaceRight( ) { // warning + this(0 ); // warning + } + + ParenPadSpaceRight(int i ) { // warning + super( ); // warning + } + + @SuppressWarnings("" ) // warning + void method(boolean status ) { // warning + try (Writer writer = new StringWriter( ) ) { // warning + do { + writer.append("a" ); // warning + } while (status ); // warning + } catch (IOException e ) { // warning + while (status ) { // warning + for (int i = 0; i < (long ) (2 * (4 / 2 ) ); i++ ) { // warning + if (i > 2 ) { // warning + synchronized (this ) { // warning + switch (i ) { // warning + case 3: + case (4 ): // warning + case 5: + break; + } + } + } + } + } + } + } + } + + String foo() { + return ( (Object // warning + ) bar( ( 1 > 2 ) ? // warning + ( ( 3 < 4 )? false : true ) : // warning + ( ( 1 == 1 ) ? false : true) ) ).toString(); // warning + } + @MyAnnotation + public boolean bar(boolean a) { + assert ( true ); // warning + return true; + } + + boolean fooo = this.bar(( true && false ) && true); // warning +} +@interface MyAnnotation { + String someField( ) default "Hello world"; // warning +} + +enum MyEnum { + SOME_CONSTANT( ) { // warning + int i = (int) (2 * (4 / 2) + ); + }; + + public void myMethod() { + String s = "test"; + Object o = s; + ((String)o).length(); + ( (String)o ).length(); // warning + } + + public void crisRon() { + Object leo = "messi"; + Object ibra = leo; + ((String)leo).compareTo( (String)ibra ); // warning + Math.random(); + } + + public void intStringConv() { + Object a = 5; + Object b = "string"; + int w = Integer.parseInt((String)a); + int x = Integer.parseInt( (String)a); // warning + double y = Double.parseDouble((String)a ); // warning + float z = Float.parseFloat( (String)a ); // warning + String d = ((String)b); + } + + public int something( Object o ) { // warning + if ( o == null || !( o instanceof Float ) ) { // warning + return -1; + } + return Integer.valueOf( 22 ).compareTo( (Integer) o ); // warning + } + + private void launch(Integer number ) { // warning + String myInt = ( number.toString() + '\0' ); // warning + boolean result = false; + if (number == 123) + result = true; + } + + private static String getterName( Exception t) { // warning + if (t instanceof ClassNotFoundException ) { // warning + return ( (ClassNotFoundException) t ).getMessage(); // warning + } + else { + return "?"; + } + } + + private Object exam; + + public String testing() { + return ( this.exam != null ) // warning + ? ( ( Enum )this.exam ).name() // warning + : null; + } + + Object stringReturnValue( Object result ) { // warning + if ( result instanceof String ) { // warning + result = ( (String) result ).length(); // warning + } + return result; + } + + + + private void except() { + java.util.ArrayList arrlist = new java.util.ArrayList( 5 ); // warning + arrlist.add( 20); // warning + arrlist.add(15 ); // warning + arrlist.add( 30 ); // warning + arrlist.add(45); + try { + ( arrlist ).remove( 2); // warning + } catch ( IndexOutOfBoundsException x ) { // warning + x.getMessage(); + } + org.junit.Assert.assertThat( "123", org.hamcrest.CoreMatchers.is( "123" ) ); // warning + org.junit.Assert.assertThat( "Help! Integers don't work", // warning + 0, org.hamcrest.CoreMatchers.is( 1 ) ); // warning + } + + private void tryWithResources() throws Exception { + try (AutoCloseable a = null) {} // ok + try (AutoCloseable a = null; AutoCloseable b = null) {} // ok + try (AutoCloseable a = null; AutoCloseable b = null; ) {} // ok + try (AutoCloseable a = null; AutoCloseable b = null; ) {} // ok + try (AutoCloseable a = null ) {} // warning + try (AutoCloseable a = null; AutoCloseable b = null ) {} // warning + } +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputWhitespaceAroundBasic.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputWhitespaceAroundBasic.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputWhitespaceAroundBasic.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputWhitespaceAroundBasic.java 2017-10-29 12:46:46.000000000 +0000 @@ -236,3 +236,24 @@ return null; } } + +/** + * Operators mentioned in Google Coding Standards 2016-07-12 + */ +class NewGoogleOperators +{ + NewGoogleOperators() + { + Runnable l; + + l = ()-> { }; //warn + l = () ->{ }; //warn + l = () -> { }; + + java.util.Arrays.sort(null, String :: compareToIgnoreCase); + java.util.Arrays.sort(null, String::compareToIgnoreCase); + + new Object().toString(); + new Object() . toString(); + } +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputWhitespaceAroundEmptyTypesAndCycles.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputWhitespaceAroundEmptyTypesAndCycles.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputWhitespaceAroundEmptyTypesAndCycles.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule462horizontalwhitespace/InputWhitespaceAroundEmptyTypesAndCycles.java 2017-10-29 12:46:46.000000000 +0000 @@ -1,14 +1,14 @@ package com.google.checkstyle.test.chapter4formatting.rule462horizontalwhitespace; -import com.google.common.base.Function; -import com.google.common.base.Supplier; +import java.util.function.Function; +import java.util.function.Supplier; class myFoo { private void foo() { int i = 0; - String[][] x = {{"foo"}}; + String[][] x = { {"foo"} }; for (int first = 0; first < 5; first++) {} //ok int j = 0; while (j == 1) {} //ok diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4822variabledistance/InputVariableDeclarationUsageDistanceCheck.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4822variabledistance/InputVariableDeclarationUsageDistanceCheck.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4822variabledistance/InputVariableDeclarationUsageDistanceCheck.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4822variabledistance/InputVariableDeclarationUsageDistanceCheck.java 2017-10-29 12:46:46.000000000 +0000 @@ -408,7 +408,7 @@ { int mm = Integer.parseInt("2"); long timeNow = 0; - Calendar cal = Calendar.getInstance(); + Calendar cal = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault()); cal.setTimeInMillis(timeNow); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); @@ -417,7 +417,7 @@ } public void testIssue32_3(MyObject[] objects) { - Calendar cal = Calendar.getInstance(); + Calendar cal = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault()); for(int i=0; i iterator() { //indent:2 exp:2 return null; //indent:4 exp:4 } //indent:2 exp:2 -} //indent:0 exp:0 \ No newline at end of file +} //indent:0 exp:0 diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4841indentation/InputIndentationCorrectIfAndParameter.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4841indentation/InputIndentationCorrectIfAndParameter.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4841indentation/InputIndentationCorrectIfAndParameter.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4841indentation/InputIndentationCorrectIfAndParameter.java 2017-10-29 12:46:46.000000000 +0000 @@ -140,4 +140,4 @@ return new SecondClassWithVeryVeryVeryLongName("VeryLoooooooooo" //indent:4 exp:4 + "oongString"); //indent:8 exp:8 } //indent:2 exp:2 -} //indent:0 exp:0 \ No newline at end of file +} //indent:0 exp:0 diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule485annotations/InputAnnotationLocation.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule485annotations/InputAnnotationLocation.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule485annotations/InputAnnotationLocation.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule485annotations/InputAnnotationLocation.java 2017-10-29 12:46:46.000000000 +0000 @@ -1,7 +1,7 @@ package com.google.checkstyle.test.chapter4formatting.rule485annotations; @MyAnnotation2 @MyAnnotation1 //warn -class InputCorrectAnnotationIndentation +class InputAnnotationLocation { @MyAnnotation2 @MyAnnotation1 @@ -18,7 +18,7 @@ @MyAnnotation2 @MyAnnotation1 //warn - public InputCorrectAnnotationIndentation() {} + public InputAnnotationLocation() {} @MyAnnotationWithParam("foo") @MyAnnotation2 void foo1() {} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule485annotations/InputAnnotationLocationVariables.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule485annotations/InputAnnotationLocationVariables.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule485annotations/InputAnnotationLocationVariables.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule485annotations/InputAnnotationLocationVariables.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,103 @@ +package com.google.checkstyle.test.chapter4formatting.rule485annotations; + +@MyAnnotation2 @MyAnnotation1 // ok - in variables config +class InputAnnotationLocationVariables +{ + + @MyAnnotation2 @MyAnnotation1 + public int a; + + @MyAnnotation1 public int b; + + @MyAnnotation2 + @MyAnnotation1 + public int c; + + @MyAnnotation1 + public int d; + + @MyAnnotation2 + @MyAnnotation1 // ok - in variables config + public InputAnnotationLocationVariables() {} + + @MyAnnotationWithParam("foo") + @MyAnnotation2 void foo1() {} + + @MyAnnotation1 + @MyAnnotation2 // ok - in variables config + void foo2() {} + + @MyAnnotation1 + @MyAnnotation2 // ok - in variables config + @MyAnnotation3 // ok - in variables configwarn + @MyAnnotation4 // ok - in variables config + class InnerClass + { + @MyAnnotation2 @MyAnnotation1 + public int a; + + @MyAnnotation1 public int b; + + @MyAnnotation2 + @MyAnnotation1 + public int c; + + @MyAnnotation1 + public int d; + + @MyAnnotation2 + @MyAnnotation1 public InnerClass() + { + // TODO Auto-generated constructor stub + } + @MyAnnotation1 + @MyAnnotation2 // ok - in variables config + void foo1() {} + + @MyAnnotation1 + @MyAnnotation2 // ok - in variables config + void foo2() {} + } + + @MyAnnotation1 + @MyAnnotation2 //warn + InnerClass anon = new InnerClass() + { + @MyAnnotation2 @MyAnnotation1 public int a; + + @MyAnnotation1 public int b; + + @MyAnnotation2 + @MyAnnotation1 + public int c; + + @MyAnnotation1 + public int d; + + @MyAnnotation1 + @MyAnnotation2 void foo1() {} // ok - in variables config + + @MyAnnotation1 + @MyAnnotation2 // ok - in variables config + void foo2() {} + + @MyAnnotation1 void foo42() {} + }; + +} + +@MyAnnotation1 + @MyAnnotation2 // ok - in variables config +class FooVariables {} + +@interface MyAnnotationVariables1 {} + +@interface MyAnnotationVariables2 {} + +@interface MyAnnotationVariables3 {} + +@interface MyAnnotationVariables4 {} + +@interface MyAnnotationWithParamVariables { + + String value();} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4861blockcommentstyle/InputCommentsIndentationInSwitchBlock.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4861blockcommentstyle/InputCommentsIndentationInSwitchBlock.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4861blockcommentstyle/InputCommentsIndentationInSwitchBlock.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule4861blockcommentstyle/InputCommentsIndentationInSwitchBlock.java 2017-10-29 12:46:46.000000000 +0000 @@ -16,7 +16,7 @@ // comment break; case "3": - /* com */ + /* // warn */ foo1(); /* com */ break; diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule487modifiers/InputModifierOrder.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule487modifiers/InputModifierOrder.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule487modifiers/InputModifierOrder.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter4formatting/rule487modifiers/InputModifierOrder.java 2017-10-29 12:46:46.000000000 +0000 @@ -236,3 +236,11 @@ @interface MyAnnotation4 { } + +/** Illegal order of modifiers for interface methods */ +interface InputModifierOrderInterface +{ + default strictfp void a() { } //ok + + strictfp default void b() { } //warn +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule51identifiernames/InputCatchParameterName.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule51identifiernames/InputCatchParameterName.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule51identifiernames/InputCatchParameterName.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule51identifiernames/InputCatchParameterName.java 2017-10-29 12:46:46.000000000 +0000 @@ -3,7 +3,7 @@ public class InputCatchParameterName { { try { - } catch (Exception e) { // warn + } catch (Exception e) { // ok } try { } catch (Exception ex) { // ok @@ -21,7 +21,7 @@ } catch (Exception noWorries) { // ok } try { - } catch (Throwable t) { // warn + } catch (Throwable t) { // ok } try { throw new InterruptedException("interruptedException"); @@ -47,7 +47,19 @@ } catch (Exception iException) { // warn } try { - } catch (Exception x) { // warn + } catch (Exception ex_1) { // warn + } + try { + } catch (Exception eX) { // warn + } + try { + } catch (Exception eXX) { // warn + } + try { + } catch (Exception x_y_z) { // warn + } + try { + } catch (Exception Ex) { // warn } } } diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule522typenames/InputTypeName.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule522typenames/InputTypeName.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule522typenames/InputTypeName.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule522typenames/InputTypeName.java 2017-10-29 12:46:46.000000000 +0000 @@ -68,4 +68,4 @@ @interface Annot$ation {} //warn -@interface Annotation$ {} //warn \ No newline at end of file +@interface Annotation$ {} //warn diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule526parameternames/InputParameterName.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule526parameternames/InputParameterName.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule526parameternames/InputParameterName.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule526parameternames/InputParameterName.java 2017-10-29 12:46:46.000000000 +0000 @@ -0,0 +1,75 @@ +package com.google.checkstyle.test.chapter5naming.rule526parameternames; + +import java.io.*; + +class InputParameterName +{ + + /** Some more Javadoc. */ + public void doSomething(int aaa, int abn, String aaA, + boolean bB) //warn + { + for (Object O : new java.util.ArrayList()) + { + + } + } +} + + +/** Test enum for member naming check */ +enum MyEnum1 +{ + /** ABC constant */ + ABC, + + /** XYZ constant */ + XYZ; + + /** Should be mSomeMemeber */ + private int someMember; + + public void doEnum(int aaaL, + long llll_llll, //warn + boolean bB) {} //warn +} + +/** Test public vs private method parameter naming check. */ +class InputParameterNameSimplePub +{ + /** Valid: public and more than one char Long */ + public void a(int par, int parA) {} + + /** Invalid: public and one char long */ + public void b(int p) {} + + /** Valid: private and one char long. */ + private void c(int p) {} + + /** Holder for inner anonymous classes */ + private void d(int param) { + new Object() { + /** Invalid: public and one char long. */ + public void e(int p) { } + }; + } + + /** Invalid: public constructor and one char long */ + public InputParameterNameSimplePub(int p) { } + + /** Valid: private constructor and one char long */ + private InputParameterNameSimplePub(float p) { } + + void toManyArgs( + int $arg1, //warn + int ar$g2, //warn + int arg3$, //warn + int a_rg4, //warn + int _arg5, //warn + int arg6_, //warn + int aArg7, //warn + int aArg8, //warn + int aar_g) //warn + + {} +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule526parameternames/InputParameterNameSimple.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule526parameternames/InputParameterNameSimple.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule526parameternames/InputParameterNameSimple.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule526parameternames/InputParameterNameSimple.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -package com.google.checkstyle.test.chapter5naming.rule526parameternames; - -import java.io.*; - -final class InputSimple -{ - void toManyArgs( - int $arg1, //warn - int ar$g2, //warn - int arg3$, //warn - int a_rg4, //warn - int _arg5, //warn - int arg6_, //warn - int aArg7, //warn - int aArg8, //warn - int aar_g) //warn - - {} -} - -class InputSimple2 -{ - - /** Some more Javadoc. */ - public void doSomething(int aaa, int abn, String aaA, - boolean bB) //warn - { - for (Object O : new java.util.ArrayList()) - { - - } - } -} - - -/** Test enum for member naming check */ -enum MyEnum1 -{ - /** ABC constant */ - ABC, - - /** XYZ constant */ - XYZ; - - /** Should be mSomeMemeber */ - private int someMember; - - public void doEnum(int aaaL, - long llll_llll, //warn - boolean bB) {} //warn -} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/InputLocalVariableNameOneCharVarName.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/InputLocalVariableNameOneCharVarName.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/InputLocalVariableNameOneCharVarName.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/InputLocalVariableNameOneCharVarName.java 2017-10-29 12:46:46.000000000 +0000 @@ -12,7 +12,7 @@ //some code } - int i = 0; //warn + int i = 0; // ok for(int index = 1; index < 10; index++) { //ok //some code diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/InputLocalVariableNameSimple.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/InputLocalVariableNameSimple.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/InputLocalVariableNameSimple.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule527localvariablenames/InputLocalVariableNameSimple.java 2017-10-29 12:46:46.000000000 +0000 @@ -23,7 +23,7 @@ private void localVariables() { //bad examples - int a; //warn + int a; int aA; //warn int a1_a; //warn int A_A; //warn diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule53camelcase/InputAbbreviationAsWordInTypeNameCheck.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule53camelcase/InputAbbreviationAsWordInTypeNameCheck.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter5naming/rule53camelcase/InputAbbreviationAsWordInTypeNameCheck.java 2015-11-13 05:06:18.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter5naming/rule53camelcase/InputAbbreviationAsWordInTypeNameCheck.java 2017-10-29 12:46:46.000000000 +0000 @@ -70,4 +70,4 @@ void XMLHTTPRequest() {} //warn }; -} \ No newline at end of file +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter6programpractice/rule62donotignoreexceptions/InputEmptyBlockCatch.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter6programpractice/rule62donotignoreexceptions/InputEmptyBlockCatch.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter6programpractice/rule62donotignoreexceptions/InputEmptyBlockCatch.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter6programpractice/rule62donotignoreexceptions/InputEmptyBlockCatch.java 2017-10-29 12:46:46.000000000 +0000 @@ -72,4 +72,20 @@ finally {} //warn } }; + + void bar1() { + try { + if(!flag) { + doSm(); + } + } catch (Exception expected) {} + } + + void bar2() { + try { + if(!flag) { + doSm(); + } + } catch (Exception expected) {} + } } diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule711generalform/InputSingleLineJavadocCheckError.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule711generalform/InputSingleLineJavadocCheckError.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule711generalform/InputSingleLineJavadocCheckError.java 2015-11-13 05:06:18.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule711generalform/InputSingleLineJavadocCheckError.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,6 +0,0 @@ -package com.google.checkstyle.test.chapter7javadoc.rule711generalform; - -public class InputSingleLineJavadocCheckError { - /** {@customTag} */ //warn - void bar() {} -} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule711generalform/InputSingleLineJavadocCheck.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule711generalform/InputSingleLineJavadocCheck.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule711generalform/InputSingleLineJavadocCheck.java 2015-11-13 05:06:18.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule711generalform/InputSingleLineJavadocCheck.java 2017-10-29 12:46:46.000000000 +0000 @@ -40,4 +40,4 @@ /** @customTag href="https://github.com/checkstyle/chestyle/" text*/ //warn void bar3() {} -} \ No newline at end of file +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/InputJavaDocTagContinuationIndentation.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/InputJavaDocTagContinuationIndentation.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/InputJavaDocTagContinuationIndentation.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/InputJavaDocTagContinuationIndentation.java 2017-10-29 12:46:46.000000000 +0000 @@ -322,4 +322,4 @@ * Some javadoc. // warn * @author max */ -interface FooIn5 {} \ No newline at end of file +interface FooIn5 {} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/InputNonEmptyAtclauseDescriptionCheck.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/InputNonEmptyAtclauseDescriptionCheck.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/InputNonEmptyAtclauseDescriptionCheck.java 2016-01-03 14:37:39.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule713atclauses/InputNonEmptyAtclauseDescriptionCheck.java 2017-10-29 12:46:46.000000000 +0000 @@ -34,7 +34,7 @@ * @param a * @param b * @param c - * @return + * @deprecated * @throws Exception * @deprecated */ @@ -48,11 +48,11 @@ * @param a * @param b * @param c - * @return + * @deprecated * @throws Exception */ public int foo4(String a, int b, double c) throws Exception { return 1; } -} \ No newline at end of file +} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/InputCorrectSummaryJavaDocCheck.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/InputCorrectSummaryJavaDocCheck.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/InputCorrectSummaryJavaDocCheck.java 2015-11-13 05:06:18.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/InputCorrectSummaryJavaDocCheck.java 2017-10-29 12:46:46.000000000 +0000 @@ -16,6 +16,7 @@ void foo3() {} /** + * This is valid. * @throws Exception if an error occurs. */ void foo4() throws Exception {} @@ -29,8 +30,9 @@ */ void foo6() {} - /** - * + /** + * This is valid. + * */ class InnerInputCorrectJavaDocParagraphCheck { @@ -46,11 +48,12 @@ public static final byte NUL_2 = 0; /** - * Returns the customer ID. This method returns + * Returns the customer ID. This method returns. */ int getId() {return 666;} /** + * This is valid. * . */ void foo2() {} @@ -62,6 +65,7 @@ void foo3() {} /** + * This is valid. * @throws Exception if an error occurs. */ void foo4() throws Exception {} @@ -74,7 +78,7 @@ /** * An especially short (int... A) bit of Javadoc. This - * method returns + * method returns. */ void foo6() {} } @@ -105,6 +109,7 @@ void foo3() {} /** + * This is valid. * @throws Exception if an error occurs. */ void foo4() throws Exception {} @@ -128,6 +133,7 @@ boolean emulated1() {return false;} /** + * This is valid. * @return Some Javadoc the customer ID. */ int geId() {return 666;} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/InputIncorrectSummaryJavaDocCheck.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/InputIncorrectSummaryJavaDocCheck.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/InputIncorrectSummaryJavaDocCheck.java 2015-11-13 05:06:18.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule72thesummaryfragment/InputIncorrectSummaryJavaDocCheck.java 2017-10-29 12:46:46.000000000 +0000 @@ -29,7 +29,7 @@ */ public static final byte NUL = 0; - /** +/*warn*//** * */ class InnerInputCorrectJavaDocParagraphCheck { @@ -39,7 +39,7 @@ */ public static final byte NUL = 0; - /** + /** * Some java@doc. */ public static final byte NUL_2 = 0; @@ -50,7 +50,7 @@ */ boolean emulated() {return false;} - /** +/*warn*//** * */ void foo2() {} @@ -62,7 +62,7 @@ int geId() {return 666;} /** - * As of JDK 1.1, replaced by {@link #setBounds(int,int,int,int)} + * As of JDK 1.1, replaced by {@link #setBounds(int,int,int,int)}. */ void foo3() {} @@ -94,17 +94,17 @@ * Some Javadoc. */ void emulated(String s) {} - + /** - * As of JDK 1.1, replaced by {@link #setBounds(int,int,int,int)} + * As of JDK 1.1, replaced by {@link #setBounds(int,int,int,int)}. */ void foo3() {} - + /*warn*//** * @throws Exception if an error occurs */ void foo4() throws Exception {} - + /** An especially short bit of Javadoc. */ void foo5() {} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule731selfexplanatory/InputJavadocMethodCheck.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule731selfexplanatory/InputJavadocMethodCheck.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule731selfexplanatory/InputJavadocMethodCheck.java 2015-11-13 05:06:18.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule731selfexplanatory/InputJavadocMethodCheck.java 2017-10-29 12:46:46.000000000 +0000 @@ -105,4 +105,4 @@ + "ooo"; } } -@interface MyAnnotation {} \ No newline at end of file +@interface MyAnnotation {} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule732overrides/InputJavadocMethodCheck.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule732overrides/InputJavadocMethodCheck.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule732overrides/InputJavadocMethodCheck.java 2015-11-13 05:06:18.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule732overrides/InputJavadocMethodCheck.java 2017-10-29 12:46:46.000000000 +0000 @@ -105,4 +105,4 @@ + "ooo"; } } -@interface MyAnnotation {} \ No newline at end of file +@interface MyAnnotation {} diff -Nru checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule73wherejavadocused/InputJavadocMethodCheck.java checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule73wherejavadocused/InputJavadocMethodCheck.java --- checkstyle-6.15/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule73wherejavadocused/InputJavadocMethodCheck.java 2015-11-13 05:06:18.000000000 +0000 +++ checkstyle-8.8/src/it/resources/com/google/checkstyle/test/chapter7javadoc/rule73wherejavadocused/InputJavadocMethodCheck.java 2017-10-29 12:46:46.000000000 +0000 @@ -105,4 +105,4 @@ + "ooo"; } } -@interface MyAnnotation {} \ No newline at end of file +@interface MyAnnotation {} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/ant/CheckstyleAntTask.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/ant/CheckstyleAntTask.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/ant/CheckstyleAntTask.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/ant/CheckstyleAntTask.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,12 +24,14 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Properties; import java.util.ResourceBundle; +import java.util.stream.Collectors; import org.apache.tools.ant.AntClassLoader; import org.apache.tools.ant.BuildException; @@ -42,17 +44,20 @@ import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; -import com.google.common.collect.Lists; import com.google.common.io.Closeables; import com.puppycrawl.tools.checkstyle.Checker; import com.puppycrawl.tools.checkstyle.ConfigurationLoader; -import com.puppycrawl.tools.checkstyle.DefaultContext; import com.puppycrawl.tools.checkstyle.DefaultLogger; +import com.puppycrawl.tools.checkstyle.ModuleFactory; +import com.puppycrawl.tools.checkstyle.PackageObjectFactory; import com.puppycrawl.tools.checkstyle.PropertiesExpander; +import com.puppycrawl.tools.checkstyle.ThreadModeSettings; import com.puppycrawl.tools.checkstyle.XMLLogger; import com.puppycrawl.tools.checkstyle.api.AuditListener; +import com.puppycrawl.tools.checkstyle.api.AutomaticBean; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Configuration; +import com.puppycrawl.tools.checkstyle.api.RootModule; import com.puppycrawl.tools.checkstyle.api.SeverityLevel; import com.puppycrawl.tools.checkstyle.api.SeverityLevelCounter; @@ -60,8 +65,10 @@ * An implementation of a ANT task for calling checkstyle. See the documentation * of the task for usage. * @author Oliver Burn + * @noinspection ClassLoaderInstantiation */ public class CheckstyleAntTask extends Task { + /** Poor man's enum for an xml formatter. */ private static final String E_XML = "xml"; /** Poor man's enum for an plain formatter. */ @@ -70,14 +77,17 @@ /** Suffix for time string. */ private static final String TIME_SUFFIX = " ms."; + /** Contains the paths to process. */ + private final List paths = new ArrayList<>(); + /** Contains the filesets to process. */ - private final List fileSets = Lists.newArrayList(); + private final List fileSets = new ArrayList<>(); /** Contains the formatters to log to. */ - private final List formatters = Lists.newArrayList(); + private final List formatters = new ArrayList<>(); /** Contains the Properties to override. */ - private final List overrideProps = Lists.newArrayList(); + private final List overrideProps = new ArrayList<>(); /** Class path to locate class files. */ private Path classpath; @@ -86,7 +96,7 @@ private String fileName; /** Config file containing configuration. */ - private String configLocation; + private String config; /** Whether to fail build on violations. */ private boolean failOnViolation = true; @@ -104,18 +114,18 @@ private int maxWarnings = Integer.MAX_VALUE; /** - * Whether to omit ignored modules - some modules may log tove + * Whether to execute ignored modules - some modules may log above * their severity depending on their configuration (e.g. WriteTag) so * need to be included */ - private boolean omitIgnoredModules = true; + private boolean executeIgnoredModules; //////////////////////////////////////////////////////////////////////////// // Setters for ANT specific attributes //////////////////////////////////////////////////////////////////////////// /** - * Tells this task to set the named property to "true" when there + * Tells this task to write failure message to the named property when there * is a violation. * @param propertyName the name of the property to set * in the event of an failure. @@ -150,6 +160,14 @@ } /** + * Adds a path. + * @param path the path to add. + */ + public void addPath(Path path) { + paths.add(path); + } + + /** * Adds set of files (nested fileset attribute). * @param fileSet the file set to add */ @@ -215,52 +233,25 @@ /** * Sets configuration file. - * @param file the configuration file to use - */ - public void setConfig(File file) { - setConfigLocation(file.getAbsolutePath()); - } - - /** - * Sets URL to the configuration. - * @param url the URL of the configuration to use - * @deprecated please use setConfigUrl instead - */ - @Deprecated - public void setConfigURL(URL url) { - setConfigUrl(url); - } - - /** - * Sets URL to the configuration. - * @param url the URL of the configuration to use + * @param configuration the configuration file, URL, or resource to use */ - public void setConfigUrl(URL url) { - setConfigLocation(url.toExternalForm()); - } - - /** - * Sets the location of the configuration. - * @param location the location, which is either a - */ - private void setConfigLocation(String location) { - if (configLocation != null) { - throw new BuildException("Attributes 'config' and 'configURL' " - + "must not be set at the same time"); + public void setConfig(String configuration) { + if (config != null) { + throw new BuildException("Attribute 'config' has already been set"); } - configLocation = location; + config = configuration; } /** - * Sets flag - whether to omit ignored modules. - * @param omit whether to omit ignored modules + * Sets flag - whether to execute ignored modules. + * @param omit whether to execute ignored modules */ - public void setOmitIgnoredModules(boolean omit) { - omitIgnoredModules = omit; + public void setExecuteIgnoredModules(boolean omit) { + executeIgnoredModules = omit; } //////////////////////////////////////////////////////////////////////////// - // Setters for Checker configuration attributes + // Setters for Root Module's configuration attributes //////////////////////////////////////////////////////////////////////////// /** @@ -283,7 +274,7 @@ try { // output version info in debug mode final ResourceBundle compilationProperties = ResourceBundle - .getBundle("checkstylecompilation"); + .getBundle("checkstylecompilation", Locale.ROOT); final String version = compilationProperties .getString("checkstyle.compile.version"); final String compileTimestamp = compilationProperties @@ -292,12 +283,14 @@ log("compiled on " + compileTimestamp, Project.MSG_VERBOSE); // Check for no arguments - if (fileName == null && fileSets.isEmpty()) { + if (fileName == null + && fileSets.isEmpty() + && paths.isEmpty()) { throw new BuildException( - "Must specify at least one of 'file' or nested 'fileset'.", + "Must specify at least one of 'file' or nested 'fileset' or 'path'.", getLocation()); } - if (configLocation == null) { + if (config == null) { throw new BuildException("Must specify 'config'.", getLocation()); } realExecute(version); @@ -314,52 +307,61 @@ * @param checkstyleVersion Checkstyle compile version. */ private void realExecute(String checkstyleVersion) { - // Create the checker - Checker checker = null; + // Create the root module + RootModule rootModule = null; try { - checker = createChecker(); + rootModule = createRootModule(); // setup the listeners final AuditListener[] listeners = getListeners(); for (AuditListener element : listeners) { - checker.addListener(element); + rootModule.addListener(element); } final SeverityLevelCounter warningCounter = new SeverityLevelCounter(SeverityLevel.WARNING); - checker.addListener(warningCounter); + rootModule.addListener(warningCounter); - processFiles(checker, warningCounter, checkstyleVersion); + processFiles(rootModule, warningCounter, checkstyleVersion); } finally { - if (checker != null) { - checker.destroy(); - } + destroyRootModule(rootModule); + } + } + + /** + * Destroy root module. This method exists only due to bug in cobertura library + * https://github.com/cobertura/cobertura/issues/170 + * @param rootModule Root module that was used to process files + */ + private static void destroyRootModule(RootModule rootModule) { + if (rootModule != null) { + rootModule.destroy(); } } /** - * Scans and processes files by means given checker. - * @param checker Checker to process files - * @param warningCounter Checker's counter of warnings + * Scans and processes files by means given root module. + * @param rootModule Root module to process files + * @param warningCounter Root Module's counter of warnings * @param checkstyleVersion Checkstyle compile version */ - private void processFiles(Checker checker, final SeverityLevelCounter warningCounter, + private void processFiles(RootModule rootModule, final SeverityLevelCounter warningCounter, final String checkstyleVersion) { final long startTime = System.currentTimeMillis(); - final List files = scanFileSets(); + final List files = getFilesToCheck(); final long endTime = System.currentTimeMillis(); log("To locate the files took " + (endTime - startTime) + TIME_SUFFIX, Project.MSG_VERBOSE); log("Running Checkstyle " + checkstyleVersion + " on " + files.size() + " files", Project.MSG_INFO); - log("Using configuration " + configLocation, Project.MSG_VERBOSE); + log("Using configuration " + config, Project.MSG_VERBOSE); final int numErrs; try { final long processingStartTime = System.currentTimeMillis(); - numErrs = checker.process(files); + numErrs = rootModule.process(files); final long processingEndTime = System.currentTimeMillis(); log("To process the files took " + (processingEndTime - processingStartTime) + TIME_SUFFIX, Project.MSG_VERBOSE); @@ -386,37 +388,49 @@ } /** - * Creates new instance of {@code Checker}. - * @return new instance of {@code Checker} + * Creates new instance of the root module. + * @return new instance of the root module */ - private Checker createChecker() { - final Checker checker; + private RootModule createRootModule() { + final RootModule rootModule; try { final Properties props = createOverridingProperties(); - final Configuration config = - ConfigurationLoader.loadConfiguration( - configLocation, - new PropertiesExpander(props), - omitIgnoredModules); - - final DefaultContext context = new DefaultContext(); - final ClassLoader loader = new AntClassLoader(getProject(), - classpath); - context.add("classloader", loader); + final ThreadModeSettings threadModeSettings = + ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE; + final ConfigurationLoader.IgnoredModulesOptions ignoredModulesOptions; + if (executeIgnoredModules) { + ignoredModulesOptions = ConfigurationLoader.IgnoredModulesOptions.EXECUTE; + } + else { + ignoredModulesOptions = ConfigurationLoader.IgnoredModulesOptions.OMIT; + } + + final Configuration configuration = ConfigurationLoader.loadConfiguration(config, + new PropertiesExpander(props), ignoredModulesOptions, threadModeSettings); final ClassLoader moduleClassLoader = Checker.class.getClassLoader(); - context.add("moduleClassLoader", moduleClassLoader); - checker = new Checker(); - checker.contextualize(context); - checker.configure(config); + final ModuleFactory factory = new PackageObjectFactory( + Checker.class.getPackage().getName() + ".", moduleClassLoader); + + rootModule = (RootModule) factory.createModule(configuration.getName()); + rootModule.setModuleClassLoader(moduleClassLoader); + + if (rootModule instanceof Checker) { + final ClassLoader loader = new AntClassLoader(getProject(), + classpath); + + ((Checker) rootModule).setClassLoader(loader); + } + + rootModule.configure(configuration); } catch (final CheckstyleException ex) { - throw new BuildException(String.format(Locale.ROOT, "Unable to create a Checker: " - + "configLocation {%s}, classpath {%s}.", configLocation, classpath), ex); + throw new BuildException(String.format(Locale.ROOT, "Unable to create Root Module: " + + "config {%s}, classpath {%s}.", config, classpath), ex); } - return checker; + return rootModule; } /** @@ -473,7 +487,8 @@ if (formatters.isEmpty()) { final OutputStream debug = new LogOutputStream(this, Project.MSG_DEBUG); final OutputStream err = new LogOutputStream(this, Project.MSG_ERR); - listeners[0] = new DefaultLogger(debug, true, err, true); + listeners[0] = new DefaultLogger(debug, AutomaticBean.OutputStreamOptions.CLOSE, + err, AutomaticBean.OutputStreamOptions.CLOSE); } else { for (int i = 0; i < formatterCount; i++) { @@ -491,33 +506,112 @@ /** * Returns the list of files (full path name) to process. - * @return the list of files included via the filesets. + * @return the list of files included via the fileName, filesets and paths. */ - protected List scanFileSets() { - final List list = Lists.newArrayList(); + private List getFilesToCheck() { + final List allFiles = new ArrayList<>(); if (fileName != null) { // oops we've got an additional one to process, don't // forget it. No sweat, it's fully resolved via the setter. log("Adding standalone file for audit", Project.MSG_VERBOSE); - list.add(new File(fileName)); + allFiles.add(new File(fileName)); + } + + final List filesFromFileSets = scanFileSets(); + allFiles.addAll(filesFromFileSets); + + final List filesFromPaths = scanPaths(); + allFiles.addAll(filesFromPaths); + + return allFiles; + } + + /** + * Retrieves all files from the defined paths. + * @return a list of files defined via paths. + */ + private List scanPaths() { + final List allFiles = new ArrayList<>(); + + for (int i = 0; i < paths.size(); i++) { + final Path currentPath = paths.get(i); + final List pathFiles = scanPath(currentPath, i + 1); + allFiles.addAll(pathFiles); } + + return allFiles; + } + + /** + * Scans the given path and retrieves all files for the given path. + * + * @param path A path to scan. + * @param pathIndex The index of the given path. Used in log messages only. + * @return A list of files, extracted from the given path. + */ + private List scanPath(Path path, int pathIndex) { + final String[] resources = path.list(); + log(pathIndex + ") Scanning path " + path, Project.MSG_VERBOSE); + final List allFiles = new ArrayList<>(); + int concreteFilesCount = 0; + + for (String resource : resources) { + final File file = new File(resource); + if (file.isFile()) { + concreteFilesCount++; + allFiles.add(file); + } + else { + final DirectoryScanner scanner = new DirectoryScanner(); + scanner.setBasedir(file); + scanner.scan(); + final List scannedFiles = retrieveAllScannedFiles(scanner, pathIndex); + allFiles.addAll(scannedFiles); + } + } + + if (concreteFilesCount > 0) { + log(String.format(Locale.ROOT, "%d) Adding %d files from path %s", + pathIndex, concreteFilesCount, path), Project.MSG_VERBOSE); + } + + return allFiles; + } + + /** + * Returns the list of files (full path name) to process. + * @return the list of files included via the filesets. + */ + protected List scanFileSets() { + final List allFiles = new ArrayList<>(); + for (int i = 0; i < fileSets.size(); i++) { final FileSet fileSet = fileSets.get(i); final DirectoryScanner scanner = fileSet.getDirectoryScanner(getProject()); - scanner.scan(); + final List scannedFiles = retrieveAllScannedFiles(scanner, i); + allFiles.addAll(scannedFiles); + } - final String[] names = scanner.getIncludedFiles(); - log(i + ") Adding " + names.length + " files from directory " - + scanner.getBasedir(), Project.MSG_VERBOSE); + return allFiles; + } - for (String element : names) { - final String pathname = scanner.getBasedir() + File.separator - + element; - list.add(new File(pathname)); - } - } + /** + * Retrieves all matched files from the given scanner. + * + * @param scanner A directory scanner. Note, that {@link DirectoryScanner#scan()} + * must be called before calling this method. + * @param logIndex A log entry index. Used only for log messages. + * @return A list of files, retrieved from the given scanner. + */ + private List retrieveAllScannedFiles(DirectoryScanner scanner, int logIndex) { + final String[] fileNames = scanner.getIncludedFiles(); + log(String.format(Locale.ROOT, "%d) Adding %d files from directory %s", + logIndex, fileNames.length, scanner.getBasedir()), Project.MSG_VERBOSE); - return list; + return Arrays.stream(fileNames) + .map(name -> scanner.getBasedir() + File.separator + name) + .map(File::new) + .collect(Collectors.toList()); } /** @@ -525,6 +619,7 @@ * @author Oliver Burn */ public static class FormatterType extends EnumeratedAttribute { + /** My possible values. */ private static final String[] VALUES = {E_XML, E_PLAIN}; @@ -532,6 +627,7 @@ public String[] getValues() { return VALUES.clone(); } + } /** @@ -539,8 +635,9 @@ * @author Oliver Burn */ public static class Formatter { + /** The formatter type. */ - private FormatterType formatterType; + private FormatterType type; /** The file to output to. */ private File toFile; /** Whether or not the write to the named file. */ @@ -551,12 +648,7 @@ * @param type the type */ public void setType(FormatterType type) { - final String val = type.getValue(); - if (!E_XML.equals(val) && !E_PLAIN.equals(val)) { - throw new BuildException("Invalid formatter type: " + val); - } - - formatterType = type; + this.type = type; } /** @@ -582,11 +674,15 @@ * @throws IOException if an error occurs */ public AuditListener createListener(Task task) throws IOException { - if (formatterType != null - && E_XML.equals(formatterType.getValue())) { - return createXmlLogger(task); + final AuditListener listener; + if (type != null + && E_XML.equals(type.getValue())) { + listener = createXmlLogger(task); + } + else { + listener = createDefaultLogger(task); } - return createDefaultLogger(task); + return listener; } /** @@ -596,14 +692,23 @@ * @throws IOException if an error occurs */ private AuditListener createDefaultLogger(Task task) - throws IOException { + throws IOException { + final AuditListener defaultLogger; if (toFile == null || !useFile) { - return new DefaultLogger( + defaultLogger = new DefaultLogger( new LogOutputStream(task, Project.MSG_DEBUG), - true, new LogOutputStream(task, Project.MSG_ERR), true); + AutomaticBean.OutputStreamOptions.CLOSE, + new LogOutputStream(task, Project.MSG_ERR), + AutomaticBean.OutputStreamOptions.CLOSE + ); + } + else { + final FileOutputStream infoStream = new FileOutputStream(toFile); + defaultLogger = + new DefaultLogger(infoStream, AutomaticBean.OutputStreamOptions.CLOSE, + infoStream, AutomaticBean.OutputStreamOptions.NONE); } - final FileOutputStream infoStream = new FileOutputStream(toFile); - return new DefaultLogger(infoStream, true, infoStream, false); + return defaultLogger; } /** @@ -613,18 +718,25 @@ * @throws IOException if an error occurs */ private AuditListener createXmlLogger(Task task) throws IOException { + final AuditListener xmlLogger; if (toFile == null || !useFile) { - return new XMLLogger(new LogOutputStream(task, - Project.MSG_INFO), true); + xmlLogger = new XMLLogger(new LogOutputStream(task, Project.MSG_INFO), + AutomaticBean.OutputStreamOptions.CLOSE); } - return new XMLLogger(new FileOutputStream(toFile), true); + else { + xmlLogger = new XMLLogger(new FileOutputStream(toFile), + AutomaticBean.OutputStreamOptions.CLOSE); + } + return xmlLogger; } + } /** * Represents a property that consists of a key and value. */ public static class Property { + /** The property key. */ private String key; /** The property value. */ @@ -669,10 +781,12 @@ public void setFile(File file) { value = file.getAbsolutePath(); } + } /** Represents a custom listener. */ public static class Listener { + /** Class name of the listener class. */ private String className; @@ -691,5 +805,7 @@ public void setClassname(String name) { className = name; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/ant/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/ant/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/ant/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/ant/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractCheck.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,318 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.api; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; + +/** + * The base class for checks. + * + * @author Oliver Burn + * @see Writing + * your own checks + * @noinspection NoopMethodInAbstractClass + */ +public abstract class AbstractCheck extends AbstractViolationReporter { + + /** Default tab width for column reporting. */ + private static final int DEFAULT_TAB_WIDTH = 8; + + /** + * The check context. + * @noinspection ThreadLocalNotStaticFinal + */ + private final ThreadLocal context = ThreadLocal.withInitial(FileContext::new); + + /** The tokens the check is interested in. */ + private final Set tokens = new HashSet<>(); + + /** The tab width for column reporting. */ + private int tabWidth = DEFAULT_TAB_WIDTH; + + /** + * The class loader to load external classes. Not initialized as this must + * be set by my creator. + */ + private ClassLoader classLoader; + + /** + * Returns the default token a check is interested in. Only used if the + * configuration for a check does not define the tokens. + * @return the default tokens + * @see TokenTypes + */ + public abstract int[] getDefaultTokens(); + + /** + * The configurable token set. + * Used to protect Checks against malicious users who specify an + * unacceptable token set in the configuration file. + * The default implementation returns the check's default tokens. + * @return the token set this check is designed for. + * @see TokenTypes + */ + public abstract int[] getAcceptableTokens(); + + /** + * The tokens that this check must be registered for. + * @return the token set this must be registered for. + * @see TokenTypes + */ + public abstract int[] getRequiredTokens(); + + /** + * Whether comment nodes are required or not. + * @return false as a default value. + */ + public boolean isCommentNodesRequired() { + return false; + } + + /** + * Adds a set of tokens the check is interested in. + * @param strRep the string representation of the tokens interested in + * @noinspection WeakerAccess + */ + public final void setTokens(String... strRep) { + Collections.addAll(tokens, strRep); + } + + /** + * Returns the tokens registered for the check. + * @return the set of token names + */ + public final Set getTokenNames() { + return Collections.unmodifiableSet(tokens); + } + + /** + * Returns the sorted set of {@link LocalizedMessage}. + * @return the sorted set of {@link LocalizedMessage}. + */ + public SortedSet getMessages() { + return new TreeSet<>(context.get().messages); + } + + /** + * Clears the sorted set of {@link LocalizedMessage} of the check. + */ + public final void clearMessages() { + context.get().messages.clear(); + } + + /** + * Initialize the check. This is the time to verify that the check has + * everything required to perform it job. + */ + public void init() { + // No code by default, should be overridden only by demand at subclasses + } + + /** + * Destroy the check. It is being retired from service. + */ + public void destroy() { + // No code by default, should be overridden only by demand at subclasses + } + + /** + * Called before the starting to process a tree. Ideal place to initialize + * information that is to be collected whilst processing a tree. + * @param rootAST the root of the tree + */ + public void beginTree(DetailAST rootAST) { + // No code by default, should be overridden only by demand at subclasses + } + + /** + * Called after finished processing a tree. Ideal place to report on + * information collected whilst processing a tree. + * @param rootAST the root of the tree + */ + public void finishTree(DetailAST rootAST) { + // No code by default, should be overridden only by demand at subclasses + } + + /** + * Called to process a token. + * @param ast the token to process + */ + public void visitToken(DetailAST ast) { + // No code by default, should be overridden only by demand at subclasses + } + + /** + * Called after all the child nodes have been process. + * @param ast the token leaving + */ + public void leaveToken(DetailAST ast) { + // No code by default, should be overridden only by demand at subclasses + } + + /** + * Returns the lines associated with the tree. + * @return the file contents + */ + public final String[] getLines() { + return context.get().fileContents.getLines(); + } + + /** + * Returns the line associated with the tree. + * @param index index of the line + * @return the line from the file contents + */ + public final String getLine(int index) { + return context.get().fileContents.getLine(index); + } + + /** + * Set the file contents associated with the tree. + * @param contents the manager + */ + public final void setFileContents(FileContents contents) { + context.get().fileContents = contents; + } + + /** + * Returns the file contents associated with the tree. + * @return the file contents + * @noinspection WeakerAccess + */ + public final FileContents getFileContents() { + return context.get().fileContents; + } + + /** + * Set the class loader associated with the tree. + * @param classLoader the class loader + */ + public final void setClassLoader(ClassLoader classLoader) { + this.classLoader = classLoader; + } + + /** + * Returns the class loader associated with the tree. + * @return the class loader + */ + public final ClassLoader getClassLoader() { + return classLoader; + } + + /** + * Get tab width to report errors with. + * @return the tab width to report errors with + */ + protected final int getTabWidth() { + return tabWidth; + } + + /** + * Set the tab width to report errors with. + * @param tabWidth an {@code int} value + */ + public final void setTabWidth(int tabWidth) { + this.tabWidth = tabWidth; + } + + /** + * Helper method to log a LocalizedMessage. + * + * @param ast a node to get line id column numbers associated + * with the message + * @param key key to locale message format + * @param args arguments to format + */ + public final void log(DetailAST ast, String key, Object... args) { + // CommonUtils.lengthExpandedTabs returns column number considering tabulation + // characters, it takes line from the file by line number, ast column number and tab + // width as arguments. Returned value is 0-based, but user must see column number starting + // from 1, that is why result of the method CommonUtils.lengthExpandedTabs + // is increased by one. + + final int col = 1 + CommonUtils.lengthExpandedTabs( + getLines()[ast.getLineNo() - 1], ast.getColumnNo(), tabWidth); + context.get().messages.add( + new LocalizedMessage( + ast.getLineNo(), + col, + ast.getColumnNo(), + ast.getType(), + getMessageBundle(), + key, + args, + getSeverityLevel(), + getId(), + getClass(), + getCustomMessages().get(key))); + } + + @Override + public final void log(int line, String key, Object... args) { + context.get().messages.add( + new LocalizedMessage( + line, + getMessageBundle(), + key, + args, + getSeverityLevel(), + getId(), + getClass(), + getCustomMessages().get(key))); + } + + @Override + public final void log(int lineNo, int colNo, String key, + Object... args) { + final int col = 1 + CommonUtils.lengthExpandedTabs( + getLines()[lineNo - 1], colNo, tabWidth); + context.get().messages.add( + new LocalizedMessage( + lineNo, + col, + getMessageBundle(), + key, + args, + getSeverityLevel(), + getId(), + getClass(), + getCustomMessages().get(key))); + } + + /** + * The actual context holder. + */ + private static class FileContext { + + /** The sorted set for collecting messages. */ + private final SortedSet messages = new TreeSet<>(); + + /** The current file contents. */ + private FileContents fileContents; + + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractFileSetCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractFileSetCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractFileSetCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractFileSetCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,10 +21,8 @@ import java.io.File; import java.util.Arrays; -import java.util.List; import java.util.SortedSet; - -import org.apache.commons.lang3.ArrayUtils; +import java.util.TreeSet; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -33,27 +31,31 @@ * * @author lkuehne * @author oliver + * @noinspection NoopMethodInAbstractClass */ public abstract class AbstractFileSetCheck extends AbstractViolationReporter implements FileSetCheck { - /** Collects the error messages. */ - private final LocalizedMessages messageCollector = new LocalizedMessages(); + /** + * Collects the error messages. + */ + private static final ThreadLocal> MESSAGE_COLLECTOR = + ThreadLocal.withInitial(TreeSet::new); /** The dispatcher errors are fired to. */ private MessageDispatcher messageDispatcher; /** The file extensions that are accepted by this filter. */ - private String[] fileExtensions = ArrayUtils.EMPTY_STRING_ARRAY; + private String[] fileExtensions = CommonUtils.EMPTY_STRING_ARRAY; /** * Called to process a file that matches the specified file extensions. * @param file the file to be processed - * @param lines an immutable list of the contents of the file. + * @param fileText the contents of the file. * @throws CheckstyleException if error condition within Checkstyle occurs. */ - protected abstract void processFiltered(File file, List lines) + protected abstract void processFiltered(File file, FileText fileText) throws CheckstyleException; @Override @@ -72,14 +74,17 @@ } @Override - public final SortedSet process(File file, List lines) + public final SortedSet process(File file, FileText fileText) throws CheckstyleException { - messageCollector.reset(); + final SortedSet messages = MESSAGE_COLLECTOR.get(); + messages.clear(); // Process only what interested in if (CommonUtils.matchesFileExtension(file, fileExtensions)) { - processFiltered(file, lines); + processFiltered(file, fileText); } - return messageCollector.getMessages(); + final SortedSet result = new TreeSet<>(messages); + messages.clear(); + return result; } @Override @@ -103,6 +108,7 @@ } /** + * Makes copy of file extensions and returns them. * @return file extensions that identify the files that pass the * filter of this FileSetCheck. */ @@ -135,14 +141,11 @@ } /** - * Returns the collector for violation messages. - * Subclasses can use the collector to find out the violation - * messages to fire via the message dispatcher. - * - * @return the collector for localized messages. + * Adds the sorted set of {@link LocalizedMessage} to the message collector. + * @param messages the sorted set of {@link LocalizedMessage}. */ - protected final LocalizedMessages getMessageCollector() { - return messageCollector; + protected static void addMessages(SortedSet messages) { + MESSAGE_COLLECTOR.get().addAll(messages); } @Override @@ -153,7 +156,7 @@ @Override public final void log(int lineNo, int colNo, String key, Object... args) { - messageCollector.add( + MESSAGE_COLLECTOR.get().add( new LocalizedMessage(lineNo, colNo, getMessageBundle(), @@ -172,9 +175,9 @@ * @param fileName the audited file */ protected final void fireErrors(String fileName) { - final SortedSet errors = messageCollector - .getMessages(); - messageCollector.reset(); - getMessageDispatcher().fireErrors(fileName, errors); + final SortedSet errors = new TreeSet<>(MESSAGE_COLLECTOR.get()); + MESSAGE_COLLECTOR.get().clear(); + messageDispatcher.fireErrors(fileName, errors); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractLoader.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractLoader.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractLoader.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractLoader.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,127 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.api; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParserFactory; - -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; - -import com.google.common.collect.Maps; - -/** - * Contains the common implementation of a loader, for loading a configuration - * from an XML file. - *

    - * The error handling policy can be described as being austere, dead set, - * disciplinary, dour, draconian, exacting, firm, forbidding, grim, hard, hard- - * boiled, harsh, harsh, in line, iron-fisted, no-nonsense, oppressive, - * persnickety, picky, prudish, punctilious, puritanical, rigid, rigorous, - * scrupulous, set, severe, square, stern, stickler, straight, strait-laced, - * stringent, stuffy, stuffy, tough, unpermissive, unsparing and uptight. - *

    - * - * @author Oliver Burn - */ -public abstract class AbstractLoader - extends DefaultHandler { - /** Maps public id to resolve to resource name for the DTD. */ - private final Map publicIdToResourceNameMap; - /** Parser to read XML files. **/ - private final XMLReader parser; - - /** - * Creates a new instance. - * @param publicId the public ID for the DTD to resolve - * @param dtdResourceName the resource for the DTD - * @throws SAXException if an error occurs - * @throws ParserConfigurationException if an error occurs - */ - protected AbstractLoader(String publicId, String dtdResourceName) - throws SAXException, ParserConfigurationException { - this(new HashMap(1)); - publicIdToResourceNameMap.put(publicId, dtdResourceName); - } - - /** - * Creates a new instance. - * @param publicIdToResourceNameMap maps public IDs to DTD resource names - * @throws SAXException if an error occurs - * @throws ParserConfigurationException if an error occurs - */ - protected AbstractLoader(Map publicIdToResourceNameMap) - throws SAXException, ParserConfigurationException { - this.publicIdToResourceNameMap = - Maps.newHashMap(publicIdToResourceNameMap); - final SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setValidating(true); - factory.setNamespaceAware(true); - parser = factory.newSAXParser().getXMLReader(); - parser.setContentHandler(this); - parser.setEntityResolver(this); - parser.setErrorHandler(this); - } - - /** - * Parses the specified input source. - * @param inputSource the input source to parse. - * @throws IOException if an error occurs - * @throws SAXException in an error occurs - */ - public void parseInputSource(InputSource inputSource) - throws IOException, SAXException { - parser.parse(inputSource); - } - - @Override - public InputSource resolveEntity(String publicId, String systemId) - throws SAXException, IOException { - if (publicIdToResourceNameMap.keySet().contains(publicId)) { - final String dtdResourceName = - publicIdToResourceNameMap.get(publicId); - final ClassLoader loader = - getClass().getClassLoader(); - final InputStream dtdIs = - loader.getResourceAsStream(dtdResourceName); - - return new InputSource(dtdIs); - } - return super.resolveEntity(publicId, systemId); - } - - @Override - public void error(SAXParseException exception) throws SAXException { - throw exception; - } - - @Override - public void fatalError(SAXParseException exception) throws SAXException { - throw exception; - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractViolationReporter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractViolationReporter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractViolationReporter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AbstractViolationReporter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,17 +21,17 @@ import java.util.Map; -import com.google.common.annotations.VisibleForTesting; - /** * Serves as an abstract base class for all modules that report inspection * findings. Such modules have a Severity level which is used for the * {@link LocalizedMessage localized messages} that are created by the module. * * @author lkuehne + * @noinspection NoopMethodInAbstractClass */ public abstract class AbstractViolationReporter extends AutomaticBean { + /** The severity level of any violations found. */ private SeverityLevel severityLevel = SeverityLevel.ERROR; @@ -43,6 +43,7 @@ * @return the severity level * @see SeverityLevel * @see LocalizedMessage#getSeverityLevel + * @noinspection WeakerAccess */ public final SeverityLevel getSeverityLevel() { return severityLevel; @@ -63,6 +64,7 @@ * Get the severity level's name. * * @return the check's severity level name. + * @noinspection WeakerAccess */ public final String getSeverity() { return severityLevel.getName(); @@ -120,27 +122,23 @@ * @return name of a resource bundle that contains the messages * used by the module. */ - @VisibleForTesting - static String getMessageBundle(final String className) { + private static String getMessageBundle(final String className) { + final String messageBundle; final int endIndex = className.lastIndexOf('.'); final String messages = "messages"; - if (endIndex < 0) { - return messages; + if (endIndex == -1) { + messageBundle = messages; } - final String packageName = className.substring(0, endIndex); - return packageName + "." + messages; + else { + final String packageName = className.substring(0, endIndex); + messageBundle = packageName + "." + messages; + } + return messageBundle; } - /** - * Helper method to log a LocalizedMessage. - * - * @param ast a node to get line id column numbers associated - * with the message - * @param key key to locale message format - * @param args arguments to format - */ - protected final void log(DetailAST ast, String key, Object... args) { - log(ast.getLineNo(), ast.getColumnNo(), key, args); + @Override + protected void finishLocalSetup() throws CheckstyleException { + // No code by default } /** @@ -152,6 +150,8 @@ * * @see java.text.MessageFormat */ + // -@cs[CustomDeclarationOrder] CustomDeclarationOrder does not treat groups of + // overloaded methods. See https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/414 public abstract void log(int line, String key, Object... args); /** @@ -164,6 +164,9 @@ * * @see java.text.MessageFormat */ + // -@cs[CustomDeclarationOrder] CustomDeclarationOrder does not treat groups of + // overloaded methods. See https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/414 public abstract void log(int line, int col, String key, Object... args); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AuditEvent.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AuditEvent.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AuditEvent.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AuditEvent.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -37,9 +37,11 @@ * * @author Stephane Bailliez * @see AuditListener + * @noinspection SerializableHasSerializationMethods */ public final class AuditEvent extends EventObject { + /** Record a version. */ private static final long serialVersionUID = -3774725606973812736L; /** Filename event associated with. **/ @@ -78,6 +80,7 @@ } /** + * Returns name of file being audited. * @return the file name currently being audited or null if there is * no relation to a file. */ @@ -115,15 +118,15 @@ * @return the audit event severity level */ public SeverityLevel getSeverityLevel() { - if (localizedMessage == null) { - return SeverityLevel.INFO; - } - else { - return localizedMessage.getSeverityLevel(); + SeverityLevel severityLevel = SeverityLevel.INFO; + if (localizedMessage != null) { + severityLevel = localizedMessage.getSeverityLevel(); } + return severityLevel; } /** + * Returns id of module. * @return the identifier of the module that generated the event. Can return * null. */ @@ -146,4 +149,5 @@ public LocalizedMessage getLocalizedMessage() { return localizedMessage; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AuditListener.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AuditListener.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AuditListener.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AuditListener.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -35,6 +35,7 @@ */ public interface AuditListener extends EventListener { + /** * Notify that the audit is about to start. * @param event the event details @@ -71,4 +72,5 @@ * @param throwable details of the exception */ void addException(AuditEvent event, Throwable throwable); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AutomaticBean.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AutomaticBean.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/AutomaticBean.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/AutomaticBean.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,10 +21,13 @@ import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; +import java.net.URI; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.StringTokenizer; +import java.util.regex.Pattern; import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.beanutils.ConversionException; @@ -42,19 +45,52 @@ import org.apache.commons.beanutils.converters.LongConverter; import org.apache.commons.beanutils.converters.ShortConverter; -import com.google.common.collect.Lists; +import com.puppycrawl.tools.checkstyle.checks.naming.AccessModifier; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * A Java Bean that implements the component lifecycle interfaces by * calling the bean's setters for all configuration attributes. * @author lkuehne */ -public class AutomaticBean +// -@cs[AbstractClassName] We can not brake compatibility with previous versions. +public abstract class AutomaticBean implements Configurable, Contextualizable { + + /** + * Enum to specify behaviour regarding ignored modules. + */ + public enum OutputStreamOptions { + + /** + * Close stream in the end. + */ + CLOSE, + + /** + * Do nothing in the end. + */ + NONE + + } + + /** Comma separator for StringTokenizer. */ + private static final String COMMA_SEPARATOR = ","; + /** The configuration of this bean. */ private Configuration configuration; /** + * Provides a hook to finish the part of this component's setup that + * was not handled by the bean introspection. + *

    + * The default implementation does nothing. + *

    + * @throws CheckstyleException if there is a configuration error. + */ + protected abstract void finishLocalSetup() throws CheckstyleException; + + /** * Creates a BeanUtilsBean that is configured to use * type converters that throw a ConversionException * instead of using the default value when something @@ -65,6 +101,19 @@ private static BeanUtilsBean createBeanUtilsBean() { final ConvertUtilsBean cub = new ConvertUtilsBean(); + registerIntegralTypes(cub); + registerCustomTypes(cub); + + return new BeanUtilsBean(cub, new PropertyUtilsBean()); + } + + /** + * Register basic types of JDK like boolean, int, and String to use with BeanUtils. All these + * types are found in the {@code java.lang} package. + * @param cub + * Instance of {@link ConvertUtilsBean} to register types with. + */ + private static void registerIntegralTypes(ConvertUtilsBean cub) { cub.register(new BooleanConverter(), Boolean.TYPE); cub.register(new BooleanConverter(), Boolean.class); cub.register(new ArrayConverter( @@ -101,8 +150,20 @@ // BigDecimal, BigInteger, Class, Date, String, Time, TimeStamp // do not use defaults in the default configuration of ConvertUtilsBean + } - return new BeanUtilsBean(cub, new PropertyUtilsBean()); + /** + * Register custom types of JDK like URI and Checkstyle specific classes to use with BeanUtils. + * None of these types should be found in the {@code java.lang} package. + * @param cub + * Instance of {@link ConvertUtilsBean} to register types with. + */ + private static void registerCustomTypes(ConvertUtilsBean cub) { + cub.register(new PatternConverter(), Pattern.class); + cub.register(new SeverityLevelConverter(), SeverityLevel.class); + cub.register(new ScopeConverter(), Scope.class); + cub.register(new UriConverter(), URI.class); + cub.register(new RelaxedAccessModifierArrayConverter(), AccessModifier[].class); } /** @@ -116,13 +177,11 @@ * is called for each {@link Configuration#getChildren child Configuration} * of {@code configuration}. * - * @param config the configuration to use. - * @throws CheckstyleException if there is a configuration error. * @see Configurable */ @Override public final void configure(Configuration config) - throws CheckstyleException { + throws CheckstyleException { configuration = config; final String[] attributes = config.getAttributeNames(); @@ -151,7 +210,6 @@ */ private void tryCopyProperty(String moduleName, String key, Object value, boolean recheck) throws CheckstyleException { - final BeanUtilsBean beanUtils = createBeanUtilsBean(); try { @@ -189,15 +247,11 @@ /** * Implements the Contextualizable interface using bean introspection. - * - * @param context the context. - * @throws CheckstyleException if there is a contextualization error. * @see Contextualizable */ @Override public final void contextualize(Context context) - throws CheckstyleException { - + throws CheckstyleException { final Collection attributes = context.getAttributeNames(); for (final String key : attributes) { @@ -216,29 +270,80 @@ } /** - * Provides a hook to finish the part of this component's setup that - * was not handled by the bean introspection. - *

    - * The default implementation does nothing. - *

    - * @throws CheckstyleException if there is a configuration error. - */ - protected void finishLocalSetup() throws CheckstyleException { - // No code by default, should be overridden only by demand at subclasses - } - - /** * Called by configure() for every child of this component's Configuration. *

    - * The default implementation does nothing. + * The default implementation throws {@link CheckstyleException} if + * {@code childConf} is {@code null} because it doesn't support children. It + * must be overridden to validate and support children that are wanted. *

    + * * @param childConf a child of this component's Configuration * @throws CheckstyleException if there is a configuration error. * @see Configuration#getChildren */ protected void setupChild(Configuration childConf) - throws CheckstyleException { - // No code by default, should be overridden only by demand at subclasses + throws CheckstyleException { + if (childConf != null) { + throw new CheckstyleException(childConf.getName() + " is not allowed as a child in " + + configuration.getName() + ". Please review 'Parent Module' section " + + "for this Check in web documentation if Check is standard."); + } + } + + /** A converter that converts strings to patterns. */ + private static class PatternConverter implements Converter { + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public Object convert(Class type, Object value) { + return CommonUtils.createPattern(value.toString()); + } + + } + + /** A converter that converts strings to severity level. */ + private static class SeverityLevelConverter implements Converter { + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public Object convert(Class type, Object value) { + return SeverityLevel.getInstance(value.toString()); + } + + } + + /** A converter that converts strings to scope. */ + private static class ScopeConverter implements Converter { + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public Object convert(Class type, Object value) { + return Scope.getInstance(value.toString()); + } + + } + + /** A converter that converts strings to uri. */ + private static class UriConverter implements Converter { + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public Object convert(Class type, Object value) { + final String url = value.toString(); + URI result = null; + + if (!CommonUtils.isBlank(url)) { + try { + result = CommonUtils.getUriByFilename(url); + } + catch (CheckstyleException ex) { + throw new IllegalArgumentException(ex); + } + } + + return result; + } + } /** @@ -247,13 +352,14 @@ * with this characters. */ private static class RelaxedStringArrayConverter implements Converter { + @SuppressWarnings({"unchecked", "rawtypes"}) @Override public Object convert(Class type, Object value) { // Convert to a String and trim it for the tokenizer. final StringTokenizer tokenizer = new StringTokenizer( - value.toString().trim(), ","); - final List result = Lists.newArrayList(); + value.toString().trim(), COMMA_SEPARATOR); + final List result = new ArrayList<>(); while (tokenizer.hasMoreTokens()) { final String token = tokenizer.nextToken(); @@ -262,5 +368,32 @@ return result.toArray(new String[result.size()]); } + } + + /** + * A converter that converts strings to {@link AccessModifier}. + * This implementation does not care whether the array elements contain characters like '_'. + * The normal {@link ArrayConverter} class has problems with this character. + */ + private static class RelaxedAccessModifierArrayConverter implements Converter { + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Override + public Object convert(Class type, Object value) { + // Converts to a String and trims it for the tokenizer. + final StringTokenizer tokenizer = new StringTokenizer( + value.toString().trim(), COMMA_SEPARATOR); + final List result = new ArrayList<>(); + + while (tokenizer.hasMoreTokens()) { + final String token = tokenizer.nextToken(); + result.add(AccessModifier.getInstance(token.trim())); + } + + return result.toArray(new AccessModifier[result.size()]); + } + + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/BeforeExecutionFileFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/BeforeExecutionFileFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/BeforeExecutionFileFilter.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/BeforeExecutionFileFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,36 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.api; + +/** + * An interface for before execution file filtering events. + * @author Richard Veach + */ +@FunctionalInterface +public interface BeforeExecutionFileFilter { + + /** + * Determines whether or not a before execution file filtered event is accepted. + * @param uri the uri to filter. + * @return true if the event is accepted. + */ + boolean accept(String uri); + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/BeforeExecutionFileFilterSet.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/BeforeExecutionFileFilterSet.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/BeforeExecutionFileFilterSet.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/BeforeExecutionFileFilterSet.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,84 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.api; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A before execution file filter set applies filters to events. + * If a before execution file filter in the set rejects an event, then the + * event is rejected. Otherwise, the event is accepted. + * @author Richard Veach + */ +public final class BeforeExecutionFileFilterSet + implements BeforeExecutionFileFilter { + + /** Filter set. */ + private final Set beforeExecutionFileFilters = new HashSet<>(); + + /** + * Adds a Filter to the set. + * @param filter the Filter to add. + */ + public void addBeforeExecutionFileFilter(BeforeExecutionFileFilter filter) { + beforeExecutionFileFilters.add(filter); + } + + /** + * Removes filter. + * @param filter filter to remove. + */ + public void removeBeforeExecutionFileFilter(BeforeExecutionFileFilter filter) { + beforeExecutionFileFilters.remove(filter); + } + + /** + * Returns the Filters of the filter set. + * @return the Filters of the filter set. + */ + public Set getBeforeExecutionFileFilters() { + return Collections.unmodifiableSet(beforeExecutionFileFilters); + } + + @Override + public String toString() { + return beforeExecutionFileFilters.toString(); + } + + @Override + public boolean accept(String uri) { + boolean result = true; + for (BeforeExecutionFileFilter filter : beforeExecutionFileFilters) { + if (!filter.accept(uri)) { + result = false; + break; + } + } + return result; + } + + /** Clears the BeforeExecutionFileFilterSet. */ + public void clear() { + beforeExecutionFileFilters.clear(); + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Check.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Check.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Check.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Check.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,268 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.api; - -import java.util.Collections; -import java.util.Set; - -import org.apache.commons.lang3.ArrayUtils; - -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; - -/** - * The base class for checks. - * - * @author Oliver Burn - * @see Writing - * your own checks - */ -public abstract class Check extends AbstractViolationReporter { - /** Default tab width for column reporting. */ - private static final int DEFAULT_TAB_WIDTH = 8; - - /** The tokens the check is interested in. */ - private final Set tokens = Sets.newHashSet(); - - /** The current file contents. */ - private FileContents fileContents; - - /** The object for collecting messages. */ - private LocalizedMessages messages; - - /** The tab width for column reporting. */ - private int tabWidth = DEFAULT_TAB_WIDTH; - - /** - * The class loader to load external classes. Not initialized as this must - * be set by my creator. - */ - private ClassLoader classLoader; - - /** - * Returns the default token a check is interested in. Only used if the - * configuration for a check does not define the tokens. - * @return the default tokens - * @see TokenTypes - */ - public abstract int[] getDefaultTokens(); - - /** - * Whether comment nodes are required or not. - * @return false as a default value. - */ - public boolean isCommentNodesRequired() { - return false; - } - - /** - * The configurable token set. - * Used to protect Checks against malicious users who specify an - * unacceptable token set in the configuration file. - * The default implementation returns the check's default tokens. - * @return the token set this check is designed for. - * @see TokenTypes - */ - public int[] getAcceptableTokens() { - final int[] defaultTokens = getDefaultTokens(); - final int[] copy = new int[defaultTokens.length]; - System.arraycopy(defaultTokens, 0, copy, 0, defaultTokens.length); - return copy; - } - - /** - * The tokens that this check must be registered for. - * @return the token set this must be registered for. - * @see TokenTypes - */ - public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; - } - - /** - * Adds a set of tokens the check is interested in. - * @param strRep the string representation of the tokens interested in - */ - public final void setTokens(String... strRep) { - Collections.addAll(tokens, strRep); - } - - /** - * Returns the tokens registered for the check. - * @return the set of token names - */ - public final Set getTokenNames() { - return Collections.unmodifiableSet(tokens); - } - - /** - * Set the global object used to collect messages. - * @param messages the messages to log with - */ - public final void setMessages(LocalizedMessages messages) { - this.messages = messages; - } - - /** - * Initialize the check. This is the time to verify that the check has - * everything required to perform it job. - */ - public void init() { - // No code by default, should be overridden only by demand at subclasses - } - - /** - * Destroy the check. It is being retired from service. - */ - public void destroy() { - // No code by default, should be overridden only by demand at subclasses - } - - /** - * Called before the starting to process a tree. Ideal place to initialize - * information that is to be collected whilst processing a tree. - * @param rootAST the root of the tree - */ - public void beginTree(DetailAST rootAST) { - // No code by default, should be overridden only by demand at subclasses - } - - /** - * Called after finished processing a tree. Ideal place to report on - * information collected whilst processing a tree. - * @param rootAST the root of the tree - */ - public void finishTree(DetailAST rootAST) { - // No code by default, should be overridden only by demand at subclasses - } - - /** - * Called to process a token. - * @param ast the token to process - */ - public void visitToken(DetailAST ast) { - // No code by default, should be overridden only by demand at subclasses - } - - /** - * Called after all the child nodes have been process. - * @param ast the token leaving - */ - public void leaveToken(DetailAST ast) { - // No code by default, should be overridden only by demand at subclasses - } - - /** - * Returns the lines associated with the tree. - * @return the file contents - */ - public final String[] getLines() { - return fileContents.getLines(); - } - - /** - * Returns the line associated with the tree. - * @param index index of the line - * @return the line from the file contents - */ - public final String getLine(int index) { - return fileContents.getLine(index); - } - - /** - * Set the file contents associated with the tree. - * @param contents the manager - */ - public final void setFileContents(FileContents contents) { - fileContents = contents; - } - - /** - * Returns the file contents associated with the tree. - * @return the file contents - */ - public final FileContents getFileContents() { - return fileContents; - } - - /** - * Set the class loader associated with the tree. - * @param classLoader the class loader - */ - public final void setClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; - } - - /** - * Returns the class loader associated with the tree. - * @return the class loader - */ - public final ClassLoader getClassLoader() { - return classLoader; - } - - /** - * Get tab width to report errors with. - * @return the tab width to report errors with - */ - protected final int getTabWidth() { - return tabWidth; - } - - /** - * Set the tab width to report errors with. - * @param tabWidth an {@code int} value - */ - public final void setTabWidth(int tabWidth) { - this.tabWidth = tabWidth; - } - - @Override - public final void log(int line, String key, Object... args) { - messages.add( - new LocalizedMessage( - line, - getMessageBundle(), - key, - args, - getSeverityLevel(), - getId(), - getClass(), - getCustomMessages().get(key))); - } - - @Override - public final void log(int lineNo, int colNo, String key, - Object... args) { - final int col = 1 + CommonUtils.lengthExpandedTabs( - getLines()[lineNo - 1], colNo, tabWidth); - messages.add( - new LocalizedMessage( - lineNo, - col, - getMessageBundle(), - key, - args, - getSeverityLevel(), - getId(), - getClass(), - getCustomMessages().get(key))); - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/CheckstyleException.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/CheckstyleException.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/CheckstyleException.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/CheckstyleException.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,8 +23,10 @@ * Represents an error condition within Checkstyle. * * @author Oliver Burn + * @noinspection CheckedExceptionClass */ public class CheckstyleException extends Exception { + /** For Serialisation that will never happen. */ private static final long serialVersionUID = -3517342299748221108L; @@ -47,4 +49,5 @@ public CheckstyleException(String message, Throwable cause) { super(message, cause); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Comment.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Comment.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Comment.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Comment.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,12 +19,15 @@ package com.puppycrawl.tools.checkstyle.api; +import java.util.Arrays; + /** * Representation of the comment block. * * @author o_sukhodolsky */ public class Comment implements TextBlock { + /** Text of the comment. */ private final String[] text; @@ -98,8 +101,11 @@ @Override public String toString() { - final String separator = ":"; - return "Comment[" + startLineNo + separator + startColNo + "-" - + endLineNo + separator + endColNo + "]"; + return "Comment[text=" + Arrays.toString(text) + + ", startLineNo=" + startLineNo + + ", endLineNo=" + endLineNo + + ", startColNo=" + startColNo + + ", endColNo=" + endColNo + ']'; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Configurable.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Configurable.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Configurable.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Configurable.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -29,11 +29,14 @@ * href="http://avalon.apache.org/closed.html">Jakarta's Avalon framework. * @author lkuehne */ +@FunctionalInterface public interface Configurable { + /** * Configures this component. * @param configuration the configuration to use. * @throws CheckstyleException if there is a configuration error. */ void configure(Configuration configuration) throws CheckstyleException; + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Configuration.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Configuration.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Configuration.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Configuration.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,8 +20,7 @@ package com.puppycrawl.tools.checkstyle.api; import java.io.Serializable; - -import com.google.common.collect.ImmutableMap; +import java.util.Map; /** * A Configuration is used to configure a Configurable component. The general @@ -30,6 +29,7 @@ * @author lkuehne */ public interface Configuration extends Serializable { + /** * The set of attribute names. * @return The set of attribute names, never null. @@ -61,5 +61,6 @@ * for this configuration. * @return unmodifiable map containing custom messages */ - ImmutableMap getMessages(); + Map getMessages(); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Context.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Context.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Context.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Context.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,7 @@ package com.puppycrawl.tools.checkstyle.api; -import com.google.common.collect.ImmutableCollection; +import java.util.Collection; /** * A context to be used in subcomponents. The general idea of @@ -29,6 +29,7 @@ * @see Contextualizable */ public interface Context { + /** * Searches for the value with the specified attribute key in this context. * @param key the attribute key. @@ -40,5 +41,6 @@ * Returns the names of all attributes of this context. * @return the names of all attributes of this context. */ - ImmutableCollection getAttributeNames(); + Collection getAttributeNames(); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Contextualizable.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Contextualizable.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Contextualizable.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Contextualizable.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -30,11 +30,14 @@ * href="http://avalon.apache.org/closed.html">Jakarta's Avalon framework. * @author lkuehne */ +@FunctionalInterface public interface Contextualizable { + /** * Sets the context for this Component. * @param context the context. * @throws CheckstyleException if there is a contextualization error. */ void contextualize(Context context) throws CheckstyleException; + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/DetailAST.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/DetailAST.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/DetailAST.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/DetailAST.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,20 +24,18 @@ import antlr.CommonASTWithHiddenTokens; import antlr.Token; import antlr.collections.AST; -import com.google.common.annotations.VisibleForTesting; import com.puppycrawl.tools.checkstyle.utils.TokenUtils; /** - * An extension of the CommonAST that records the line and column - * number. The idea was taken from Java Guru - * FAQ: How can I include line numbers in automatically generated - * ASTs?. + * An extension of the CommonAST that records the line and column number. + * * @author Oliver Burn * @author lkuehne * @see ANTLR Website + * @noinspection FieldNotUsedInToString, SerializableHasSerializationMethods */ public final class DetailAST extends CommonASTWithHiddenTokens { + private static final long serialVersionUID = -2580884815577559874L; /** Constant to indicate if not calculated the child count. */ @@ -84,7 +82,8 @@ @Override public void setFirstChild(AST ast) { - childCount = NOT_INITIALIZED; + clearBranchTokenTypes(); + clearChildCountCache(this); super.setFirstChild(ast); if (ast != null) { ((DetailAST) ast).setParent(this); @@ -93,6 +92,8 @@ @Override public void setNextSibling(AST ast) { + clearBranchTokenTypes(); + clearChildCountCache(parent); super.setNextSibling(ast); if (ast != null && parent != null) { ((DetailAST) ast).setParent(parent); @@ -108,8 +109,10 @@ * DetailAST object. */ public void addPreviousSibling(DetailAST ast) { + clearBranchTokenTypes(); + clearChildCountCache(parent); if (ast != null) { - ast.setParent(parent); + //parent is set in setNextSibling or parent.setFirstChild final DetailAST previousSiblingNode = previousSibling; if (previousSiblingNode != null) { @@ -131,8 +134,10 @@ * DetailAST object. */ public void addNextSibling(DetailAST ast) { + clearBranchTokenTypes(); + clearChildCountCache(parent); if (ast != null) { - ast.setParent(parent); + //parent is set in setNextSibling final DetailAST nextSibling = getNextSibling(); if (nextSibling != null) { @@ -147,11 +152,13 @@ @Override public void addChild(AST ast) { - super.addChild(ast); + clearBranchTokenTypes(); + clearChildCountCache(this); if (ast != null) { ((DetailAST) ast).setParent(this); - getFirstChild().setParent(this); + ((DetailAST) ast).previousSibling = getLastChild(); } + super.addChild(ast); } /** @@ -192,14 +199,18 @@ * Set the parent token. * @param parent the parent token */ - @VisibleForTesting - void setParent(DetailAST parent) { - this.parent = parent; - final DetailAST nextSibling = getNextSibling(); - if (nextSibling != null) { - nextSibling.setParent(parent); - nextSibling.previousSibling = this; - } + private void setParent(DetailAST parent) { + DetailAST instance = this; + do { + instance.clearBranchTokenTypes(); + instance.parent = parent; + final DetailAST nextSibling = instance.getNextSibling(); + if (nextSibling != null) { + nextSibling.previousSibling = instance; + } + + instance = nextSibling; + } while (instance != null); } /** @@ -222,11 +233,11 @@ // with initialize(String text) resultNo = findLineNo(getFirstChild()); - if (resultNo < 0) { + if (resultNo == -1) { resultNo = findLineNo(getNextSibling()); } } - if (resultNo < 0) { + if (resultNo == -1) { resultNo = lineNo; } return resultNo; @@ -253,11 +264,11 @@ // with initialize(String text) resultNo = findColumnNo(getFirstChild()); - if (resultNo < 0) { + if (resultNo == -1) { resultNo = findColumnNo(getNextSibling()); } } - if (resultNo < 0) { + if (resultNo == -1) { resultNo = columnNo; } return resultNo; @@ -329,12 +340,12 @@ } /** + * Returns token type with branch. * @return the token types that occur in the branch as a sorted set. */ private BitSet getBranchTokenTypes() { // lazy init if (branchTokenTypes == null) { - branchTokenTypes = new BitSet(); branchTokenTypes.set(getType()); @@ -400,4 +411,26 @@ return (DetailAST) super.getFirstChild(); } + /** + * Clears the child count for the ast instance. + * @param ast The ast to clear. + */ + private static void clearChildCountCache(DetailAST ast) { + if (ast != null) { + ast.childCount = NOT_INITIALIZED; + } + } + + /** + * Clears branchTokenTypes cache for all parents of the current DetailAST instance, and the + * child count for the current DetailAST instance. + */ + private void clearBranchTokenTypes() { + DetailAST prevParent = parent; + while (prevParent != null) { + prevParent.branchTokenTypes = null; + prevParent = prevParent.parent; + } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/DetailNode.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/DetailNode.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/DetailNode.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/DetailNode.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,17 +19,16 @@ package com.puppycrawl.tools.checkstyle.api; -import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocNodeImpl; - /** * DetailNode is used to construct tree during parsing Javadoc comments. * Contains array of children, parent node and other useful fields. * * @author Baratali Izmailov - * @see JavadocNodeImpl + * @see com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocNodeImpl * @see com.puppycrawl.tools.checkstyle.checks.javadoc.AbstractJavadocCheck */ public interface DetailNode { + /** * Node type. * @return node type. @@ -72,4 +71,5 @@ * @return index */ int getIndex(); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/ExternalResourceHolder.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/ExternalResourceHolder.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/ExternalResourceHolder.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/ExternalResourceHolder.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,51 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.api; + +import java.util.Set; + +import com.puppycrawl.tools.checkstyle.Checker; + +/** + * The following interface should be implemented by each module (inheritor of + * {@link AbstractCheck}, implementor of {@link FileSetCheck}, or {@link Filter}) which uses + * external resources of any kind for its configuration. Such modules must declare external + * resource locations as a set of {@link String} which will be returned from + * {@link #getExternalResourceLocations}. This allows Checkstyle to invalidate (clear) cache + * when the content of at least one external configuration resource of the module is changed. + * + * @author Andrei Selkin + */ +@FunctionalInterface +public interface ExternalResourceHolder { + + /** + * Returns a set of external configuration resource locations which are used by the module. + * ATTENTION! + * If 'getExternalResourceLocations()' return null, there will be + * {@link NullPointerException} in {@link Checker}. + * Such behaviour will signal that your module (check or filter) is designed incorrectly. + * It make sense to return an empty set from 'getExternalResourceLocations()' + * only for composite modules like {@link com.puppycrawl.tools.checkstyle.TreeWalker}. + * @return a set of external configuration resource locations which are used by the module. + */ + Set getExternalResourceLocations(); + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/FileContents.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/FileContents.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/FileContents.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/FileContents.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,16 +20,17 @@ package com.puppycrawl.tools.checkstyle.api; import java.io.File; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.puppycrawl.tools.checkstyle.grammars.CommentListener; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * Represents the contents of a file. @@ -37,6 +38,7 @@ * @author Oliver Burn */ public final class FileContents implements CommentListener { + /** * The pattern to match a single line comment containing only the comment * itself -- no code. @@ -55,16 +57,15 @@ /** Map of the Javadoc comments indexed on the last line of the comment. * The hack is it assumes that there is only one Javadoc comment per line. */ - private final Map javadocComments = Maps.newHashMap(); + private final Map javadocComments = new HashMap<>(); /** Map of the C++ comments indexed on the first line of the comment. */ - private final Map cppComments = - Maps.newHashMap(); + private final Map cppComments = new HashMap<>(); /** * Map of the C comments indexed on the first line of the comment to a list * of comments on that line. */ - private final Map> clangComments = Maps.newHashMap(); + private final Map> clangComments = new HashMap<>(); /** * Creates a new {@code FileContents} instance. @@ -77,7 +78,7 @@ @Deprecated public FileContents(String filename, String... lines) { fileName = filename; - text = FileText.fromLines(new File(filename), Arrays.asList(lines)); + text = new FileText(new File(filename), Arrays.asList(lines)); } /** @@ -93,21 +94,15 @@ @Override public void reportSingleLineComment(String type, int startLineNo, int startColNo) { - reportCppComment(startLineNo, startColNo); - } - - @Override - public void reportBlockComment(String type, int startLineNo, - int startColNo, int endLineNo, int endColNo) { - reportCComment(startLineNo, startColNo, endLineNo, endColNo); + reportSingleLineComment(startLineNo, startColNo); } /** - * Report the location of a C++ style comment. + * Report the location of a single line comment. * @param startLineNo the starting line number * @param startColNo the starting column number **/ - public void reportCppComment(int startLineNo, int startColNo) { + public void reportSingleLineComment(int startLineNo, int startColNo) { final String line = line(startLineNo - 1); final String[] txt = {line.substring(startColNo)}; final Comment comment = new Comment(txt, startColNo, startLineNo, @@ -115,25 +110,22 @@ cppComments.put(startLineNo, comment); } - /** - * Returns a map of all the C++ style comments. The key is a line number, - * the value is the comment {@link TextBlock} at the line. - * @return the Map of comments - */ - public ImmutableMap getCppComments() { - return ImmutableMap.copyOf(cppComments); + @Override + public void reportBlockComment(String type, int startLineNo, + int startColNo, int endLineNo, int endColNo) { + reportBlockComment(startLineNo, startColNo, endLineNo, endColNo); } /** - * Report the location of a C-style comment. + * Report the location of a block comment. * @param startLineNo the starting line number * @param startColNo the starting column number * @param endLineNo the ending line number * @param endColNo the ending column number **/ - public void reportCComment(int startLineNo, int startColNo, + private void reportBlockComment(int startLineNo, int startColNo, int endLineNo, int endColNo) { - final String[] cComment = extractCComment(startLineNo, startColNo, + final String[] cComment = extractBlockComment(startLineNo, startColNo, endLineNo, endColNo); final Comment comment = new Comment(cComment, startColNo, endLineNo, endColNo); @@ -144,7 +136,7 @@ entries.add(comment); } else { - final List entries = Lists.newArrayList(); + final List entries = new ArrayList<>(); entries.add(comment); clangComments.put(startLineNo, entries); } @@ -157,24 +149,83 @@ } /** + * Report the location of a C++ style comment. + * @param startLineNo the starting line number + * @param startColNo the starting column number + * @deprecated Use {@link #reportSingleLineComment(int, int)} instead. + **/ + @Deprecated + public void reportCppComment(int startLineNo, int startColNo) { + reportSingleLineComment(startLineNo, startColNo); + } + + /** + * Returns a map of all the C++ style comments. The key is a line number, + * the value is the comment {@link TextBlock} at the line. + * @return the Map of comments + * @deprecated Use {@link #getSingleLineComments()} instead. + */ + @Deprecated + public Map getCppComments() { + return getSingleLineComments(); + } + + /** + * Returns a map of all the single line comments. The key is a line number, + * the value is the comment {@link TextBlock} at the line. + * @return the Map of comments + */ + public Map getSingleLineComments() { + return Collections.unmodifiableMap(cppComments); + } + + /** + * Report the location of a C-style comment. + * @param startLineNo the starting line number + * @param startColNo the starting column number + * @param endLineNo the ending line number + * @param endColNo the ending column number + * @deprecated Use {@link #reportBlockComment(int, int, int, int)} instead. + **/ + // -@cs[AbbreviationAsWordInName] Can't change yet since class is API. + @Deprecated + public void reportCComment(int startLineNo, int startColNo, + int endLineNo, int endColNo) { + reportBlockComment(startLineNo, startColNo, endLineNo, endColNo); + } + + /** * Returns a map of all C style comments. The key is the line number, the * value is a {@link List} of C style comment {@link TextBlock}s * that start at that line. * @return the map of comments + * @deprecated Use {@link #getBlockComments()} instead. */ - public ImmutableMap> getCComments() { - return ImmutableMap.copyOf(clangComments); + // -@cs[AbbreviationAsWordInName] Can't change yet since class is API. + @Deprecated + public Map> getCComments() { + return getBlockComments(); } /** - * Returns the specified C comment as a String array. + * Returns a map of all block comments. The key is the line number, the + * value is a {@link List} of block comment {@link TextBlock}s + * that start at that line. + * @return the map of comments + */ + public Map> getBlockComments() { + return Collections.unmodifiableMap(clangComments); + } + + /** + * Returns the specified block comment as a String array. * @param startLineNo the starting line number * @param startColNo the starting column number * @param endLineNo the ending line number * @param endColNo the ending column number - * @return C comment as a array + * @return block comment as an array **/ - private String[] extractCComment(int startLineNo, int startColNo, + private String[] extractBlockComment(int startLineNo, int startColNo, int endLineNo, int endColNo) { final String[] returnValue; if (startLineNo == endLineNo) { @@ -258,23 +309,12 @@ } /** - * Getter. - * @return the name of the file - * @deprecated use {@link #getFileName} instead - */ - @Deprecated - public String getFilename() { - return fileName; - } - - /** * Checks if the specified line is blank. * @param lineNo the line number to check * @return if the specified line consists only of tabs and spaces. **/ public boolean lineIsBlank(int lineNo) { - // possible improvement: avoid garbage creation in trim() - return line(lineNo).trim().isEmpty(); + return CommonUtils.isBlank(line(lineNo)); } /** @@ -297,8 +337,9 @@ **/ public boolean hasIntersectionWithComment(int startLineNo, int startColNo, int endLineNo, int endColNo) { - return hasIntersectionWithCComment(startLineNo, startColNo, endLineNo, endColNo) - || hasIntersectionWithCppComment(startLineNo, startColNo, endLineNo, endColNo); + return hasIntersectionWithBlockComment(startLineNo, startColNo, endLineNo, endColNo) + || hasIntersectionWithSingleLineComment(startLineNo, startColNo, endLineNo, + endColNo); } /** @@ -310,46 +351,54 @@ } /** - * Checks if the specified position intersects with a C comment. + * Checks if the specified position intersects with a block comment. * @param startLineNo the starting line number * @param startColNo the starting column number * @param endLineNo the ending line number * @param endColNo the ending column number - * @return true if the positions intersects with a C comment. + * @return true if the positions intersects with a block comment. */ - private boolean hasIntersectionWithCComment(int startLineNo, int startColNo, + private boolean hasIntersectionWithBlockComment(int startLineNo, int startColNo, int endLineNo, int endColNo) { + boolean hasIntersection = false; // Check C comments (all comments should be checked) final Collection> values = clangComments.values(); for (final List row : values) { for (final TextBlock comment : row) { if (comment.intersects(startLineNo, startColNo, endLineNo, endColNo)) { - return true; + hasIntersection = true; + break; } } + if (hasIntersection) { + break; + } } - return false; + return hasIntersection; } /** - * Checks if the specified position intersects with a CPP comment. + * Checks if the specified position intersects with a single line comment. * @param startLineNo the starting line number * @param startColNo the starting column number * @param endLineNo the ending line number * @param endColNo the ending column number - * @return true if the positions intersects with a CPP comment. + * @return true if the positions intersects with a single line comment. */ - private boolean hasIntersectionWithCppComment(int startLineNo, int startColNo, + private boolean hasIntersectionWithSingleLineComment(int startLineNo, int startColNo, int endLineNo, int endColNo) { + boolean hasIntersection = false; // Check CPP comments (line searching is possible) for (int lineNumber = startLineNo; lineNumber <= endLineNo; lineNumber++) { final TextBlock comment = cppComments.get(lineNumber); if (comment != null && comment.intersects(startLineNo, startColNo, endLineNo, endColNo)) { - return true; + hasIntersection = true; + break; } } - return false; + return hasIntersection; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/FileSetCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/FileSetCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/FileSetCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/FileSetCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,7 +20,6 @@ package com.puppycrawl.tools.checkstyle.api; import java.io.File; -import java.util.List; import java.util.SortedSet; /** @@ -31,6 +30,7 @@ */ public interface FileSetCheck extends Configurable, Contextualizable { + /** * Sets the MessageDispatcher that is used to dispatch error * messages to AuditListeners during processing. @@ -68,11 +68,11 @@ *

    * * @param file the file to be processed - * @param lines an immutable list of the contents of the file. + * @param fileText the contents of the file. * @return the sorted set of messages to be logged. * @throws CheckstyleException if error condition within Checkstyle occurs */ - SortedSet process(File file, List lines) throws CheckstyleException; + SortedSet process(File file, FileText fileText) throws CheckstyleException; /** * Called when all the files have been processed. This is the time to @@ -80,4 +80,5 @@ * method, the implementation is responsible for the logging of messages. */ void finishProcessing(); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/FileText.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/FileText.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/FileText.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/FileText.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -31,30 +31,24 @@ import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.nio.charset.UnsupportedCharsetException; -import java.util.AbstractList; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.lang3.ArrayUtils; - -import com.google.common.io.Closeables; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * Represents the text contents of a file of arbitrary plain text type. *

    * This class will be passed to instances of class FileSetCheck by - * Checker. It implements a string list to ensure backwards - * compatibility, but can be extended in the future to allow more - * flexible, more powerful or more efficient handling of certain - * situations. + * Checker. *

    * * @author Martin von Gagern */ -public final class FileText extends AbstractList { +public final class FileText { /** * The number of characters to read in one go. @@ -132,17 +126,21 @@ // Use the BufferedReader to break down the lines as this // is about 30% faster than using the // LINE_TERMINATOR.split(fullText, -1) method - final ArrayList textLines = new ArrayList<>(); - final BufferedReader reader = - new BufferedReader(new StringReader(fullText)); - while (true) { - final String line = reader.readLine(); - if (line == null) { - break; + final BufferedReader reader = new BufferedReader(new StringReader(fullText)); + try { + final ArrayList textLines = new ArrayList<>(); + while (true) { + final String line = reader.readLine(); + if (line == null) { + break; + } + textLines.add(line); } - textLines.add(line); + lines = textLines.toArray(new String[textLines.size()]); + } + finally { + CommonUtils.close(reader); } - lines = textLines.toArray(new String[textLines.size()]); } /** @@ -154,7 +152,12 @@ charset = fileText.charset; fullText = fileText.fullText; lines = fileText.lines.clone(); - lineBreaks = ArrayUtils.clone(fileText.lineBreaks); + if (fileText.lineBreaks == null) { + lineBreaks = null; + } + else { + lineBreaks = fileText.lineBreaks.clone(); + } } /** @@ -168,12 +171,11 @@ * @param lines the lines of the text, without terminators * @throws NullPointerException if the lines array is null */ - private FileText(File file, List lines) { - final StringBuilder buf = new StringBuilder(); + public FileText(File file, List lines) { + final StringBuilder buf = new StringBuilder(1024); for (final String line : lines) { buf.append(line).append('\n'); } - buf.trimToSize(); this.file = file; charset = null; @@ -193,48 +195,26 @@ if (!inputFile.exists()) { throw new FileNotFoundException(inputFile.getPath() + " (No such file or directory)"); } - final StringBuilder buf = new StringBuilder(); + final StringBuilder buf = new StringBuilder(1024); final FileInputStream stream = new FileInputStream(inputFile); final Reader reader = new InputStreamReader(stream, decoder); try { final char[] chars = new char[READ_BUFFER_SIZE]; while (true) { final int len = reader.read(chars); - if (len < 0) { + if (len == -1) { break; } buf.append(chars, 0, len); } } finally { - Closeables.closeQuietly(reader); + CommonUtils.close(reader); } return buf.toString(); } /** - * Compatibility conversion. - * - *

    This method can be used to convert the arguments passed to - * {@link FileSetCheck#process(File,List)} to a FileText - * object. If the list of lines already is a FileText, it is - * returned as is. Otherwise, a new FileText is constructed by - * joining the lines using line feed characters. - * - * @param file the name of the file - * @param lines the lines of the text, without terminators - * @return an object representing the denoted text file - */ - public static FileText fromLines(File file, List lines) { - if (lines instanceof FileText) { - return (FileText) lines; - } - else { - return new FileText(file, lines); - } - } - - /** * Get the name of the file. * @return an object containing the name of the file */ @@ -316,7 +296,6 @@ * @param lineNo the number of the line to get, starting at zero * @return the line with the given number */ - @Override public String get(final int lineNo) { return lines[lineNo]; } @@ -325,7 +304,6 @@ * Counts the lines of the text. * @return the number of lines in the text */ - @Override public int size() { return lines.length; } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Filter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Filter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Filter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Filter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,11 +23,14 @@ * An interface for filtering AuditEvents. * @author Rick Giles */ +@FunctionalInterface public interface Filter { + /** * Determines whether or not a filtered AuditEvent is accepted. * @param event the AuditEvent to filter. * @return true if the event is accepted. */ boolean accept(AuditEvent event); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/FilterSet.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/FilterSet.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/FilterSet.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/FilterSet.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,11 +20,10 @@ package com.puppycrawl.tools.checkstyle.api; import java.util.Collections; +import java.util.HashSet; import java.util.Objects; import java.util.Set; -import com.google.common.collect.Sets; - /** * A filter set applies filters to AuditEvents. * If a filter in the set rejects an AuditEvent, then the @@ -33,8 +32,9 @@ */ public class FilterSet implements Filter { + /** Filter set. */ - private final Set filters = Sets.newHashSet(); + private final Set filters = new HashSet<>(); /** * Adds a Filter to the set. @@ -84,16 +84,19 @@ @Override public boolean accept(AuditEvent event) { + boolean result = true; for (Filter filter : filters) { if (!filter.accept(event)) { - return false; + result = false; + break; } } - return true; + return result; } /** Clears the FilterSet. */ public void clear() { filters.clear(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/FullIdent.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/FullIdent.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/FullIdent.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/FullIdent.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,8 +22,6 @@ import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.StringUtils; - /** * Represents a full identifier, including dots, with associated * position information. @@ -40,6 +38,7 @@ * @see TokenTypes#IDENT **/ public final class FullIdent { + /** The list holding subsequent elements of identifier. **/ private final List elements = new ArrayList<>(); /** The line number. **/ @@ -76,7 +75,7 @@ * @return the text */ public String getText() { - return StringUtils.join(elements, ""); + return String.join("", elements); } /** @@ -97,7 +96,7 @@ @Override public String toString() { - return getText() + "[" + lineNo + "x" + columnNo + "]"; + return String.join("", elements) + "[" + lineNo + "x" + columnNo + "]"; } /** @@ -107,18 +106,16 @@ * @param ast the node to recurse from */ private static void extractFullIdent(FullIdent full, DetailAST ast) { - if (ast == null) { - return; - } - - if (ast.getType() == TokenTypes.DOT) { - extractFullIdent(full, ast.getFirstChild()); - full.append("."); - extractFullIdent( - full, ast.getFirstChild().getNextSibling()); - } - else { - full.append(ast); + if (ast != null) { + if (ast.getType() == TokenTypes.DOT) { + extractFullIdent(full, ast.getFirstChild()); + full.append("."); + extractFullIdent( + full, ast.getFirstChild().getNextSibling()); + } + else { + full.append(ast); + } } } @@ -150,4 +147,5 @@ columnNo = Math.min(columnNo, ast.getColumnNo()); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/JavadocTokenTypes.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,125 +24,25 @@ import com.puppycrawl.tools.checkstyle.grammars.javadoc.JavadocParser; /** + * Contains the constants for all the tokens contained in the Abstract + * Syntax Tree for the javadoc grammar. + * * @author Baratali Izmailov - * @see + * @see * javadoc - The Java API Documentation Generator */ public final class JavadocTokenTypes { - /** Rule types offset. */ - private static final int RULE_TYPES_OFFSET = 10000; - - /** - * Root node of any Javadoc comment. - * Last child is always {@link #EOF}. - * - *

    - * Tree for example: - *

    {@code
    -     * JAVADOC[3x0]
    -     *   |--NEWLINE[3x0] : [\n]
    -     *   |--LEADING_ASTERISK[4x0] : [ *]
    -     *   |--WS[4x2] : [ ]
    -     *   |--JAVADOC_TAG[4x3] : [@param T The bar.\n ]
    -     *       |--PARAM_LITERAL[4x3] : [@param]
    -     *       |--WS[4x9] : [ ]
    -     *       |--PARAMETER_NAME[4x10] : [T]
    -     *       |--WS[4x11] : [ ]
    -     *       |--DESCRIPTION[4x12] : [The bar.\n ]
    -     *           |--TEXT[4x12] : [The bar.]
    -     *           |--NEWLINE[4x20] : [\n]
    -     *           |--TEXT[5x0] : [ ]
    -     *   |--EOF[5x1] : []
    -     * }
    - */ - public static final int JAVADOC = JavadocParser.RULE_javadoc + RULE_TYPES_OFFSET; //--------------------------------------------------------------------------------------------// //------------------ JAVADOC TAGS --------------------------------------------// //--------------------------------------------------------------------------------------------// /** - * Javadoc tag. - * - *

    Type of Javadoc tag is resolved by literal node that is first child of this node. - * - *

    As literal could be: - *

      - *
    • {@link #RETURN_LITERAL}
    • - *
    • {@link #DEPRECATED_LITERAL}
    • - *
    • {@link #SINCE_LITERAL}
    • - *
    • {@link #SERIAL_DATA_LITERAL}
    • - *
    • {@link #SERIAL_FIELD_LITERAL}
    • - *
    • {@link #PARAM_LITERAL}
    • - *
    • {@link #SEE_LITERAL}
    • - *
    • {@link #SERIAL_LITERAL}
    • - *
    • {@link #VERSION_LITERAL}
    • - *
    • {@link #EXCEPTION_LITERAL}
    • - *
    • {@link #THROWS_LITERAL}
    • - *
    • {@link #AUTHOR_LITERAL}
    • - *
    • or {@link #CUSTOM_NAME} if it is custom Javadoc tag.
    • - *
    - * - *

    - * Example - *

    {@code @param T The bar.}
    - * Tree - *
    {@code
    -     *   |--JAVADOC_TAG[4x3] : [@param T The bar.]
    -     *       |--PARAM_LITERAL[4x3] : [@param]
    -     *       |--WS[4x9] : [ ]
    -     *       |--PARAMETER_NAME[4x10] : [T]
    -     *       |--WS[4x11] : [ ]
    -     *       |--DESCRIPTION[4x12] : [The bar.]
    -     *           |--TEXT[4x12] : [The bar.]
    -     * }
    - */ - public static final int JAVADOC_TAG = JavadocParser.RULE_javadocTag + RULE_TYPES_OFFSET; - - /** - * Javadoc inline tag. - * - *

    Type of Javadoc inline tag is resolved by literal node that is second child of this node. - * First child is always {@link #JAVADOC_INLINE_TAG_START} and last node is always - * {@link #JAVADOC_INLINE_TAG_END}. - * - *

    As literal could be: - *

      - *
    • {@link #CODE_LITERAL}
    • - *
    • {@link #DOC_ROOT_LITERAL}
    • - *
    • {@link #LINK_LITERAL}
    • - *
    • {@link #INHERIT_DOC_LITERAL}
    • - *
    • {@link #LINKPLAIN_LITERAL}
    • - *
    • {@link #LITERAL_LITERAL}
    • - *
    • {@link #VALUE_LITERAL}
    • - *
    • or {@link #CUSTOM_NAME} if it is custom Javadoc inline tag.
    • - *
    - * - *

    - * Example: - *

    {@code {@link String}}
    - * Tree: - *
    -     * {@code |--JAVADOC_INLINE_TAG[4x3] : [{@link String}]
    -     *        |--JAVADOC_INLINE_TAG_START[4x3] : [{]
    -     *        |--LINK_LITERAL[4x4] : [@link]
    -     *        |--WS[4x9] : [ ]
    -     *        |--REFERENCE[4x10] : [String]
    -     *            |--CLASS[4x10] : [String]
    -     *        |--JAVADOC_INLINE_TAG_END[4x16] : [}]
    -     * }
    -     * 
    - */ - public static final int JAVADOC_INLINE_TAG = JavadocParser.RULE_javadocInlineTag - + RULE_TYPES_OFFSET; - - /** * '@return' literal in @return Javadoc tag. * - *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION} + *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION}

    * - *

    - * Example: + *

    Example:

    *
    {@code @return true if file exists}
    * Tree: *
    {@code
    @@ -154,19 +54,18 @@
          * }
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ public static final int RETURN_LITERAL = JavadocParser.RETURN_LITERAL; /** - * '@deprecated' literal in @deprecated Javadoc tag. + * '{@literal @}deprecated' literal in {@literal @}deprecated Javadoc tag. * - *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION} + *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION}

    * - *

    - * Example: + *

    Example:

    *
    {@code @deprecated it is deprecated method}
    * Tree: *
    {@code
    @@ -178,7 +77,7 @@
          * }
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ @@ -187,10 +86,9 @@ /** * '@since' literal in @since Javadoc tag. * - *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION} + *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION}

    * - *

    - * Example: + *

    Example:

    *
    {@code @since 3.4 RELEASE}
    * Tree: *
    {@code
    @@ -202,7 +100,7 @@
          * }
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ @@ -211,10 +109,9 @@ /** * '@serialData' literal in @serialData Javadoc tag. * - *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION} + *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION}

    * - *

    - * Example: + *

    Example:

    *
    {@code @serialData two values of Integer type}
    * Tree: *
    {@code
    @@ -227,7 +124,7 @@
          * 
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ @@ -236,15 +133,14 @@ /** * '@serialField' literal in @serialField Javadoc tag. * - *

    Such Javadoc tag can have three arguments: + *

    Such Javadoc tag can have three arguments:

    *
      *
    1. {@link #FIELD_NAME}
    2. *
    3. {@link #FIELD_TYPE}
    4. *
    5. {@link #DESCRIPTION}
    6. *
    * - *

    - * Example: + *

    Example:

    *
    {@code @serialField counter Integer objects counter}
    * Tree: *
    {@code
    @@ -260,7 +156,7 @@
          * }
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ @@ -269,14 +165,13 @@ /** * '@param' literal in @param Javadoc tag. * - *

    Such Javadoc tag can have two arguments: + *

    Such Javadoc tag can have two arguments:

    *
      *
    1. {@link #PARAMETER_NAME}
    2. *
    3. {@link #DESCRIPTION}
    4. *
    * - *

    - * Example: + *

    Example:

    *
    {@code @param T The bar.}
    * Tree: *
    {@code
    @@ -290,7 +185,7 @@
          * }
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ @@ -299,10 +194,9 @@ /** * '@see' literal in @see Javadoc tag. * - *

    Such Javadoc tag can have one argument - {@link #REFERENCE} + *

    Such Javadoc tag can have one argument - {@link #REFERENCE}

    * - *

    - * Example: + *

    Example:

    *
    {@code @see org.apache.utils.Lists.Comparator#compare(Object)}
    * Tree: *
    {@code
    @@ -310,7 +204,7 @@
          *       |--SEE_LITERAL[3x0] : [@see]
          *       |--WS[3x4] : [ ]
          *       |--REFERENCE[3x5] : [org.apache.utils.Lists.Comparator#compare(Object)]
    -     *           |--PACKAGE[3x5] : [org.apache.utils]
    +     *           |--PACKAGE_CLASS[3x5] : [org.apache.utils]
          *           |--DOT[3x21] : [.]
          *           |--CLASS[3x22] : [Lists]
          *           |--DOT[3x27] : [.]
    @@ -324,20 +218,19 @@
          * }
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ public static final int SEE_LITERAL = JavadocParser.SEE_LITERAL; /** - * '@see' literal in @see Javadoc tag. + * '@serial' literal in @serial Javadoc tag. * *

    Such Javadoc tag can have one argument - {@link #REFERENCE} or {@link #LITERAL_EXCLUDE} - * or {@link #LITERAL_INCLUDE} + * or {@link #LITERAL_INCLUDE}

    * - *

    - * Example: + *

    Example:

    *
    {@code @serial include}
    * Tree: *
    {@code
    @@ -347,8 +240,7 @@
          *       |--LITERAL_INCLUDE[3x8] : [include]
          * }
    * - *

    - * Example: + *

    Example:

    *
    {@code @serial serialized company name}
    * Tree: *
    {@code
    @@ -360,7 +252,7 @@
          * }
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ @@ -369,10 +261,9 @@ /** * '@version' literal in @version Javadoc tag. * - *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION} + *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION}

    * - *

    - * Example: + *

    Example:

    *
    {@code @version 1.3}
    * Tree: *
    {@code
    @@ -384,7 +275,7 @@
          * }
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ @@ -393,10 +284,9 @@ /** * '@exception' literal in @exception Javadoc tag. * - *

    Such Javadoc tag can have two argument - {@link #CLASS_NAME} and {@link #DESCRIPTION} + *

    Such Javadoc tag can have two argument - {@link #CLASS_NAME} and {@link #DESCRIPTION}

    * - *

    - * Example: + *

    Example:

    *
    {@code @exception SQLException if query is not correct}
    * Tree: *
    {@code
    @@ -410,7 +300,7 @@
          * }
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ @@ -419,10 +309,9 @@ /** * '@throws' literal in @throws Javadoc tag. * - *

    Such Javadoc tag can have two argument - {@link #CLASS_NAME} and {@link #DESCRIPTION} + *

    Such Javadoc tag can have two argument - {@link #CLASS_NAME} and {@link #DESCRIPTION}

    * - *

    - * Example: + *

    Example:

    *
    {@code @throws SQLException if query is not correct}
    * Tree: *
    {@code
    @@ -436,7 +325,7 @@
          * }
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ @@ -445,10 +334,9 @@ /** * '@author' literal in @author Javadoc tag. * - *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION} + *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION}

    * - *

    - * Example: + *

    Example:

    *
    {@code @author Baratali Izmailov}
    * Tree: *
    {@code
    @@ -460,7 +348,7 @@
          * }
    * * @see - * + * * Oracle Docs * @see #JAVADOC_TAG */ @@ -469,10 +357,9 @@ /** * Name of custom Javadoc tag (or Javadoc inline tag). * - *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION} + *

    Such Javadoc tag can have one argument - {@link #DESCRIPTION}

    * - *

    - * Example: + *

    Example:

    *
    {@code @myJavadocTag some magic}
    * Tree: *
    {@code
    @@ -488,130 +375,128 @@
         /**
          * First child of {@link #JAVADOC_INLINE_TAG} that represents left curly brace '{'.
          *
    -     * 

    - * Example: - *

    {@code {@code Comparable<E>}}
    + *

    Example:

    + *
    {@code Comparable<E>}
    * Tree: *
    -     * {@code |--JAVADOC_INLINE_TAG[3x0] : [{@code Comparable<E>}]
    +     *  |--JAVADOC_INLINE_TAG[3x0] : [{@code Comparable<E>}]
          *         |--JAVADOC_INLINE_TAG_START[3x0] : [{]
          *         |--CODE_LITERAL[3x1] : [@code]
          *         |--WS[3x6] : [ ]
          *         |--TEXT[3x7] : [Comparable<E>]
          *         |--JAVADOC_INLINE_TAG_END[3x21] : [}]
    -     * }
    + * + *
    + * @noinspection HtmlTagCanBeJavadocTag */ public static final int JAVADOC_INLINE_TAG_START = JavadocParser.JAVADOC_INLINE_TAG_START; /** * Last child of {@link #JAVADOC_INLINE_TAG} that represents right curly brace '}'. * - *

    - * Example: - *

    {@code {@code Comparable<E>}}
    + *

    Example:

    + *
    {@code Comparable<E>}
    * Tree: *
    -     * {@code |--JAVADOC_INLINE_TAG[3x0] : [{@code Comparable<E>}]
    +     *  |--JAVADOC_INLINE_TAG[3x0] : [{@code Comparable<E>}]
          *         |--JAVADOC_INLINE_TAG_START[3x0] : [{]
          *         |--CODE_LITERAL[3x1] : [@code]
          *         |--WS[3x6] : [ ]
          *         |--TEXT[3x7] : [Comparable<E>]
          *         |--JAVADOC_INLINE_TAG_END[3x21] : [}]
    -     * }
    +     * 
          * 
    + * @noinspection HtmlTagCanBeJavadocTag */ public static final int JAVADOC_INLINE_TAG_END = JavadocParser.JAVADOC_INLINE_TAG_END; /** * '@code' literal in {@code} Javadoc inline tag. * - *

    Such Javadoc inline tag can have such child nodes: + *

    Such Javadoc inline tag can have such child nodes:

    *
      *
    • {@link #NEWLINE}
    • *
    • {@link #WS}
    • *
    • {@link #TEXT}
    • *
    * - *

    - * Example: - *

    {@code {@code Comparable<E>}}
    + *

    Example:

    + *
    {@code Comparable<E>}
    * Tree: *
    -     * {@code |--JAVADOC_INLINE_TAG[3x0] : [{@code Comparable<E>}]
    +     *  |--JAVADOC_INLINE_TAG[3x0] : [{@code Comparable<E>}]
          *         |--JAVADOC_INLINE_TAG_START[3x0] : [{]
          *         |--CODE_LITERAL[3x1] : [@code]
          *         |--WS[3x6] : [ ]
          *         |--TEXT[3x7] : [Comparable<E>]
          *         |--JAVADOC_INLINE_TAG_END[3x21] : [}]
    -     * }
    +     * 
          * 
    * * @see - * + * * Oracle Docs * @see #JAVADOC_INLINE_TAG + * @noinspection HtmlTagCanBeJavadocTag */ public static final int CODE_LITERAL = JavadocParser.CODE_LITERAL; /** * '@docRoot' literal in {@docRoot} Javadoc inline tag. * - *

    Such Javadoc inline tag does not have any arguments and can have such child nodes: + *

    Such Javadoc inline tag does not have any arguments and can have such child nodes:

    *
      *
    • {@link #NEWLINE}
    • *
    • {@link #WS}
    • *
    * - *

    - * Example: - *

    {@code {@docRoot}}
    + *

    Example:

    + *
    {@docRoot}
    * Tree: *
    -     * {@code  |--JAVADOC_INLINE_TAG[1x0] : [{@docRoot \n}]
    +     *   |--JAVADOC_INLINE_TAG[1x0] : [{@docRoot}]
          *            |--JAVADOC_INLINE_TAG_START[1x0] : [{]
          *            |--DOC_ROOT_LITERAL[1x1] : [@docRoot]
          *            |--JAVADOC_INLINE_TAG_END[2x0] : [}]
    -     * }
    +     * 
          * 
    * - *

    - * Example: - *

    {@code {@docRoot
    -     *}}
    + *

    Example:

    + *
    {@docRoot
    +     *}
    * Tree: *
    -     * {@code  |--JAVADOC_INLINE_TAG[1x0] : [{@docRoot \n}]
    +     *   |--JAVADOC_INLINE_TAG[1x0] : [{@docRoot \n}]
          *            |--JAVADOC_INLINE_TAG_START[1x0] : [{]
          *            |--DOC_ROOT_LITERAL[1x1] : [@docRoot]
          *            |--WS[1x9] : [ ]
          *            |--NEWLINE[1x10] : [\n]
          *            |--JAVADOC_INLINE_TAG_END[2x0] : [}]
    -     * }
    +     * 
          * 
    * * @see - * + * * Oracle Docs * @see #JAVADOC_INLINE_TAG + * @noinspection HtmlTagCanBeJavadocTag */ public static final int DOC_ROOT_LITERAL = JavadocParser.DOC_ROOT_LITERAL; /** * '@link' literal in {@link} Javadoc inline tag. - *

    - * Such Javadoc inline tag can have one argument - {@link #REFERENCE} - *

    + *

    Such Javadoc inline tag can have one argument - {@link #REFERENCE}

    *

    Example:

    - *
    {@code {@link org.apache.utils.Lists.Comparator#compare(Object)}}
    + *
    {@link org.apache.utils.Lists.Comparator#compare(Object)}
    *

    Tree:

    *
    -     * {@code |--JAVADOC_INLINE_TAG[1x0] :
    +     *  |--JAVADOC_INLINE_TAG[1x0] :
          *               [{@link org.apache.utils.Lists.Comparator#compare(Object)}]
          *        |--JAVADOC_INLINE_TAG_START[1x0] : [{]
          *        |--LINK_LITERAL[1x1] : [@link]
          *        |--WS[1x6] : [ ]
          *        |--REFERENCE[1x7] : [org.apache.utils.Lists.Comparator#compare(Object)]
    -     *            |--PACKAGE[1x7] : [org.apache.utils]
    +     *            |--PACKAGE_CLASS[1x7] : [org.apache.utils]
          *            |--DOT[1x23] : [.]
          *            |--CLASS[1x24] : [Lists]
          *            |--DOT[1x29] : [.]
    @@ -623,61 +508,62 @@
          *                |--ARGUMENT[1x49] : [Object]
          *                |--RIGHT_BRACE[1x55] : [)]
          *        |--JAVADOC_INLINE_TAG_END[1x56] : [}]
    -     * }
    +     * 
          * 
    * * @see - * + * * Oracle Docs * @see #JAVADOC_INLINE_TAG + * @noinspection HtmlTagCanBeJavadocTag */ public static final int LINK_LITERAL = JavadocParser.LINK_LITERAL; /** * '@inheritDoc' literal in {@inheritDoc} Javadoc inline tag. * - *

    Such Javadoc inline tag does not have any arguments and can have such child nodes: + *

    Such Javadoc inline tag does not have any arguments and can have such child nodes:

    *
      *
    • {@link #NEWLINE}
    • *
    • {@link #WS}
    • *
    * - *

    - * Example: - *

    {@code {@inheritDoc}}
    + *

    Example:

    + *
    {@inheritDoc}
    * Tree: *
    -     * {@code  |--JAVADOC_INLINE_TAG[1x0] : [{@inheritDoc}]
    +     *   |--JAVADOC_INLINE_TAG[1x0] : [{@inheritDoc}]
          *            |--JAVADOC_INLINE_TAG_START[1x0] : [{]
          *            |--INHERIT_DOC_LITERAL[1x1] : [@inheritDoc]
          *            |--JAVADOC_INLINE_TAG_END[1x12] : [}]
    -     * }
    +     * 
          * 
    * * @see - * + * * Oracle Docs * @see #JAVADOC_INLINE_TAG + * @noinspection HtmlTagCanBeJavadocTag */ public static final int INHERIT_DOC_LITERAL = JavadocParser.INHERIT_DOC_LITERAL; /** * '@linkplain' literal in {@linkplain} Javadoc inline tag. * - *

    Such Javadoc inline tag can have one argument - {@link #REFERENCE} + *

    Such Javadoc inline tag can have one argument - {@link #REFERENCE}

    * - *

    - * Example: - *

    {@code {@linkplain org.apache.utils.Lists.Comparator#compare(Object) compare}}
    + *

    Example:

    + *
    {@linkplain org.apache.utils.Lists.Comparator#compare(Object) compare}
    +     * 
    * Tree: *
    -     * {@code |--JAVADOC_INLINE_TAG[1x0] :
    +     *  |--JAVADOC_INLINE_TAG[1x0] :
          *               [{@linkplain org.apache.utils.Lists.Comparator#compare(Object) compare}]
          *        |--JAVADOC_INLINE_TAG_START[1x0] : [{]
          *        |--LINKPLAIN_LITERAL[1x1] : [@linkplain]
          *        |--WS[1x11] : [ ]
          *        |--REFERENCE[1x12] : [org.apache.utils.Lists.Comparator#compare(Object)]
    -     *            |--PACKAGE[1x12] : [org.apache.utils]
    +     *            |--PACKAGE_CLASS[1x12] : [org.apache.utils]
          *            |--DOT[1x28] : [.]
          *            |--CLASS[1x29] : [Lists]
          *            |--DOT[1x34] : [.]
    @@ -691,44 +577,45 @@
          *        |--DESCRIPTION[1x61] : [ compare]
          *            |--TEXT[1x61] : [ compare]
          *        |--JAVADOC_INLINE_TAG_END[1x69] : [}]
    -     * }
    +     * 
          * 
    * * @see - * + * * Oracle Docs * @see #JAVADOC_INLINE_TAG + * @noinspection HtmlTagCanBeJavadocTag */ public static final int LINKPLAIN_LITERAL = JavadocParser.LINKPLAIN_LITERAL; /** * '@literal' literal in {@literal} Javadoc inline tag. * - *

    Such Javadoc inline tag can have such child nodes: + *

    Such Javadoc inline tag can have such child nodes:

    *
      *
    • {@link #NEWLINE}
    • *
    • {@link #WS}
    • *
    • {@link #TEXT}
    • *
    * - *

    - * Example: - *

    {@code {@literal #compare(Object)}}
    + *

    Example:

    + *
    {@literal #compare(Object)}
    * Tree: *
    -     * {@code |--JAVADOC_INLINE_TAG[1x0] : [{@literal #compare(Object)}]
    +     *  |--JAVADOC_INLINE_TAG[1x0] : [{@literal #compare(Object)}]
          *        |--JAVADOC_INLINE_TAG_START[1x0] : [{]
          *        |--LITERAL_LITERAL[1x1] : [@literal]
          *        |--WS[1x9] : [ ]
          *        |--TEXT[1x10] : [#compare(Object)]
          *        |--JAVADOC_INLINE_TAG_END[1x27] : [}]
    -     * }
    +     * 
          * 
    * * @see - * + * * Oracle Docs * @see #JAVADOC_INLINE_TAG + * @noinspection HtmlTagCanBeJavadocTag */ public static final int LITERAL_LITERAL = JavadocParser.LITERAL_LITERAL; @@ -736,18 +623,17 @@ * '@value' literal in {@value} Javadoc inline tag. * *

    Such Javadoc inline tag has one argument {@link #REFERENCE} - * and can have such child nodes: + * and can have such child nodes:

    *
      *
    • {@link #NEWLINE}
    • *
    • {@link #WS}
    • *
    * - *

    - * Example: - *

    {@code {@value Integer#MAX_VALUE}}
    + *

    Example:

    + *
    {@value Integer#MAX_VALUE}
    * Tree: *
    -     * {@code |--JAVADOC_INLINE_TAG[1x0] : [{@value Integer#MAX_VALUE}]
    +     *  |--JAVADOC_INLINE_TAG[1x0] : [@value Integer#MAX_VALUE}]
          *        |--JAVADOC_INLINE_TAG_START[1x0] : [{]
          *        |--VALUE_LITERAL[1x1] : [@value]
          *        |--WS[1x7] : [ ]
    @@ -756,93 +642,32 @@
          *            |--HASH[1x15] : [#]
          *            |--MEMBER[1x16] : [MAX_VALUE]
          *        |--JAVADOC_INLINE_TAG_END[1x25] : [}]
    -     * }
    +     * 
          * 
    * * @see - * + * * Oracle Docs * @see #JAVADOC_INLINE_TAG + * @noinspection HtmlTagCanBeJavadocTag */ public static final int VALUE_LITERAL = JavadocParser.VALUE_LITERAL; /** - * Parameter of the Javadoc tags listed below. - *
      - *
    • {@link #SEE_LITERAL @see}
    • - *
    • {@link #LINK_LITERAL {@link}}
    • - *
    • {@link #LINKPLAIN_LITERAL {@linkplain}}
    • - *
    • {@link #VALUE_LITERAL {@value}}
    • - *
    - */ - public static final int REFERENCE = JavadocParser.RULE_reference + RULE_TYPES_OFFSET; - - /** - * Package definition in {@link #REFERENCE}. - * Package definition is lowercase part of REFERENCE and before a hash character (#). - * - *

    - * Example: - *

    {@code @see org.apache.utils.Lists.Comparator#compare(Object)}
    - * Tree: - *
    -     * {@code |--JAVADOC_TAG[3x0] : [@see org.apache.utils.Lists.Comparator#compare(Object)]
    -     *        |--SEE_LITERAL[3x0] : [@see]
    -     *        |--WS[3x4] : [ ]
    -     *        |--REFERENCE[3x5] : [org.apache.utils.Lists.Comparator#compare(Object)]
    -     *            |--PACKAGE[3x5] : [org.apache.utils]
    -     *            |--DOT[3x21] : [.]
    -     *            |--CLASS[3x22] : [Lists]
    -     *            |--DOT[3x27] : [.]
    -     *            |--CLASS[3x28] : [Comparator]
    -     *            |--HASH[3x38] : [#]
    -     *            |--MEMBER[3x39] : [compare]
    -     *            |--PARAMETERS[3x46] : [(Object)]
    -     *                |--LEFT_BRACE[3x46] : [(]
    -     *                |--ARGUMENT[3x47] : [Object]
    -     *                |--RIGHT_BRACE[3x53] : [)]
    -     * }
    -     * 
    - */ - public static final int PACKAGE = JavadocParser.PACKAGE; - - /** - * Class definition in {@link #REFERENCE}. - * Class definition is part of REFERENCE, that is started by capital letter - * and before a hash character (#). - * - *

    - * Example: - *

    {@code @see org.apache.utils.Lists.Comparator#compare(Object)}
    - * Tree: - *
    -     * {@code |--JAVADOC_TAG[3x0] : [@see org.apache.utils.Lists.Comparator#compare(Object)]
    -     *        |--SEE_LITERAL[3x0] : [@see]
    -     *        |--WS[3x4] : [ ]
    -     *        |--REFERENCE[3x5] : [org.apache.utils.Lists.Comparator#compare(Object)]
    -     *            |--PACKAGE[3x5] : [org.apache.utils]
    -     *            |--DOT[3x21] : [.]
    -     *            |--CLASS[3x22] : [Lists]
    -     *            |--DOT[3x27] : [.]
    -     *            |--CLASS[3x28] : [Comparator]
    -     *            |--HASH[3x38] : [#]
    -     *            |--MEMBER[3x39] : [compare]
    -     *            |--PARAMETERS[3x46] : [(Object)]
    -     *                |--LEFT_BRACE[3x46] : [(]
    -     *                |--ARGUMENT[3x47] : [Object]
    -     *                |--RIGHT_BRACE[3x53] : [)]
    -     * }
    -     * 
    - */ - public static final int CLASS = JavadocParser.CLASS; - - /** - * Dot separator in {@link #REFERENCE}. - * Dot separator is used between {@link #PACKAGE} and {@link #CLASS}; between {@link #CLASS} - * and {@link #CLASS} + * PACKAGE_CLASS represents the package or class which has been referenced in the `@see`, + * `@link`, `@linkplain` or `@value` javadoc tags. In the javadoc tree it shall be a child + * of {@link #REFERENCE}. + *
    + * IMPORTANT: Constructs like + * {@code package.Class.NestedClassAtDepth1.NestedClassAtDepth2#member} are recognized by + * the javadoc tool from oracle, and no assumptions like, package names wouldn't consist of + * uppercase characters or class names begin with an uppercase character, are made. + * Also, the reference in a javadoc tag can consist just a package name or a + * simple class name or even a full class name. Thus, PACKAGE_CLASS can represent a + * package name or a simple class name or a full class name i.e checkstyle doesn't + * resolve references at present. * - *

    - * Example: + *

    Example:

    *
    {@code @see org.apache.utils.Lists.Comparator#compare(Object)}
    * Tree: *
    @@ -850,7 +675,7 @@
          *        |--SEE_LITERAL[3x0] : [@see]
          *        |--WS[3x4] : [ ]
          *        |--REFERENCE[3x5] : [org.apache.utils.Lists.Comparator#compare(Object)]
    -     *            |--PACKAGE[3x5] : [org.apache.utils]
    +     *            |--PACKAGE_CLASS[3x5] : [org.apache.utils]
          *            |--DOT[3x21] : [.]
          *            |--CLASS[3x22] : [Lists]
          *            |--DOT[3x27] : [.]
    @@ -864,14 +689,13 @@
          * }
          * 
    */ - public static final int DOT = JavadocParser.DOT; + public static final int PACKAGE_CLASS = JavadocParser.PACKAGE_CLASS; /** * Hash character in {@link #REFERENCE}. * Hash character is used before specifying a class member. * - *

    - * Example: + *

    Example:

    *
    {@code @see org.apache.utils.Lists.Comparator#compare(Object)}
    * Tree: *
    @@ -879,7 +703,7 @@
          *        |--SEE_LITERAL[3x0] : [@see]
          *        |--WS[3x4] : [ ]
          *        |--REFERENCE[3x5] : [org.apache.utils.Lists.Comparator#compare(Object)]
    -     *            |--PACKAGE[3x5] : [org.apache.utils]
    +     *            |--PACKAGE_CLASS[3x5] : [org.apache.utils]
          *            |--DOT[3x21] : [.]
          *            |--CLASS[3x22] : [Lists]
          *            |--DOT[3x27] : [.]
    @@ -899,8 +723,7 @@
          * A class member in {@link #REFERENCE}.
          * Class member is specified after {@link #HASH} symbol.
          *
    -     * 

    - * Example: + *

    Example:

    *
    {@code @see org.apache.utils.Lists.Comparator#compare(Object)}
    * Tree: *
    @@ -908,7 +731,7 @@
          *        |--SEE_LITERAL[3x0] : [@see]
          *        |--WS[3x4] : [ ]
          *        |--REFERENCE[3x5] : [org.apache.utils.Lists.Comparator#compare(Object)]
    -     *            |--PACKAGE[3x5] : [org.apache.utils]
    +     *            |--PACKAGE_CLASS[3x5] : [org.apache.utils]
          *            |--DOT[3x21] : [.]
          *            |--CLASS[3x22] : [Lists]
          *            |--DOT[3x27] : [.]
    @@ -925,40 +748,9 @@
         public static final int MEMBER = JavadocParser.MEMBER;
     
         /**
    -     * Parameters part in {@link #REFERENCE}.
    -     * It is used to specify parameters for {@link #MEMBER method}.
    -     * Always contains {@link #LEFT_BRACE} as first child and {@link #RIGHT_BRACE} as last child.
    -     * Each parameter is represented by {@link #ARGUMENT} node.
    -     * Arguments in braces are separated by {@link #COMMA} (and optional {@link #WS}).
    -     *
    -     * 

    - * Example: - *

    {@code @see #method(Processor, String)}
    - * Tree: - *
    -     * {@code |--JAVADOC_TAG[1x0] : [@see #method(Processor, String)]
    -     *        |--SEE_LITERAL[1x0] : [@see]
    -     *        |--WS[1x4] : [ ]
    -     *        |--REFERENCE[1x5] : [#method(Processor, String)]
    -     *            |--HASH[1x5] : [#]
    -     *            |--MEMBER[1x6] : [method]
    -     *            |--PARAMETERS[1x12] : [(Processor, String)]
    -     *                |--LEFT_BRACE[1x12] : [(]
    -     *                |--ARGUMENT[1x13] : [Processor]
    -     *                |--COMMA[1x22] : [,]
    -     *                |--WS[1x23] : [ ]
    -     *                |--ARGUMENT[1x24] : [String]
    -     *                |--RIGHT_BRACE[1x30] : [)]
    -     * }
    -     * 
    - */ - public static final int PARAMETERS = JavadocParser.RULE_parameters + RULE_TYPES_OFFSET; - - /** * Left brace in {@link #PARAMETERS} part of {@link #REFERENCE}. * - *

    - * Example: + *

    Example:

    *
    {@code @see #method(Processor, String)}
    * Tree: *
    @@ -983,8 +775,7 @@
         /**
          * Right brace in {@link #PARAMETERS} part of {@link #REFERENCE}.
          *
    -     * 

    - * Example: + *

    Example:

    *
    {@code @see #method(Processor, String)}
    * Tree: *
    @@ -1009,8 +800,7 @@
         /**
          * Argument definition in {@link #PARAMETERS} part of {@link #REFERENCE}.
          *
    -     * 

    - * Example: + *

    Example:

    *
    {@code @see #method(Processor, String)}
    * Tree: *
    @@ -1035,8 +825,7 @@
         /**
          * Comma separator between parameters in {@link #PARAMETERS} part of {@link #REFERENCE}.
          *
    -     * 

    - * Example: + *

    Example:

    *
    {@code @see #method(Processor, String)}
    * Tree: *
    @@ -1066,8 +855,7 @@
          * Quoted text.
          * One of possible @see tag arguments.
          *
    -     * 

    - * Example: + *

    Example:

    *
    {@code @see "Spring Framework"}
    * Tree: *
    @@ -1083,53 +871,10 @@
         public static final int STRING = JavadocParser.STRING;
     
         /**
    -     * Description node, that contains:
    -     * 
      - *
    • {@link #TEXT}
    • - *
    • {@link #WS}
    • - *
    • {@link #NEWLINE}
    • - *
    • {@link #HTML_ELEMENT}
    • - *
    - * - *

    It is argument for many Javadoc tags and inline tags. - * - *

    - * Example: - *

    {@code @throws IOException if <b>connection</b> problems occur}
    - * Tree: - *
    -     * {@code |--JAVADOC_TAG[1x0] :
    -     *               [@throws IOException if <b>connection</b> problems occur]
    -     *        |--THROWS_LITERAL[1x0] : [@throws]
    -     *        |--WS[1x7] : [ ]
    -     *        |--CLASS_NAME[1x8] : [IOException]
    -     *        |--WS[1x19] : [ ]
    -     *        |--DESCRIPTION[1x20] : [if <b>connection</b> problems occur]
    -     *            |--TEXT[1x20] : [if ]
    -     *            |--HTML_ELEMENT[1x23] : [<b>connection</b>]
    -     *                |--HTML_TAG[1x23] : [<b>connection</b>]
    -     *                    |--HTML_ELEMENT_OPEN[1x23] : [<b>]
    -     *                        |--OPEN[1x23] : [<]
    -     *                        |--HTML_TAG_NAME[1x24] : [b]
    -     *                        |--CLOSE[1x25] : [>]
    -     *                    |--TEXT[1x26] : [connection]
    -     *                    |--HTML_ELEMENT_CLOSE[1x36] : [</b>]
    -     *                        |--OPEN[1x36] : [<]
    -     *                        |--SLASH[1x37] : [/]
    -     *                        |--HTML_TAG_NAME[1x38] : [b]
    -     *                        |--CLOSE[1x39] : [>]
    -     *            |--TEXT[1x40] : [ problems occur]
    -     * }
    -     * 
    - */ - public static final int DESCRIPTION = JavadocParser.RULE_description + RULE_TYPES_OFFSET; - - /** * Exception class name. First argument in {@link #THROWS_LITERAL @throws} and * {@link #EXCEPTION_LITERAL @exception} Javadoc tags. * - *

    - * Example: + *

    Example:

    *
    {@code @throws IOException connection problems}
    * Tree: *
    @@ -1151,8 +896,7 @@
         /**
          * First argument in {@link #PARAM_LITERAL @param} Javadoc tag.
          *
    -     * 

    - * Example: + *

    Example:

    *
    {@code @param T The bar.}
    * Tree: *
    @@ -1167,7 +911,7 @@
          * 
    * * @see - * + * * Oracle Docs * @see #PARAM_LITERAL */ @@ -1177,8 +921,7 @@ * 'exclude' literal. * One of three possible {@link #SERIAL_LITERAL @serial} tag arguments. * - *

    - * Example: + *

    Example:

    *
    {@code @serial exclude}
    * Tree: *
    @@ -1190,7 +933,7 @@
          * 
    * * @see - * + * * Oracle Docs * @see #SERIAL_LITERAL */ @@ -1200,8 +943,7 @@ * 'include' literal. * One of three possible {@link #SERIAL_LITERAL @serial} tag arguments. * - *

    - * Example: + *

    Example:

    *
    {@code @serial include}
    * Tree: *
    @@ -1213,7 +955,7 @@
          * 
    * * @see - * + * * Oracle Docs * @see #SERIAL_LITERAL */ @@ -1222,8 +964,7 @@ /** * Field name. First argument of {@link #SERIAL_FIELD_LITERAL @serialField} Javadoc tag. * - *

    - * Example: + *

    Example:

    *
    {@code @serialField counter Integer objects counter}
    * Tree: *
    @@ -1240,7 +981,7 @@
          * 
    * * @see - * + * * Oracle Docs * @see #SERIAL_FIELD_LITERAL */ @@ -1249,8 +990,7 @@ /** * Field type. Second argument of {@link #SERIAL_FIELD_LITERAL @serialField} Javadoc tag. * - *

    - * Example: + *

    Example:

    *
    {@code @serialField counter Integer objects counter}
    * Tree: *
    @@ -1267,7 +1007,7 @@
          * 
    * * @see - * + * * Oracle Docs * @see #SERIAL_FIELD_LITERAL */ @@ -1278,47 +1018,16 @@ //--------------------------------------------------------------------------------------------// /** - * Parent node for all html tags. + * Identifier inside HTML tag: tag name or attribute name. */ - public static final int HTML_ELEMENT = JavadocParser.RULE_htmlElement - + RULE_TYPES_OFFSET; - - /** - * Open html tag: <XXX>. - */ - public static final int HTML_ELEMENT_OPEN = JavadocParser.RULE_htmlElementOpen - + RULE_TYPES_OFFSET - + RULE_TYPES_OFFSET; - - /** - * Close html tag: <XXX>. - */ - public static final int HTML_ELEMENT_CLOSE = JavadocParser.RULE_htmlElementClose - + RULE_TYPES_OFFSET; - - /** - * Non-special HTML tag. - */ - public static final int HTML_TAG = JavadocParser.RULE_htmlTag + RULE_TYPES_OFFSET; - - /** - * Identifier inside HTML tag: tag name or attribute name. - */ - public static final int HTML_TAG_NAME = JavadocParser.HTML_TAG_NAME; - - /** - * Html tag attribute. Parent node for: {@code HTML_TAG_IDENT, EQUALS, ATTR_VALUE}. - */ - public static final int ATTRIBUTE = JavadocParser.RULE_attribute - + RULE_TYPES_OFFSET - + RULE_TYPES_OFFSET; + public static final int HTML_TAG_NAME = JavadocParser.HTML_TAG_NAME; // HTML tag components /** - * Open html tag component: {@code '<'}. + * Start html tag component: {@code '<'}. */ - public static final int OPEN = JavadocParser.OPEN; + public static final int START = JavadocParser.START; /** * Slash html tag component: {@code '/'}. @@ -1326,14 +1035,14 @@ public static final int SLASH = JavadocParser.SLASH; /** - * Close html tag component: {@code '>'}. + * End html tag component: {@code '>'}. */ - public static final int CLOSE = JavadocParser.CLOSE; + public static final int END = JavadocParser.END; /** * Slash close html tag component: {@code '/>'}. */ - public static final int SLASH_CLOSE = JavadocParser.SLASH_CLOSE; + public static final int SLASH_END = JavadocParser.SLASH_END; /** * Equals html tag component: {@code '='}. @@ -1345,232 +1054,106 @@ */ public static final int ATTR_VALUE = JavadocParser.ATTR_VALUE; - /////////////////////// HTML TAGS WITH OPTIONAL CLOSE TAG ///////////////////////////////////// - /** Paragraph html tag: {@code

    }. */ - public static final int PARAGRAPH = JavadocParser.RULE_paragraph + RULE_TYPES_OFFSET; - /** Open paragraph tag. */ - public static final int P_TAG_OPEN = JavadocParser.RULE_pTagOpen + RULE_TYPES_OFFSET; - /** Close paragraph tag. */ - public static final int P_TAG_CLOSE = JavadocParser.RULE_pTagClose + RULE_TYPES_OFFSET; + /////////////////////// HTML TAGS WITH OPTIONAL END TAG ///////////////////////////////////// /** Paragraph tag name. */ public static final int P_HTML_TAG_NAME = JavadocParser.P_HTML_TAG_NAME; - /** List item html tag: {@code
  • }. */ - public static final int LI = JavadocParser.RULE_li + RULE_TYPES_OFFSET; - /** Open list item tag. */ - public static final int LI_TAG_OPEN = JavadocParser.RULE_liTagOpen + RULE_TYPES_OFFSET; - /** Close list item tag. */ - public static final int LI_TAG_CLOSE = JavadocParser.RULE_liTagClose + RULE_TYPES_OFFSET; /** List item tag name. */ public static final int LI_HTML_TAG_NAME = JavadocParser.LI_HTML_TAG_NAME; - /** Table row html tag: {@code }. */ - public static final int TR = JavadocParser.RULE_tr + RULE_TYPES_OFFSET; - /** Open table row tag. */ - public static final int TR_TAG_OPEN = JavadocParser.RULE_trTagOpen + RULE_TYPES_OFFSET; - /** Close table row tag. */ - public static final int TR_TAG_CLOSE = JavadocParser.RULE_trTagClose + RULE_TYPES_OFFSET; /** Table row tag name. */ public static final int TR_HTML_TAG_NAME = JavadocParser.TR_HTML_TAG_NAME; - /** Table cell html tag: {@code }. */ - public static final int TD = JavadocParser.RULE_td + RULE_TYPES_OFFSET; - /** Open table cell tag. */ - public static final int TD_TAG_OPEN = JavadocParser.RULE_tdTagOpen + RULE_TYPES_OFFSET; - /** Close table cell tag. */ - public static final int TD_TAG_CLOSE = JavadocParser.RULE_tdTagClose + RULE_TYPES_OFFSET; /** Table cell tag name. */ public static final int TD_HTML_TAG_NAME = JavadocParser.TD_HTML_TAG_NAME; - /** Table header cell html tag: {@code }. */ - public static final int TH = JavadocParser.RULE_th + RULE_TYPES_OFFSET; - /** Open table header cell tag. */ - public static final int TH_TAG_OPEN = JavadocParser.RULE_thTagOpen + RULE_TYPES_OFFSET; - /** Close table header cell tag. */ - public static final int TH_TAG_CLOSE = JavadocParser.RULE_thTagClose + RULE_TYPES_OFFSET; /** Table header cell tag name. */ public static final int TH_HTML_TAG_NAME = JavadocParser.TH_HTML_TAG_NAME; - /** Body html tag. */ - public static final int BODY = JavadocParser.RULE_body + RULE_TYPES_OFFSET; - /** Open body tag. */ - public static final int BODY_TAG_OPEN = JavadocParser.RULE_bodyTagOpen + RULE_TYPES_OFFSET; - /** Close body tag. */ - public static final int BODY_TAG_CLOSE = JavadocParser.RULE_bodyTagClose + RULE_TYPES_OFFSET; /** Body tag name. */ public static final int BODY_HTML_TAG_NAME = JavadocParser.BODY_HTML_TAG_NAME; - /** Colgroup html tag. */ - public static final int COLGROUP = JavadocParser.RULE_colgroup + RULE_TYPES_OFFSET; - /** Open colgroup tag. */ - public static final int COLGROUP_TAG_OPEN = JavadocParser.RULE_colgroupTagOpen - + RULE_TYPES_OFFSET; - /** Close colgroup tag. */ - public static final int COLGROUP_TAG_CLOSE = JavadocParser.RULE_colgroupTagClose - + RULE_TYPES_OFFSET; /** Colgroup tag name. */ public static final int COLGROUP_HTML_TAG_NAME = JavadocParser.COLGROUP_HTML_TAG_NAME; - /** Description of a term html tag: {@code
    }. */ - public static final int DD = JavadocParser.RULE_dd + RULE_TYPES_OFFSET; - /** Open description of a term tag. */ - public static final int DD_TAG_OPEN = JavadocParser.RULE_ddTagOpen + RULE_TYPES_OFFSET; - /** Close description of a term tag. */ - public static final int DD_TAG_CLOSE = JavadocParser.RULE_ddTagClose + RULE_TYPES_OFFSET; /** Description of a term tag name. */ public static final int DD_HTML_TAG_NAME = JavadocParser.DD_HTML_TAG_NAME; - /** Description term html tag: {@code
    }. */ - public static final int DT = JavadocParser.RULE_dt + RULE_TYPES_OFFSET; - /** Open description term tag. */ - public static final int DT_TAG_OPEN = JavadocParser.RULE_dtTagOpen + RULE_TYPES_OFFSET; - /** Close description term tag. */ - public static final int DT_TAG_CLOSE = JavadocParser.RULE_dtTagClose + RULE_TYPES_OFFSET; /** Description term tag name. */ public static final int DT_HTML_TAG_NAME = JavadocParser.DT_HTML_TAG_NAME; - /** Head html tag. */ - public static final int HEAD = JavadocParser.RULE_head + RULE_TYPES_OFFSET; - /** Open head tag. */ - public static final int HEAD_TAG_OPEN = JavadocParser.RULE_headTagOpen + RULE_TYPES_OFFSET; - /** Close head tag. */ - public static final int HEAD_TAG_CLOSE = JavadocParser.RULE_headTagClose + RULE_TYPES_OFFSET; /** Head tag name. */ public static final int HEAD_HTML_TAG_NAME = JavadocParser.HEAD_HTML_TAG_NAME; - /** Html html tag. */ - public static final int HTML = JavadocParser.RULE_html + RULE_TYPES_OFFSET; - /** Open html tag. */ - public static final int HTML_TAG_OPEN = JavadocParser.RULE_htmlTagOpen + RULE_TYPES_OFFSET; - /** Close html tag. */ - public static final int HTML_TAG_CLOSE = JavadocParser.RULE_htmlTagClose + RULE_TYPES_OFFSET; /** Html tag name. */ public static final int HTML_HTML_TAG_NAME = JavadocParser.HTML_HTML_TAG_NAME; - /** Option html tag. */ - public static final int OPTION = JavadocParser.RULE_option + RULE_TYPES_OFFSET; - /** Open option tag. */ - public static final int OPTION_TAG_OPEN = JavadocParser.RULE_optionTagOpen + RULE_TYPES_OFFSET; - /** Close option tag. */ - public static final int OPTION_TAG_CLOSE = JavadocParser.RULE_optionTagClose - + RULE_TYPES_OFFSET; /** Option tag name. */ public static final int OPTION_HTML_TAG_NAME = JavadocParser.OPTION_HTML_TAG_NAME; - /** Table body html tag. */ - public static final int TBODY = JavadocParser.RULE_tbody + RULE_TYPES_OFFSET; - /** Open table body tag. */ - public static final int TBODY_TAG_OPEN = JavadocParser.RULE_tbodyTagOpen + RULE_TYPES_OFFSET; - /** Close table body tag. */ - public static final int TBODY_TAG_CLOSE = JavadocParser.RULE_tbodyTagClose + RULE_TYPES_OFFSET; /** Table body tag name. */ public static final int TBODY_HTML_TAG_NAME = JavadocParser.TBODY_HTML_TAG_NAME; - /** Table foot html tag. */ - public static final int TFOOT = JavadocParser.RULE_tfoot + RULE_TYPES_OFFSET; - /** Open table foot tag. */ - public static final int TFOOT_TAG_OPEN = JavadocParser.RULE_tfootTagOpen + RULE_TYPES_OFFSET; - /** Close table foot tag. */ - public static final int TFOOT_TAG_CLOSE = JavadocParser.RULE_tfootTagClose + RULE_TYPES_OFFSET; /** Table foot tag name. */ public static final int TFOOT_HTML_TAG_NAME = JavadocParser.TFOOT_HTML_TAG_NAME; - /** Table head html tag. */ - public static final int THEAD = JavadocParser.RULE_thead + RULE_TYPES_OFFSET; - /** Open table head tag. */ - public static final int THEAD_TAG_OPEN = JavadocParser.RULE_theadTagOpen + RULE_TYPES_OFFSET; - /** Close table head tag. */ - public static final int THEAD_TAG_CLOSE = JavadocParser.RULE_theadTagClose + RULE_TYPES_OFFSET; /** Table head tag name. */ public static final int THEAD_HTML_TAG_NAME = JavadocParser.THEAD_HTML_TAG_NAME; /////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////// SINGLETON HTML TAGS ////////////////////////////////////////////////// - /** - * Parent node for all singleton html tags. - */ - public static final int SINGLETON_ELEMENT = JavadocParser.RULE_singletonElement - + RULE_TYPES_OFFSET; - - /** - * Non-special singleton html tag. - */ - public static final int SINGLETON_TAG = JavadocParser.RULE_singletonTag - + RULE_TYPES_OFFSET; - - /** Area html tag. */ - public static final int AREA_TAG = JavadocParser.RULE_areaTag + RULE_TYPES_OFFSET; /** Area tag name. */ public static final int AREA_HTML_TAG_NAME = JavadocParser.AREA_HTML_TAG_NAME; - /** Base html tag. */ - public static final int BASE_TAG = JavadocParser.RULE_baseTag + RULE_TYPES_OFFSET; /** Base tag name. */ public static final int BASE_HTML_TAG_NAME = JavadocParser.BASE_HTML_TAG_NAME; - /** Basefont html tag. */ - public static final int BASEFONT_TAG = JavadocParser.RULE_basefontTag + RULE_TYPES_OFFSET; /** Basefont tag name. */ public static final int BASEFONT_HTML_TAG_NAME = JavadocParser.BASEFONT_HTML_TAG_NAME; - /** Br html tag. */ - public static final int BR_TAG = JavadocParser.RULE_brTag + RULE_TYPES_OFFSET; /** Br tag name. */ public static final int BR_HTML_TAG_NAME = JavadocParser.BR_HTML_TAG_NAME; - /** Col html tag. */ - public static final int COL_TAG = JavadocParser.RULE_colTag + RULE_TYPES_OFFSET; /** Col tag name. */ public static final int COL_HTML_TAG_NAME = JavadocParser.COL_HTML_TAG_NAME; - /** Frame html tag. */ - public static final int FRAME_TAG = JavadocParser.RULE_frameTag + RULE_TYPES_OFFSET; /** Frame tag name. */ public static final int FRAME_HTML_TAG_NAME = JavadocParser.FRAME_HTML_TAG_NAME; - /** Hr html tag. */ - public static final int HR_TAG = JavadocParser.RULE_hrTag + RULE_TYPES_OFFSET; /** Hr tag name. */ public static final int HR_HTML_TAG_NAME = JavadocParser.HR_HTML_TAG_NAME; - /** Img html tag. */ - public static final int IMG_TAG = JavadocParser.RULE_imgTag + RULE_TYPES_OFFSET; /** Img tag name. */ public static final int IMG_HTML_TAG_NAME = JavadocParser.IMG_HTML_TAG_NAME; - /** Input html tag. */ - public static final int INPUT_TAG = JavadocParser.RULE_inputTag + RULE_TYPES_OFFSET; /** Input tag name. */ public static final int INPUT_HTML_TAG_NAME = JavadocParser.INPUT_HTML_TAG_NAME; - /** Isindex html tag. */ - public static final int ISINDEX_TAG = JavadocParser.RULE_isindexTag + RULE_TYPES_OFFSET; /** Isindex tag name. */ public static final int ISINDEX_HTML_TAG_NAME = JavadocParser.ISINDEX_HTML_TAG_NAME; - /** Link html tag. */ - public static final int LINK_TAG = JavadocParser.RULE_linkTag + RULE_TYPES_OFFSET; /** Link tag name. */ public static final int LINK_HTML_TAG_NAME = JavadocParser.LINK_HTML_TAG_NAME; - /** Meta html tag. */ - public static final int META_TAG = JavadocParser.RULE_metaTag + RULE_TYPES_OFFSET; /** Meta tag name. */ public static final int META_HTML_TAG_NAME = JavadocParser.META_HTML_TAG_NAME; - /** Param html tag. */ - public static final int PARAM_TAG = JavadocParser.RULE_paramTag + RULE_TYPES_OFFSET; /** Param tag name. */ public static final int PARAM_HTML_TAG_NAME = JavadocParser.PARAM_HTML_TAG_NAME; + /** "embed" tag name. */ + public static final int EMBED_HTML_TAG_NAME = JavadocParser.EMBED_HTML_TAG_NAME; + /** "keygen" tag name. */ + public static final int KEYGEN_HTML_TAG_NAME = JavadocParser.KEYGEN_HTML_TAG_NAME; + /** "source" tag name. */ + public static final int SOURCE_HTML_TAG_NAME = JavadocParser.SOURCE_HTML_TAG_NAME; + /** "track" tag name. */ + public static final int TRACK_HTML_TAG_NAME = JavadocParser.TRACK_HTML_TAG_NAME; + /** "wbr" tag name. */ + public static final int WBR_HTML_TAG_NAME = JavadocParser.WBR_HTML_TAG_NAME; /////////////////////////////////////////////////////////////////////////////////////////////// - /** Html comment: {@code }. */ - public static final int HTML_COMMENT = JavadocParser.RULE_htmlComment - + RULE_TYPES_OFFSET - + RULE_TYPES_OFFSET; - /** - * HTML comment start symbol '<!--'. + * HTML comment start symbol '<!--'. */ public static final int HTML_COMMENT_START = JavadocParser.HTML_COMMENT_START; @@ -1580,7 +1163,7 @@ public static final int HTML_COMMENT_END = JavadocParser.HTML_COMMENT_END; /** - * <![CDATA[...]]> block. + * <![CDATA[...]]> block. */ public static final int CDATA = JavadocParser.CDATA; @@ -1607,16 +1190,455 @@ public static final int WS = JavadocParser.WS; /** - * CHAR and WS sequence. + * End Of File symbol. */ - public static final int TEXT = JavadocParser.RULE_text + RULE_TYPES_OFFSET; + public static final int EOF = Recognizer.EOF; + + //--------------------------------------------------------------------------------------------// + //------- JAVADOC TAGS DEPENDING ON RULE TYPES OFFSET ----------------------------------------// + //--------------------------------------------------------------------------------------------// + + /** Rule types offset. + * RULE_TYPES_OFFSET constant is used to split lexer tokens types and parser rules types. + * We need unique numbers for all tokens, + * ANTLR do not need this and that is why this types are mixed by used values. + * All values we can take a look at + * target/generated-sources/antlr/com/puppycrawl/tools/checkstyle/grammars/javadoc/JavadocParser.java + * For example: LEADING_ASTERISK=1 and RULE_htmlElement = 1. + * RULE_TYPES_OFFSET required to shift parser rules, + * to let them not overlap with types that have prefix "RULE_". + */ + private static final int RULE_TYPES_OFFSET = 10000; /** - * End Of File symbol. + * Root node of any Javadoc comment. + * Last child is always {@link #EOF}. + * + *

    Tree for example:

    + *
    {@code
    +     * JAVADOC[3x0]
    +     *   |--NEWLINE[3x0] : [\n]
    +     *   |--LEADING_ASTERISK[4x0] : [ *]
    +     *   |--WS[4x2] : [ ]
    +     *   |--JAVADOC_TAG[4x3] : [@param T The bar.\n ]
    +     *       |--PARAM_LITERAL[4x3] : [@param]
    +     *       |--WS[4x9] : [ ]
    +     *       |--PARAMETER_NAME[4x10] : [T]
    +     *       |--WS[4x11] : [ ]
    +     *       |--DESCRIPTION[4x12] : [The bar.\n ]
    +     *           |--TEXT[4x12] : [The bar.]
    +     *           |--NEWLINE[4x20] : [\n]
    +     *           |--TEXT[5x0] : [ ]
    +     *   |--EOF[5x1] : []
    +     * }
    */ - public static final int EOF = Recognizer.EOF; + public static final int JAVADOC = JavadocParser.RULE_javadoc + RULE_TYPES_OFFSET; + + /** + * Javadoc tag. + * + *

    Type of Javadoc tag is resolved by literal node that is first child of this node.

    + * + *

    As literal could be:

    + *
      + *
    • {@link #RETURN_LITERAL}
    • + *
    • {@link #DEPRECATED_LITERAL}
    • + *
    • {@link #SINCE_LITERAL}
    • + *
    • {@link #SERIAL_DATA_LITERAL}
    • + *
    • {@link #SERIAL_FIELD_LITERAL}
    • + *
    • {@link #PARAM_LITERAL}
    • + *
    • {@link #SEE_LITERAL}
    • + *
    • {@link #SERIAL_LITERAL}
    • + *
    • {@link #VERSION_LITERAL}
    • + *
    • {@link #EXCEPTION_LITERAL}
    • + *
    • {@link #THROWS_LITERAL}
    • + *
    • {@link #AUTHOR_LITERAL}
    • + *
    • or {@link #CUSTOM_NAME} if it is custom Javadoc tag.
    • + *
    + * + *

    Example

    + *
    {@code @param T The bar.}
    + * Tree + *
    {@code
    +     *   |--JAVADOC_TAG[4x3] : [@param T The bar.]
    +     *       |--PARAM_LITERAL[4x3] : [@param]
    +     *       |--WS[4x9] : [ ]
    +     *       |--PARAMETER_NAME[4x10] : [T]
    +     *       |--WS[4x11] : [ ]
    +     *       |--DESCRIPTION[4x12] : [The bar.]
    +     *           |--TEXT[4x12] : [The bar.]
    +     * }
    + */ + + public static final int JAVADOC_TAG = JavadocParser.RULE_javadocTag + RULE_TYPES_OFFSET; + /** + * Javadoc inline tag. + * + *

    Type of Javadoc inline tag is resolved by literal node that is second child of this node. + * First child is always {@link #JAVADOC_INLINE_TAG_START} and last node is always + * {@link #JAVADOC_INLINE_TAG_END}.

    + * + *

    As literal could be:

    + *
      + *
    • {@link #CODE_LITERAL}
    • + *
    • {@link #DOC_ROOT_LITERAL}
    • + *
    • {@link #LINK_LITERAL}
    • + *
    • {@link #INHERIT_DOC_LITERAL}
    • + *
    • {@link #LINKPLAIN_LITERAL}
    • + *
    • {@link #LITERAL_LITERAL}
    • + *
    • {@link #VALUE_LITERAL}
    • + *
    • or {@link #CUSTOM_NAME} if it is custom Javadoc inline tag.
    • + *
    + * + *

    Example:

    + *
    {@link String}
    + * Tree: + *
    +     *  |--JAVADOC_INLINE_TAG[4x3] : [@link String}]
    +     *        |--JAVADOC_INLINE_TAG_START[4x3] : [{]
    +     *        |--LINK_LITERAL[4x4] : [@link]
    +     *        |--WS[4x9] : [ ]
    +     *        |--REFERENCE[4x10] : [String]
    +     *            |--CLASS[4x10] : [String]
    +     *        |--JAVADOC_INLINE_TAG_END[4x16] : [}]
    +     * 
    +     * 
    + * @noinspection HtmlTagCanBeJavadocTag + */ + public static final int JAVADOC_INLINE_TAG = JavadocParser.RULE_javadocInlineTag + + RULE_TYPES_OFFSET; + + /** + * Parameter of the Javadoc tags listed below. + *
      + *
    • {@link #SEE_LITERAL @see}
    • + *
    • {@link #LINK_LITERAL {@link}}
    • + *
    • {@link #LINKPLAIN_LITERAL {@linkplain}}
    • + *
    • {@link #VALUE_LITERAL {@value}}
    • + *
    + */ + public static final int REFERENCE = JavadocParser.RULE_reference + RULE_TYPES_OFFSET; + + /** + * Parameters part in {@link #REFERENCE}. + * It is used to specify parameters for {@link #MEMBER method}. + * Always contains {@link #LEFT_BRACE} as first child and {@link #RIGHT_BRACE} as last child. + * Each parameter is represented by {@link #ARGUMENT} node. + * Arguments in braces are separated by {@link #COMMA} (and optional {@link #WS}). + * + *

    Example:

    + *
    {@code @see #method(Processor, String)}
    + * Tree: + *
    +     * {@code |--JAVADOC_TAG[1x0] : [@see #method(Processor, String)]
    +     *        |--SEE_LITERAL[1x0] : [@see]
    +     *        |--WS[1x4] : [ ]
    +     *        |--REFERENCE[1x5] : [#method(Processor, String)]
    +     *            |--HASH[1x5] : [#]
    +     *            |--MEMBER[1x6] : [method]
    +     *            |--PARAMETERS[1x12] : [(Processor, String)]
    +     *                |--LEFT_BRACE[1x12] : [(]
    +     *                |--ARGUMENT[1x13] : [Processor]
    +     *                |--COMMA[1x22] : [,]
    +     *                |--WS[1x23] : [ ]
    +     *                |--ARGUMENT[1x24] : [String]
    +     *                |--RIGHT_BRACE[1x30] : [)]
    +     * }
    +     * 
    + */ + public static final int PARAMETERS = JavadocParser.RULE_parameters + RULE_TYPES_OFFSET; + + /** + * Description node. It contains: + *
      + *
    • {@link #TEXT}
    • + *
    • {@link #WS}
    • + *
    • {@link #NEWLINE}
    • + *
    • {@link #HTML_ELEMENT}
    • + *
    + * + *

    It is argument for many Javadoc tags and inline tags.

    + * + *

    Example:

    + *
    {@code @throws IOException if connection problems occur}
    + * Tree: + *
    +     * {@code |--JAVADOC_TAG[1x0] : [@throws IOException if connection problems occur]
    +     *        |--THROWS_LITERAL[1x0] : [@throws]
    +     *        |--WS[1x7] : [ ]
    +     *        |--CLASS_NAME[1x8] : [IOException]
    +     *        |--WS[1x19] : [ ]
    +     *        |--DESCRIPTION[1x20] : [if connection problems occur]
    +     *            |--TEXT[1x20] : [if ]
    +     *            |--HTML_ELEMENT[1x23] : [connection]
    +     *                |--HTML_TAG[1x23] : [connection]
    +     *                    |--HTML_ELEMENT_START[1x23] : []
    +     *                        |--START[1x23] : [<]
    +     *                        |--HTML_TAG_NAME[1x24] : [b]
    +     *                        |--END[1x25] : [>]
    +     *                    |--TEXT[1x26] : [connection]
    +     *                    |--HTML_ELEMENT_END[1x36] : []
    +     *                        |--START[1x36] : [<]
    +     *                        |--SLASH[1x37] : [/]
    +     *                        |--HTML_TAG_NAME[1x38] : [b]
    +     *                        |--END[1x39] : [>]
    +     *            |--TEXT[1x40] : [ problems occur]
    +     * }
    +     * 
    + */ + public static final int DESCRIPTION = JavadocParser.RULE_description + RULE_TYPES_OFFSET; + + //--------------------------------------------------------------------------------------------// + //--------- HTML TAGS DEPENDING ON RULE TYPES OFFSET -----------------------------------------// + //--------------------------------------------------------------------------------------------// + + /** + * Parent node for all html tags. + */ + public static final int HTML_ELEMENT = JavadocParser.RULE_htmlElement + + RULE_TYPES_OFFSET; + + /** + * Start html tag: <XXX>. + */ + public static final int HTML_ELEMENT_START = JavadocParser.RULE_htmlElementStart + + RULE_TYPES_OFFSET; + + /** + * End html tag: <XXX>. + */ + public static final int HTML_ELEMENT_END = JavadocParser.RULE_htmlElementEnd + + RULE_TYPES_OFFSET; + + /** + * Non-special HTML tag. + */ + public static final int HTML_TAG = JavadocParser.RULE_htmlTag + RULE_TYPES_OFFSET; + + /** + * Html tag attribute. Parent node for: {@code HTML_TAG_IDENT, EQUALS, ATTR_VALUE}. + */ + public static final int ATTRIBUTE = JavadocParser.RULE_attribute + + RULE_TYPES_OFFSET; + + /////////////////////// HTML TAGS WITH OPTIONAL END TAG ///////////////////////////////////// + /** Paragraph html tag: {@code

    }. */ + public static final int PARAGRAPH = JavadocParser.RULE_paragraph + RULE_TYPES_OFFSET; + /** Start paragraph tag. */ + public static final int P_TAG_START = JavadocParser.RULE_pTagStart + RULE_TYPES_OFFSET; + /** End paragraph tag. */ + public static final int P_TAG_END = JavadocParser.RULE_pTagEnd + RULE_TYPES_OFFSET; + /** List item html tag: {@code
  • }. */ + + public static final int LI = JavadocParser.RULE_li + RULE_TYPES_OFFSET; + /** Start list item tag. */ + public static final int LI_TAG_START = JavadocParser.RULE_liTagStart + RULE_TYPES_OFFSET; + /** End list item tag. */ + public static final int LI_TAG_END = JavadocParser.RULE_liTagEnd + RULE_TYPES_OFFSET; + + /** Table row html tag: {@code }. */ + public static final int TR = JavadocParser.RULE_tr + RULE_TYPES_OFFSET; + /** Start table row tag. */ + public static final int TR_TAG_START = JavadocParser.RULE_trTagStart + RULE_TYPES_OFFSET; + /** End table row tag. */ + public static final int TR_TAG_END = JavadocParser.RULE_trTagEnd + RULE_TYPES_OFFSET; + + /** Table cell html tag: {@code }. */ + public static final int TD = JavadocParser.RULE_td + RULE_TYPES_OFFSET; + /** Start table cell tag. */ + public static final int TD_TAG_START = JavadocParser.RULE_tdTagStart + RULE_TYPES_OFFSET; + /** End table cell tag. */ + public static final int TD_TAG_END = JavadocParser.RULE_tdTagEnd + RULE_TYPES_OFFSET; + + /** Table header cell html tag: {@code }. */ + public static final int TH = JavadocParser.RULE_th + RULE_TYPES_OFFSET; + /** Start table header cell tag. */ + public static final int TH_TAG_START = JavadocParser.RULE_thTagStart + RULE_TYPES_OFFSET; + /** End table header cell tag. */ + public static final int TH_TAG_END = JavadocParser.RULE_thTagEnd + RULE_TYPES_OFFSET; + + /** Body html tag. */ + public static final int BODY = JavadocParser.RULE_body + RULE_TYPES_OFFSET; + /** Start body tag. */ + public static final int BODY_TAG_START = JavadocParser.RULE_bodyTagStart + RULE_TYPES_OFFSET; + /** End body tag. */ + public static final int BODY_TAG_END = JavadocParser.RULE_bodyTagEnd + RULE_TYPES_OFFSET; + + /** Colgroup html tag. */ + public static final int COLGROUP = JavadocParser.RULE_colgroup + RULE_TYPES_OFFSET; + /** Start colgroup tag. */ + public static final int COLGROUP_TAG_START = JavadocParser.RULE_colgroupTagStart + + RULE_TYPES_OFFSET; + /** End colgroup tag. */ + public static final int COLGROUP_TAG_END = JavadocParser.RULE_colgroupTagEnd + + RULE_TYPES_OFFSET; + + /** Description of a term html tag: {@code
    }. */ + public static final int DD = JavadocParser.RULE_dd + RULE_TYPES_OFFSET; + /** Start description of a term tag. */ + public static final int DD_TAG_START = JavadocParser.RULE_ddTagStart + RULE_TYPES_OFFSET; + /** End description of a term tag. */ + public static final int DD_TAG_END = JavadocParser.RULE_ddTagEnd + RULE_TYPES_OFFSET; + + /** Description term html tag: {@code
    }. */ + public static final int DT = JavadocParser.RULE_dt + RULE_TYPES_OFFSET; + /** Start description term tag. */ + public static final int DT_TAG_START = JavadocParser.RULE_dtTagStart + RULE_TYPES_OFFSET; + /** End description term tag. */ + public static final int DT_TAG_END = JavadocParser.RULE_dtTagEnd + RULE_TYPES_OFFSET; + + /** Head html tag. */ + public static final int HEAD = JavadocParser.RULE_head + RULE_TYPES_OFFSET; + /** Start head tag. */ + public static final int HEAD_TAG_START = JavadocParser.RULE_headTagStart + RULE_TYPES_OFFSET; + /** End head tag. */ + public static final int HEAD_TAG_END = JavadocParser.RULE_headTagEnd + RULE_TYPES_OFFSET; + + /** Html html tag. */ + public static final int HTML = JavadocParser.RULE_html + RULE_TYPES_OFFSET; + /** Start html tag. */ + public static final int HTML_TAG_START = JavadocParser.RULE_htmlTagStart + RULE_TYPES_OFFSET; + /** End html tag. */ + public static final int HTML_TAG_END = JavadocParser.RULE_htmlTagEnd + RULE_TYPES_OFFSET; + + /** Option html tag. */ + public static final int OPTION = JavadocParser.RULE_option + RULE_TYPES_OFFSET; + /** Start option tag. */ + public static final int OPTION_TAG_START = + JavadocParser.RULE_optionTagStart + RULE_TYPES_OFFSET; + /** End option tag. */ + public static final int OPTION_TAG_END = JavadocParser.RULE_optionTagEnd + + RULE_TYPES_OFFSET; + + /** Table body html tag. */ + public static final int TBODY = JavadocParser.RULE_tbody + RULE_TYPES_OFFSET; + /** Start table body tag. */ + public static final int TBODY_TAG_START = JavadocParser.RULE_tbodyTagStart + RULE_TYPES_OFFSET; + /** End table body tag. */ + public static final int TBODY_TAG_END = JavadocParser.RULE_tbodyTagEnd + RULE_TYPES_OFFSET; + + /** Table foot html tag. */ + public static final int TFOOT = JavadocParser.RULE_tfoot + RULE_TYPES_OFFSET; + /** Start table foot tag. */ + public static final int TFOOT_TAG_START = JavadocParser.RULE_tfootTagStart + RULE_TYPES_OFFSET; + /** End table foot tag. */ + public static final int TFOOT_TAG_END = JavadocParser.RULE_tfootTagEnd + RULE_TYPES_OFFSET; + + /** Table head html tag. */ + public static final int THEAD = JavadocParser.RULE_thead + RULE_TYPES_OFFSET; + /** Start table head tag. */ + public static final int THEAD_TAG_START = JavadocParser.RULE_theadTagStart + RULE_TYPES_OFFSET; + /** End table head tag. */ + public static final int THEAD_TAG_END = JavadocParser.RULE_theadTagEnd + RULE_TYPES_OFFSET; + + /////////////////////// SINGLETON HTML TAGS ////////////////////////////////////////////////// + /** + * Parent node for all singleton html tags. + */ + public static final int SINGLETON_ELEMENT = JavadocParser.RULE_singletonElement + + RULE_TYPES_OFFSET; + + /** + * Non-special empty html tag. + */ + public static final int EMPTY_TAG = JavadocParser.RULE_emptyTag + + RULE_TYPES_OFFSET; + + /** Area html tag. */ + public static final int AREA_TAG = JavadocParser.RULE_areaTag + RULE_TYPES_OFFSET; + + /** Base html tag. */ + public static final int BASE_TAG = JavadocParser.RULE_baseTag + RULE_TYPES_OFFSET; + + /** Basefont html tag. */ + public static final int BASEFONT_TAG = JavadocParser.RULE_basefontTag + RULE_TYPES_OFFSET; + + /** Br html tag. */ + public static final int BR_TAG = JavadocParser.RULE_brTag + RULE_TYPES_OFFSET; + + /** Col html tag. */ + public static final int COL_TAG = JavadocParser.RULE_colTag + RULE_TYPES_OFFSET; + + /** Frame html tag. */ + public static final int FRAME_TAG = JavadocParser.RULE_frameTag + RULE_TYPES_OFFSET; + + /** Hr html tag. */ + public static final int HR_TAG = JavadocParser.RULE_hrTag + RULE_TYPES_OFFSET; + + /** Img html tag. */ + public static final int IMG_TAG = JavadocParser.RULE_imgTag + RULE_TYPES_OFFSET; + + /** Input html tag. */ + public static final int INPUT_TAG = JavadocParser.RULE_inputTag + RULE_TYPES_OFFSET; + + /** Isindex html tag. */ + public static final int ISINDEX_TAG = JavadocParser.RULE_isindexTag + RULE_TYPES_OFFSET; + + /** Link html tag. */ + public static final int LINK_TAG = JavadocParser.RULE_linkTag + RULE_TYPES_OFFSET; + + /** Meta html tag. */ + public static final int META_TAG = JavadocParser.RULE_metaTag + RULE_TYPES_OFFSET; + + /** Param html tag. */ + public static final int PARAM_TAG = JavadocParser.RULE_paramTag + RULE_TYPES_OFFSET; + + /** + * HTML void element {@code }. + * @see #SINGLETON_ELEMENT + * @see + * W3 docs + */ + public static final int EMBED_TAG = JavadocParser.RULE_embedTag + RULE_TYPES_OFFSET; + + /** + * HTML void element {@code }. + * @see #SINGLETON_ELEMENT + * @see + * W3 docs + */ + public static final int KEYGEN_TAG = JavadocParser.RULE_keygenTag + RULE_TYPES_OFFSET; + + /** + * HTML void element {@code }. + * @see #SINGLETON_ELEMENT + * @see + * W3 docs + */ + public static final int SOURCE_TAG = JavadocParser.RULE_sourceTag + RULE_TYPES_OFFSET; + + /** + * HTML void element {@code }. + * @see #SINGLETON_ELEMENT + * @see + * W3 docs + */ + public static final int TRACK_TAG = JavadocParser.RULE_trackTag + RULE_TYPES_OFFSET; + + /** + * HTML void element {@code }. + * @see #SINGLETON_ELEMENT + * @see + * W3 docs + */ + public static final int WBR_TAG = JavadocParser.RULE_wbrTag + RULE_TYPES_OFFSET; + + /////////////////////////////////////////////////////////////////////////////////////////////// + + /** Html comment: <!-- -->. + * @noinspection HtmlTagCanBeJavadocTag + */ + public static final int HTML_COMMENT = JavadocParser.RULE_htmlComment + + RULE_TYPES_OFFSET; + /** + * CHAR and WS sequence. + */ + public static final int TEXT = JavadocParser.RULE_text + RULE_TYPES_OFFSET; /** Empty private constructor of the current class. */ private JavadocTokenTypes() { } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/LineColumn.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/LineColumn.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/LineColumn.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/LineColumn.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -62,12 +62,14 @@ @Override public int compareTo(LineColumn lineColumn) { + final int result; if (line == lineColumn.line) { - return Integer.compare(column, lineColumn.column); + result = Integer.compare(column, lineColumn.column); } else { - return Integer.compare(line, lineColumn.line); + result = Integer.compare(line, lineColumn.line); } + return result; } @Override @@ -87,4 +89,5 @@ public int hashCode() { return Objects.hash(line, column); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/LocalizedMessage.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/LocalizedMessage.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/LocalizedMessage.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/LocalizedMessage.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -26,6 +26,7 @@ import java.io.Serializable; import java.net.URL; import java.net.URLConnection; +import java.nio.charset.StandardCharsets; import java.text.MessageFormat; import java.util.Arrays; import java.util.Collections; @@ -45,9 +46,11 @@ * * @author Oliver Burn * @author lkuehne + * @noinspection SerializableHasSerializationMethods, ClassWithTooManyConstructors */ public final class LocalizedMessage implements Comparable, Serializable { + private static final long serialVersionUID = 5675176836184862150L; /** @@ -55,7 +58,7 @@ * Avoids repetitive calls to ResourceBundle.getBundle(). */ private static final Map BUNDLE_CACHE = - Collections.synchronizedMap(new HashMap()); + Collections.synchronizedMap(new HashMap<>()); /** The default severity level if one is not specified. */ private static final SeverityLevel DEFAULT_SEVERITY = SeverityLevel.ERROR; @@ -67,6 +70,10 @@ private final int lineNo; /** The column number. **/ private final int columnNo; + /** The column char index. **/ + private final int columnCharIndex; + /** The token type constant. See {@link TokenTypes}. **/ + private final int tokenType; /** The severity level. **/ private final SeverityLevel severityLevel; @@ -77,7 +84,9 @@ /** Key for the message format. **/ private final String key; - /** Arguments for MessageFormat. **/ + /** Arguments for MessageFormat. + * @noinspection NonSerializableFieldInSerializableClass + */ private final Object[] args; /** Name of the resource bundle to get messages from. **/ @@ -94,6 +103,8 @@ * * @param lineNo line number associated with the message * @param columnNo column number associated with the message + * @param columnCharIndex column char index associated with the message + * @param tokenType token type of the event associated with the message. See {@link TokenTypes} * @param bundle resource bundle name * @param key the key to locate the translation * @param args arguments for the translation @@ -101,9 +112,13 @@ * @param moduleId the id of the module the message is associated with * @param sourceClass the Class that is the source of the message * @param customMessage optional custom message overriding the default + * @noinspection ConstructorWithTooManyParameters */ + // -@cs[ParameterNumber] Class is immutable, we need that amount of arguments. public LocalizedMessage(int lineNo, int columnNo, + int columnCharIndex, + int tokenType, String bundle, String key, Object[] args, @@ -113,6 +128,8 @@ String customMessage) { this.lineNo = lineNo; this.columnNo = columnNo; + this.columnCharIndex = columnCharIndex; + this.tokenType = tokenType; this.key = key; if (args == null) { @@ -133,13 +150,73 @@ * * @param lineNo line number associated with the message * @param columnNo column number associated with the message + * @param tokenType token type of the event associated with the message. See {@link TokenTypes} + * @param bundle resource bundle name + * @param key the key to locate the translation + * @param args arguments for the translation + * @param severityLevel severity level for the message + * @param moduleId the id of the module the message is associated with + * @param sourceClass the Class that is the source of the message + * @param customMessage optional custom message overriding the default + * @noinspection ConstructorWithTooManyParameters + */ + // -@cs[ParameterNumber] Class is immutable, we need that amount of arguments. + public LocalizedMessage(int lineNo, + int columnNo, + int tokenType, + String bundle, + String key, + Object[] args, + SeverityLevel severityLevel, + String moduleId, + Class sourceClass, + String customMessage) { + this(lineNo, columnNo, columnNo, tokenType, bundle, key, args, severityLevel, moduleId, + sourceClass, customMessage); + } + + /** + * Creates a new {@code LocalizedMessage} instance. + * + * @param lineNo line number associated with the message + * @param columnNo column number associated with the message + * @param bundle resource bundle name + * @param key the key to locate the translation + * @param args arguments for the translation + * @param severityLevel severity level for the message + * @param moduleId the id of the module the message is associated with + * @param sourceClass the Class that is the source of the message + * @param customMessage optional custom message overriding the default + * @noinspection ConstructorWithTooManyParameters + */ + // -@cs[ParameterNumber] Class is immutable, we need that amount of arguments. + public LocalizedMessage(int lineNo, + int columnNo, + String bundle, + String key, + Object[] args, + SeverityLevel severityLevel, + String moduleId, + Class sourceClass, + String customMessage) { + this(lineNo, columnNo, 0, bundle, key, args, severityLevel, moduleId, sourceClass, + customMessage); + } + + /** + * Creates a new {@code LocalizedMessage} instance. + * + * @param lineNo line number associated with the message + * @param columnNo column number associated with the message * @param bundle resource bundle name * @param key the key to locate the translation * @param args arguments for the translation * @param moduleId the id of the module the message is associated with * @param sourceClass the Class that is the source of the message * @param customMessage optional custom message overriding the default + * @noinspection ConstructorWithTooManyParameters */ + // -@cs[ParameterNumber] Class is immutable, we need that amount of arguments. public LocalizedMessage(int lineNo, int columnNo, String bundle, @@ -170,7 +247,9 @@ * @param moduleId the id of the module the message is associated with * @param sourceClass the source class for the message * @param customMessage optional custom message overriding the default + * @noinspection ConstructorWithTooManyParameters */ + // -@cs[ParameterNumber] Class is immutable, we need that amount of arguments. public LocalizedMessage(int lineNo, String bundle, String key, @@ -194,6 +273,7 @@ * @param moduleId the id of the module the message is associated with * @param sourceClass the name of the source for the message * @param customMessage optional custom message overriding the default + * @noinspection ConstructorWithTooManyParameters */ public LocalizedMessage( int lineNo, @@ -207,6 +287,7 @@ sourceClass, customMessage); } + // -@cs[CyclomaticComplexity] equals - a lot of fields to check. @Override public boolean equals(Object object) { if (this == object) { @@ -218,6 +299,8 @@ final LocalizedMessage localizedMessage = (LocalizedMessage) object; return Objects.equals(lineNo, localizedMessage.lineNo) && Objects.equals(columnNo, localizedMessage.columnNo) + && Objects.equals(columnCharIndex, localizedMessage.columnCharIndex) + && Objects.equals(tokenType, localizedMessage.tokenType) && Objects.equals(severityLevel, localizedMessage.severityLevel) && Objects.equals(moduleId, localizedMessage.moduleId) && Objects.equals(key, localizedMessage.key) @@ -229,15 +312,13 @@ @Override public int hashCode() { - return Objects.hash(lineNo, columnNo, severityLevel, moduleId, key, bundle, sourceClass, - customMessage, Arrays.hashCode(args)); + return Objects.hash(lineNo, columnNo, columnCharIndex, tokenType, severityLevel, moduleId, + key, bundle, sourceClass, customMessage, Arrays.hashCode(args)); } /** Clears the cache. */ public static void clearCache() { - synchronized (BUNDLE_CACHE) { - BUNDLE_CACHE.clear(); - } + BUNDLE_CACHE.clear(); } /** @@ -275,12 +356,12 @@ * if there is no custom message */ private String getCustomMessage() { - - if (customMessage == null) { - return null; + String message = null; + if (customMessage != null) { + final MessageFormat formatter = new MessageFormat(customMessage, Locale.ROOT); + message = formatter.format(args); } - final MessageFormat formatter = new MessageFormat(customMessage, Locale.ROOT); - return formatter.format(args); + return message; } /** @@ -291,16 +372,8 @@ * @return a ResourceBundle */ private ResourceBundle getBundle(String bundleName) { - synchronized (BUNDLE_CACHE) { - ResourceBundle resourceBundle = BUNDLE_CACHE - .get(bundleName); - if (resourceBundle == null) { - resourceBundle = ResourceBundle.getBundle(bundleName, sLocale, - sourceClass.getClassLoader(), new Utf8Control()); - BUNDLE_CACHE.put(bundleName, resourceBundle); - } - return resourceBundle; - } + return BUNDLE_CACHE.computeIfAbsent(bundleName, name -> ResourceBundle.getBundle( + name, sLocale, sourceClass.getClassLoader(), new Utf8Control())); } /** @@ -320,6 +393,22 @@ } /** + * Gets the column char index. + * @return the column char index + */ + public int getColumnCharIndex() { + return columnCharIndex; + } + + /** + * Gets the token type. + * @return the token type + */ + public int getTokenType() { + return tokenType; + } + + /** * Gets the severity level. * @return the severity level */ @@ -328,6 +417,7 @@ } /** + * Returns id of module. * @return the module identifier. */ public String getModuleId() { @@ -357,6 +447,7 @@ * @param locale the locale to use for localization */ public static void setLocale(Locale locale) { + clearCache(); if (Locale.ENGLISH.getLanguage().equals(locale.getLanguage())) { sLocale = Locale.ROOT; } @@ -371,28 +462,44 @@ @Override public int compareTo(LocalizedMessage other) { - int result = Integer.compare(lineNo, other.lineNo); + final int result; if (lineNo == other.lineNo) { if (columnNo == other.columnNo) { - result = getMessage().compareTo(other.getMessage()); + if (Objects.equals(moduleId, other.moduleId)) { + result = getMessage().compareTo(other.getMessage()); + } + else if (moduleId == null) { + result = -1; + } + else if (other.moduleId == null) { + result = 1; + } + else { + result = moduleId.compareTo(other.moduleId); + } } else { result = Integer.compare(columnNo, other.columnNo); } } + else { + result = Integer.compare(lineNo, other.lineNo); + } return result; } /** *

    * Custom ResourceBundle.Control implementation which allows explicitly read - * the properties files as UTF-8 + * the properties files as UTF-8. *

    * * @author Aleksey Nesterenko + * @noinspection IOResourceOpenedButNotSafelyClosed */ - protected static class Utf8Control extends Control { + public static class Utf8Control extends Control { + @Override public ResourceBundle newBundle(String aBaseName, Locale aLocale, String aFormat, ClassLoader aLoader, boolean aReload) throws IOException { @@ -415,7 +522,8 @@ } ResourceBundle resourceBundle = null; if (stream != null) { - final Reader streamReader = new InputStreamReader(stream, "UTF-8"); + final Reader streamReader = new InputStreamReader(stream, + StandardCharsets.UTF_8.name()); try { // Only this line is changed to make it to read properties files as UTF-8. resourceBundle = new PropertyResourceBundle(streamReader); @@ -426,5 +534,7 @@ } return resourceBundle; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/LocalizedMessages.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/LocalizedMessages.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/LocalizedMessages.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/LocalizedMessages.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,63 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.api; - -import java.util.Set; -import java.util.SortedSet; - -import com.google.common.collect.Sets; - -/** - * Collection of messages. - * @author Oliver Burn - */ -public final class LocalizedMessages { - /** Contains the messages logged. **/ - private final Set messages = Sets.newTreeSet(); - - /** - * Gets the logged messages. - * @return the logged messages - */ - public SortedSet getMessages() { - return Sets.newTreeSet(messages); - } - - /** Reset the object. **/ - public void reset() { - messages.clear(); - } - - /** - * Logs a message to be reported. - * @param message the message to log - **/ - public void add(LocalizedMessage message) { - messages.add(message); - } - - /** - * Gets the number of messages. - * @return the number of messages - */ - public int size() { - return messages.size(); - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/MessageDispatcher.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/MessageDispatcher.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/MessageDispatcher.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/MessageDispatcher.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -26,6 +26,7 @@ * @author lkuehne */ public interface MessageDispatcher { + /** * Notify all listeners about the beginning of a file audit. * @param fileName the file to be audited @@ -44,4 +45,5 @@ * @param errors the audit errors from the file */ void fireErrors(String fileName, SortedSet errors); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/RootModule.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/RootModule.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/RootModule.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/RootModule.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,61 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.api; + +import java.io.File; +import java.util.List; + +/** + * The first module that is run as part of Checkstyle and controls its entire + * behavior and children. + * @author Richard Veach + */ +public interface RootModule extends Configurable { + + /** Cleans up the object. **/ + void destroy(); + + /** + * Processes a set of files. + * Once this is done, it is highly recommended to call for + * the destroy method to close and remove the listeners. + * @param files the list of files to be audited. + * @return the total number of errors found + * @throws CheckstyleException if error condition within Checkstyle occurs + * @see #destroy() + */ + int process(List files) throws CheckstyleException; + + /** + * Add the listener that will be used to receive events from the audit. + * @param listener the nosy thing + */ + void addListener(AuditListener listener); + + /** + * Sets the classloader used to load Checkstyle core and custom module + * classes when the module tree is being built up. + * If no custom ModuleFactory is being set for the root module then + * this module classloader must be specified. + * @param moduleClassLoader the classloader used to load module classes + */ + void setModuleClassLoader(ClassLoader moduleClassLoader); + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Scope.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Scope.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/Scope.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/Scope.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -29,6 +29,7 @@ * @author Mehmet Can Cömert */ public enum Scope { + /** Nothing scope. */ NOTHING, /** Public scope. */ @@ -48,6 +49,7 @@ } /** + * Returns name of severity level. * @return the name of this severity level. */ public String getName() { @@ -74,4 +76,5 @@ public static Scope getInstance(String scopeName) { return valueOf(Scope.class, scopeName.trim().toUpperCase(Locale.ENGLISH)); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/SeverityLevelCounter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/SeverityLevelCounter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/SeverityLevelCounter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/SeverityLevelCounter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,6 +19,8 @@ package com.puppycrawl.tools.checkstyle.api; +import java.util.concurrent.atomic.AtomicInteger; + /** * An audit listener that counts how many {@link AuditEvent AuditEvents} * of a given severity have been generated. @@ -26,11 +28,12 @@ * @author lkuehne */ public final class SeverityLevelCounter implements AuditListener { + /** The severity level to watch out for. */ private final SeverityLevel level; /** Keeps track of the number of counted events. */ - private int count; + private final AtomicInteger count = new AtomicInteger(); /** * Creates a new counter. @@ -46,20 +49,20 @@ @Override public void addError(AuditEvent event) { if (level == event.getSeverityLevel()) { - count++; + count.incrementAndGet(); } } @Override public void addException(AuditEvent event, Throwable throwable) { if (level == SeverityLevel.ERROR) { - count++; + count.incrementAndGet(); } } @Override public void auditStarted(AuditEvent event) { - count = 0; + count.set(0); } @Override @@ -82,6 +85,7 @@ * @return the number of counted events since audit started. */ public int getCount() { - return count; + return count.get(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/SeverityLevel.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/SeverityLevel.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/SeverityLevel.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/SeverityLevel.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -35,6 +35,7 @@ * @author Mehmet Can Cömert */ public enum SeverityLevel { + /** Severity level ignore. */ IGNORE, /** Severity level info. */ @@ -50,6 +51,7 @@ } /** + * Returns name of severity level. * @return the name of this severity level. */ public String getName() { @@ -67,4 +69,5 @@ return valueOf(SeverityLevel.class, securityLevelName.trim() .toUpperCase(Locale.ENGLISH)); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/TextBlock.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/TextBlock.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/TextBlock.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/TextBlock.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -26,6 +26,7 @@ * @author lkuehne */ public interface TextBlock { + /** * The text content of the text block. * Each line is represented by one array entry. @@ -75,4 +76,5 @@ */ boolean intersects(int startLineNo, int startColNo, int endLineNo, int endColNo); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/TokenTypes.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/TokenTypes.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/api/TokenTypes.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/api/TokenTypes.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -30,13 +30,9 @@ * * @author Oliver Burn * @author Peter Dobratz + * @noinspection ClassWithTooManyDependents */ public final class TokenTypes { - // The following three types are never part of an AST, - // left here as a reminder so nobody will read them accidentally - - // These are the types that can actually occur in an AST - // it makes sense to register Checks for these types /** * The end of file token. This is the root node for the source @@ -56,7 +52,7 @@ * children. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html">Java * Language Specification, §8 * @see #LITERAL_PUBLIC * @see #LITERAL_PROTECTED @@ -263,7 +259,7 @@ * of the object block of the declaring type. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.6">Java * Language Specification§8.6 * @see #SLIST * @see #OBJBLOCK @@ -278,7 +274,7 @@ * first and only child is a statement list. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.7">Java * Language Specification, §8.7 * @see #SLIST * @see #OBJBLOCK @@ -341,7 +337,7 @@ *
    * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html">Java * Language Specification, §8 * @see #MODIFIERS * @see #IDENT @@ -381,7 +377,7 @@ *
    * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html">Java * Language Specification, §9 * @see #MODIFIERS * @see #IDENT @@ -427,7 +423,7 @@ *
    * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-7.html#jls-7.4">Java * Language Specification §7.4 * @see #DOT * @see #IDENT @@ -469,7 +465,7 @@ * initialization block.

    * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-10.html">Java * Language Specification §10 * @see #TYPE * @see #ARRAY_INIT @@ -480,11 +476,14 @@ /** * An extends clause. This appear as part of class and interface * definitions. This element appears even if the - * extends keyword is not explicitly used. The child + * {@code extends} keyword is not explicitly used. The child * is an optional identifier. * *

    For example:

    * + *
    +     * extends java.util.LinkedList
    +     * 
    * *

    parses as:

    *
    @@ -601,7 +600,7 @@
          * 
    * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.7">Java * Language Specification, §14.7 * @see #SLIST **/ @@ -633,7 +632,7 @@ * +--RPAREN ()) *
    * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.16">Java * Language Specification, §15.16 * @see #EXPR * @see #TYPE @@ -668,20 +667,20 @@ **/ public static final int INDEX_OP = GeneratedJavaTokenTypes.INDEX_OP; /** - * The ++ (postfix increment) operator. + * The {@code ++} (postfix increment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.14.1">Java * Language Specification, §15.14.1 * @see #EXPR * @see #INC **/ public static final int POST_INC = GeneratedJavaTokenTypes.POST_INC; /** - * The -- (postfix decrement) operator. + * The {@code --} (postfix decrement) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.14.2">Java * Language Specification, §15.14.2 * @see #EXPR * @see #DEC @@ -719,7 +718,24 @@ public static final int METHOD_CALL = GeneratedJavaTokenTypes.METHOD_CALL; /** - * Part of Java 8 syntax. Method or constructor call without arguments. + * A reference to a method or constructor without arguments. Part of Java 8 syntax. + * The token should be used for subscribing for double colon literal. + * {@link #DOUBLE_COLON} token does not appear in the tree. + * + *

    For example:

    + *
    +     * String::compareToIgnoreCase
    +     * 
    + * + *

    parses as: + *

    +     * +--METHOD_REF (::)
    +     *     |
    +     *     +--IDENT (String)
    +     *     +--IDENT (compareToIgnoreCase)
    +     * 
    + * + * @see #IDENT * @see #DOUBLE_COLON */ public static final int METHOD_REF = GeneratedJavaTokenTypes.METHOD_REF; @@ -782,7 +798,7 @@ public static final int EXPR = GeneratedJavaTokenTypes.EXPR; /** * An array initialization. This may occur as part of an array - * declaration or inline with new. + * declaration or inline with {@code new}. * *

    For example:

    *
    @@ -892,7 +908,7 @@
          * 
    * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-7.html#jls-7.5">Java * Language Specification §7.5 * @see #DOT * @see #IDENT @@ -902,19 +918,19 @@ **/ public static final int IMPORT = GeneratedJavaTokenTypes.IMPORT; /** - * The - (unary minus) operator. + * The {@code -} (unary minus) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.15.4">Java * Language Specification, §15.15.4 * @see #EXPR **/ public static final int UNARY_MINUS = GeneratedJavaTokenTypes.UNARY_MINUS; /** - * The + (unary plus) operator. + * The {@code +} (unary plus) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.15.3">Java * Language Specification, §15.15.3 * @see #EXPR **/ @@ -986,7 +1002,7 @@ public static final int ELIST = GeneratedJavaTokenTypes.ELIST; /** * A for loop initializer. This is a child of - * LITERAL_FOR. The children of this element may be + * {@code LITERAL_FOR}. The children of this element may be * a comma separated list of variable declarations, an expression * list, or empty. * @@ -997,7 +1013,7 @@ public static final int FOR_INIT = GeneratedJavaTokenTypes.FOR_INIT; /** * A for loop condition. This is a child of - * LITERAL_FOR. The child of this element is an + * {@code LITERAL_FOR}. The child of this element is an * optional expression. * * @see #EXPR @@ -1008,7 +1024,7 @@ /** * A for loop iterator. This is a child of - * LITERAL_FOR. The child of this element is an + * {@code LITERAL_FOR}. The child of this element is an * optional expression list. * * @see #ELIST @@ -1019,30 +1035,30 @@ /** * The empty statement. This goes in place of an - * SLIST for a for or while + * {@code SLIST} for a {@code for} or {@code while} * loop body. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.6">Java * Language Specification, §14.6 * @see #LITERAL_FOR * @see #LITERAL_WHILE **/ public static final int EMPTY_STAT = GeneratedJavaTokenTypes.EMPTY_STAT; /** - * The final keyword. + * The {@code final} keyword. * * @see #MODIFIERS **/ public static final int FINAL = GeneratedJavaTokenTypes.FINAL; /** - * The abstract keyword. + * The {@code abstract} keyword. * * @see #MODIFIERS **/ public static final int ABSTRACT = GeneratedJavaTokenTypes.ABSTRACT; /** - * The strictfp keyword. + * The {@code strictfp} keyword. * * @see #MODIFIERS **/ @@ -1087,7 +1103,7 @@ public static final int CTOR_CALL = GeneratedJavaTokenTypes.CTOR_CALL; /** - * The statement terminator (;). Depending on the + * The statement terminator ({@code ;}). Depending on the * context, this make occur as a sibling, a child, or not at all. * * @see #PACKAGE_DEF @@ -1099,14 +1115,14 @@ public static final int SEMI = GeneratedJavaTokenTypes.SEMI; /** - * The ] symbol. + * The {@code ]} symbol. * * @see #INDEX_OP * @see #ARRAY_DECLARATOR **/ public static final int RBRACK = GeneratedJavaTokenTypes.RBRACK; /** - * The void keyword. + * The {@code void} keyword. * * @see #TYPE **/ @@ -1114,7 +1130,7 @@ GeneratedJavaTokenTypes.LITERAL_void; /** - * The boolean keyword. + * The {@code boolean} keyword. * * @see #TYPE **/ @@ -1122,7 +1138,7 @@ GeneratedJavaTokenTypes.LITERAL_boolean; /** - * The byte keyword. + * The {@code byte} keyword. * * @see #TYPE **/ @@ -1130,7 +1146,7 @@ GeneratedJavaTokenTypes.LITERAL_byte; /** - * The char keyword. + * The {@code char} keyword. * * @see #TYPE **/ @@ -1138,7 +1154,7 @@ GeneratedJavaTokenTypes.LITERAL_char; /** - * The short keyword. + * The {@code short} keyword. * * @see #TYPE **/ @@ -1146,13 +1162,13 @@ GeneratedJavaTokenTypes.LITERAL_short; /** - * The int keyword. + * The {@code int} keyword. * * @see #TYPE **/ public static final int LITERAL_INT = GeneratedJavaTokenTypes.LITERAL_int; /** - * The float keyword. + * The {@code float} keyword. * * @see #TYPE **/ @@ -1160,7 +1176,7 @@ GeneratedJavaTokenTypes.LITERAL_float; /** - * The long keyword. + * The {@code long} keyword. * * @see #TYPE **/ @@ -1168,7 +1184,7 @@ GeneratedJavaTokenTypes.LITERAL_long; /** - * The double keyword. + * The {@code double} keyword. * * @see #TYPE **/ @@ -1184,23 +1200,24 @@ * The . (dot) operator. * * @see FullIdent + * @noinspection HtmlTagCanBeJavadocTag **/ public static final int DOT = GeneratedJavaTokenTypes.DOT; /** - * The * (multiplication or wildcard) operator. + * The {@code *} (multiplication or wildcard) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-7.html#jls-7.5.2">Java * Language Specification, §7.5.2 * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.17.1">Java * Language Specification, §15.17.1 * @see #EXPR * @see #IMPORT **/ public static final int STAR = GeneratedJavaTokenTypes.STAR; /** - * The private keyword. + * The {@code private} keyword. * * @see #MODIFIERS **/ @@ -1208,7 +1225,7 @@ GeneratedJavaTokenTypes.LITERAL_private; /** - * The public keyword. + * The {@code public} keyword. * * @see #MODIFIERS **/ @@ -1216,7 +1233,7 @@ GeneratedJavaTokenTypes.LITERAL_public; /** - * The protected keyword. + * The {@code protected} keyword. * * @see #MODIFIERS **/ @@ -1224,7 +1241,7 @@ GeneratedJavaTokenTypes.LITERAL_protected; /** - * The static keyword. + * The {@code static} keyword. * * @see #MODIFIERS **/ @@ -1232,7 +1249,7 @@ GeneratedJavaTokenTypes.LITERAL_static; /** - * The transient keyword. + * The {@code transient} keyword. * * @see #MODIFIERS **/ @@ -1240,7 +1257,7 @@ GeneratedJavaTokenTypes.LITERAL_transient; /** - * The native keyword. + * The {@code native} keyword. * * @see #MODIFIERS **/ @@ -1248,7 +1265,7 @@ GeneratedJavaTokenTypes.LITERAL_native; /** - * The synchronized keyword. This may be used as a + * The {@code synchronized} keyword. This may be used as a * modifier of a method or in the definition of a synchronized * block. * @@ -1294,7 +1311,7 @@ GeneratedJavaTokenTypes.LITERAL_synchronized; /** - * The volatile keyword. + * The {@code volatile} keyword. * * @see #MODIFIERS **/ @@ -1302,7 +1319,7 @@ GeneratedJavaTokenTypes.LITERAL_volatile; /** - * The class keyword. This element appears both + * The {@code class} keyword. This element appears both * as part of a class declaration, and inline to reference a * class object. * @@ -1330,7 +1347,7 @@ GeneratedJavaTokenTypes.LITERAL_class; /** - * The interface keyword. This token appears in + * The {@code interface} keyword. This token appears in * interface definition. * * @see #INTERFACE_DEF @@ -1339,23 +1356,25 @@ GeneratedJavaTokenTypes.LITERAL_interface; /** - * A left (curly) brace ({). + * A left curly brace ({). * * @see #OBJBLOCK * @see #ARRAY_INIT * @see #SLIST + * @noinspection HtmlTagCanBeJavadocTag **/ public static final int LCURLY = GeneratedJavaTokenTypes.LCURLY; /** - * A right (curly) brace (}). + * A right curly brace (}). * * @see #OBJBLOCK * @see #ARRAY_INIT * @see #SLIST + * @noinspection HtmlTagCanBeJavadocTag **/ public static final int RCURLY = GeneratedJavaTokenTypes.RCURLY; /** - * The , (comma) operator. + * The {@code ,} (comma) operator. * * @see #ARRAY_INIT * @see #FOR_INIT @@ -1366,7 +1385,7 @@ public static final int COMMA = GeneratedJavaTokenTypes.COMMA; /** - * A left parenthesis ((). + * A left parenthesis ({@code (}). * * @see #LITERAL_FOR * @see #LITERAL_NEW @@ -1376,7 +1395,7 @@ **/ public static final int LPAREN = GeneratedJavaTokenTypes.LPAREN; /** - * A right parenthesis ()). + * A right parenthesis ({@code )}). * * @see #LITERAL_FOR * @see #LITERAL_NEW @@ -1388,7 +1407,7 @@ **/ public static final int RPAREN = GeneratedJavaTokenTypes.RPAREN; /** - * The this keyword. + * The {@code this} keyword. * * @see #EXPR * @see #CTOR_CALL @@ -1397,7 +1416,7 @@ GeneratedJavaTokenTypes.LITERAL_this; /** - * The super keyword. + * The {@code super} keyword. * * @see #EXPR * @see #SUPER_CTOR_CALL @@ -1406,20 +1425,20 @@ GeneratedJavaTokenTypes.LITERAL_super; /** - * The = (assignment) operator. + * The {@code =} (assignment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.1">Java * Language Specification, §15.26.1 * @see #EXPR **/ public static final int ASSIGN = GeneratedJavaTokenTypes.ASSIGN; /** - * The throws keyword. The children are a number of + * The {@code throws} keyword. The children are a number of * one or more identifiers separated by commas. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.4">Java * Language Specification, §8.4.4 * @see #IDENT * @see #DOT @@ -1432,8 +1451,8 @@ GeneratedJavaTokenTypes.LITERAL_throws; /** - * The : (colon) operator. This will appear as part - * of the conditional operator (? :). + * The {@code :} (colon) operator. This will appear as part + * of the conditional operator ({@code ? :}). * * @see #QUESTION * @see #LABELED_STAT @@ -1442,13 +1461,15 @@ public static final int COLON = GeneratedJavaTokenTypes.COLON; /** - * The :: (double colon) operator. + * The {@code ::} (double colon) separator. * It is part of Java 8 syntax that is used for method reference. + * The token does not appear in tree, {@link #METHOD_REF} should be used instead. + * * @see #METHOD_REF */ public static final int DOUBLE_COLON = GeneratedJavaTokenTypes.DOUBLE_COLON; /** - * The if keyword. + * The {@code if} keyword. * *

    For example:

    *
    @@ -1503,8 +1524,8 @@
          **/
         public static final int LITERAL_IF = GeneratedJavaTokenTypes.LITERAL_if;
         /**
    -     * The for keyword.  The children are (,
    -     * an initializer, a condition, an iterator, a ) and
    +     * The {@code for} keyword.  The children are {@code (},
    +     * an initializer, a condition, an iterator, a {@code )} and
          * either a statement list, a single expression, or an empty
          * statement.
          *
    @@ -1587,7 +1608,7 @@
          **/
         public static final int LITERAL_FOR = GeneratedJavaTokenTypes.LITERAL_for;
         /**
    -     * The while keyword.
    +     * The {@code while} keyword.
          *
          * 

    For example:

    *
    @@ -1644,7 +1665,7 @@
             GeneratedJavaTokenTypes.LITERAL_while;
     
         /**
    -     * The do keyword.  Note the the while token does not
    +     * The {@code do} keyword.  Note the the while token does not
          * appear as part of the do-while construct.
          *
          * 

    For example:

    @@ -1680,6 +1701,7 @@ * +--RPAREN ()) * +--SEMI (;) * +--RCURLY (}) + * +--DO_WHILE (while) * +--LPAREN (() * +--EXPR * | @@ -1700,12 +1722,12 @@ **/ public static final int LITERAL_DO = GeneratedJavaTokenTypes.LITERAL_do; /** - * Literal while in do-while loop. + * Literal {@code while} in do-while loop. * @see #LITERAL_DO */ public static final int DO_WHILE = GeneratedJavaTokenTypes.DO_WHILE; /** - * The break keyword. The first child is an optional + * The {@code break} keyword. The first child is an optional * identifier and the last child is a semicolon. * * @see #IDENT @@ -1716,7 +1738,7 @@ GeneratedJavaTokenTypes.LITERAL_break; /** - * The continue keyword. The first child is an + * The {@code continue} keyword. The first child is an * optional identifier and the last child is a semicolon. * * @see #IDENT @@ -1727,7 +1749,7 @@ GeneratedJavaTokenTypes.LITERAL_continue; /** - * The return keyword. The first child is an + * The {@code return} keyword. The first child is an * optional expression for the return value. The last child is a * semi colon. * @@ -1739,7 +1761,7 @@ GeneratedJavaTokenTypes.LITERAL_return; /** - * The switch keyword. + * The {@code switch} keyword. * *

    For example:

    *
    @@ -1832,7 +1854,7 @@
          * 
    * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.10">Java * Language Specification, §14.10 * @see #LPAREN * @see #EXPR @@ -1846,11 +1868,11 @@ GeneratedJavaTokenTypes.LITERAL_switch; /** - * The throw keyword. The first child is an - * expression that evaluates to a Throwable instance. + * The {@code throw} keyword. The first child is an + * expression that evaluates to a {@code Throwable} instance. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.17">Java * Language Specification, §14.17 * @see #SLIST * @see #EXPR @@ -1859,8 +1881,8 @@ GeneratedJavaTokenTypes.LITERAL_throw; /** - * The else keyword. This appears as a child of an - * if statement. + * The {@code else} keyword. This appears as a child of an + * {@code if} statement. * * @see #SLIST * @see #EXPR @@ -1871,8 +1893,8 @@ GeneratedJavaTokenTypes.LITERAL_else; /** - * The case keyword. The first child is a constant - * expression that evaluates to a integer. + * The {@code case} keyword. The first child is a constant + * expression that evaluates to an integer. * * @see #CASE_GROUP * @see #EXPR @@ -1881,7 +1903,7 @@ GeneratedJavaTokenTypes.LITERAL_case; /** - * The default keyword. This element has no + * The {@code default} keyword. This element has no * children. * * @see #CASE_GROUP @@ -1891,7 +1913,7 @@ GeneratedJavaTokenTypes.LITERAL_default; /** - * The try keyword. The children are a statement + * The {@code try} keyword. The children are a statement * list, zero or more catch blocks and then an optional finally * block. * @@ -1960,7 +1982,7 @@ *
    * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.19">Java * Language Specification, §14.19 * @see #SLIST * @see #LITERAL_CATCH @@ -1969,7 +1991,7 @@ public static final int LITERAL_TRY = GeneratedJavaTokenTypes.LITERAL_try; /** - * Java 7 try-with-resources construct. + * The Java 7 try-with-resources construct. * *

    For example:

    *
    @@ -2022,6 +2044,70 @@
          *         +--RCURLY (})
          * 
    * + *

    Also consider:

    + *
    +     * try (BufferedReader br = new BufferedReader(new FileReader(path)))
    +     * {
    +     *  return br.readLine();
    +     * }
    +     * 
    + *

    which parses as:

    + *
    +     * +--LITERAL_TRY (try)
    +     *     |
    +     *     +--RESOURCE_SPECIFICATION
    +     *         |
    +     *         +--LPAREN (()
    +     *         +--RESOURCES
    +     *             |
    +     *             +--RESOURCE
    +     *                 |
    +     *                 +--MODIFIERS
    +     *                 +--TYPE
    +     *                     |
    +     *                     +--IDENT (BufferedReader)
    +     *                 +--IDENT (br)
    +     *                 +--ASSIGN (=)
    +     *                 +--EXPR
    +     *                     |
    +     *                     +--LITERAL_NEW (new)
    +     *                         |
    +     *                         +--IDENT (FileReader)
    +     *                         +--LPAREN (()
    +     *                         +--ELIST
    +     *                             |
    +     *                             +--EXPR
    +     *                                 |
    +     *                                 +--LITERAL_NEW (new)
    +     *                                     |
    +     *                                     +--IDENT (BufferedReader)
    +     *                                     +--LPAREN (()
    +     *                                     +--ELIST
    +     *                                         |
    +     *                                         +--EXPR
    +     *                                             |
    +     *                                             +--IDENT (path)
    +     *                                     +--RPAREN ())
    +     *                         +--RPAREN ())
    +     *         +--RPAREN ())
    +     *     +--SLIST ({)
    +     *         |
    +     *         +--LITERAL_RETURN (return)
    +     *             |
    +     *             +--EXPR
    +     *                 |
    +     *                 +--METHOD_CALL (()
    +     *                     |
    +     *                     +--DOT (.)
    +     *                         |
    +     *                         +--IDENT (br)
    +     *                         +--IDENT (readLine)
    +     *                     +--ELIST
    +     *                     +--RPAREN ())
    +     *             +--SEMI (;)
    +     *         +--RCURLY (})
    +     * 
    + * * @see #LPAREN * @see #RESOURCES * @see #RESOURCE @@ -2033,7 +2119,8 @@ GeneratedJavaTokenTypes.RESOURCE_SPECIFICATION; /** - * Java 7 try-with-resources construct. + * A list of resources in the Java 7 try-with-resources construct. + * This is a child of RESOURCE_SPECIFICATION. * * @see #RESOURCE_SPECIFICATION **/ @@ -2041,15 +2128,17 @@ GeneratedJavaTokenTypes.RESOURCES; /** - * Java 7 try-with-resources construct. + * A resource in the Java 7 try-with-resources construct. + * This is a child of RESOURCES. * + * @see #RESOURCES * @see #RESOURCE_SPECIFICATION **/ public static final int RESOURCE = GeneratedJavaTokenTypes.RESOURCE; /** - * The catch keyword. + * The {@code catch} keyword. * * @see #LPAREN * @see #PARAMETER_DEF @@ -2061,7 +2150,7 @@ GeneratedJavaTokenTypes.LITERAL_catch; /** - * The finally keyword. + * The {@code finally} keyword. * * @see #SLIST * @see #LITERAL_TRY @@ -2070,19 +2159,19 @@ GeneratedJavaTokenTypes.LITERAL_finally; /** - * The += (addition assignment) operator. + * The {@code +=} (addition assignment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2">Java * Language Specification, §15.26.2 * @see #EXPR **/ public static final int PLUS_ASSIGN = GeneratedJavaTokenTypes.PLUS_ASSIGN; /** - * The -= (subtraction assignment) operator. + * The {@code -=} (subtraction assignment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2">Java * Language Specification, §15.26.2 * @see #EXPR **/ @@ -2090,84 +2179,84 @@ GeneratedJavaTokenTypes.MINUS_ASSIGN; /** - * The *= (multiplication assignment) operator. + * The {@code *=} (multiplication assignment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2">Java * Language Specification, §15.26.2 * @see #EXPR **/ public static final int STAR_ASSIGN = GeneratedJavaTokenTypes.STAR_ASSIGN; /** - * The /= (division assignment) operator. + * The {@code /=} (division assignment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2">Java * Language Specification, §15.26.2 * @see #EXPR **/ public static final int DIV_ASSIGN = GeneratedJavaTokenTypes.DIV_ASSIGN; /** - * The %= (remainder assignment) operator. + * The {@code %=} (remainder assignment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2">Java * Language Specification, §15.26.2 * @see #EXPR **/ public static final int MOD_ASSIGN = GeneratedJavaTokenTypes.MOD_ASSIGN; /** - * The >>= (signed right shift assignment) + * The {@code >>=} (signed right shift assignment) * operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2">Java * Language Specification, §15.26.2 * @see #EXPR **/ public static final int SR_ASSIGN = GeneratedJavaTokenTypes.SR_ASSIGN; /** - * The >>>= (unsigned right shift assignment) + * The {@code >>>=} (unsigned right shift assignment) * operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2">Java * Language Specification, §15.26.2 * @see #EXPR **/ public static final int BSR_ASSIGN = GeneratedJavaTokenTypes.BSR_ASSIGN; /** - * The <<= (left shift assignment) operator. + * The {@code <<=} (left shift assignment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2">Java * Language Specification, §15.26.2 * @see #EXPR **/ public static final int SL_ASSIGN = GeneratedJavaTokenTypes.SL_ASSIGN; /** - * The &= (bitwise AND assignment) operator. + * The {@code &=} (bitwise AND assignment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2">Java * Language Specification, §15.26.2 * @see #EXPR **/ public static final int BAND_ASSIGN = GeneratedJavaTokenTypes.BAND_ASSIGN; /** - * The ^= (bitwise exclusive OR assignment) operator. + * The {@code ^=} (bitwise exclusive OR assignment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2">Java * Language Specification, §15.26.2 * @see #EXPR **/ public static final int BXOR_ASSIGN = GeneratedJavaTokenTypes.BXOR_ASSIGN; /** - * The |= (bitwise OR assignment) operator. + * The {@code |=} (bitwise OR assignment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.26.2">Java * Language Specification, §15.26.2 * @see #EXPR **/ @@ -2199,53 +2288,54 @@ *
    * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.25">Java * Language Specification, §15.25 * @see #EXPR * @see #COLON + * @noinspection HtmlTagCanBeJavadocTag **/ public static final int QUESTION = GeneratedJavaTokenTypes.QUESTION; /** - * The || (conditional OR) operator. + * The {@code ||} (conditional OR) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.24">Java * Language Specification, §15.24 * @see #EXPR **/ public static final int LOR = GeneratedJavaTokenTypes.LOR; /** - * The && (conditional AND) operator. + * The {@code &&} (conditional AND) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.23">Java * Language Specification, §15.23 * @see #EXPR **/ public static final int LAND = GeneratedJavaTokenTypes.LAND; /** - * The | (bitwise OR) operator. + * The {@code |} (bitwise OR) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.22.1">Java * Language Specification, §15.22.1 * @see #EXPR **/ public static final int BOR = GeneratedJavaTokenTypes.BOR; /** - * The ^ (bitwise exclusive OR) operator. + * The {@code ^} (bitwise exclusive OR) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.22.1">Java * Language Specification, §15.22.1 * @see #EXPR **/ public static final int BXOR = GeneratedJavaTokenTypes.BXOR; /** - * The & (bitwise AND) operator. + * The {@code &} (bitwise AND) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.22.1">Java * Language Specification, §15.22.1 * @see #EXPR **/ @@ -2254,45 +2344,46 @@ * The != (not equal) operator. * * @see #EXPR + * @noinspection HtmlTagCanBeJavadocTag **/ public static final int NOT_EQUAL = GeneratedJavaTokenTypes.NOT_EQUAL; /** - * The == (equal) operator. + * The {@code ==} (equal) operator. * * @see #EXPR **/ public static final int EQUAL = GeneratedJavaTokenTypes.EQUAL; /** - * The < (less than) operator. + * The {@code <} (less than) operator. * * @see #EXPR **/ public static final int LT = GeneratedJavaTokenTypes.LT; /** - * The > (greater than) operator. + * The {@code >} (greater than) operator. * * @see #EXPR **/ public static final int GT = GeneratedJavaTokenTypes.GT; /** - * The <= (less than or equal) operator. + * The {@code <=} (less than or equal) operator. * * @see #EXPR **/ public static final int LE = GeneratedJavaTokenTypes.LE; /** - * The >= (greater than or equal) operator. + * The {@code >=} (greater than or equal) operator. * * @see #EXPR **/ public static final int GE = GeneratedJavaTokenTypes.GE; /** - * The instanceof operator. The first child is an + * The {@code instanceof} operator. The first child is an * object reference or something that evaluates to an object * reference. The second child is a reference type. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.20.2">Java * Language Specification, §15.20.2 * @see #EXPR * @see #METHOD_CALL @@ -2305,93 +2396,93 @@ GeneratedJavaTokenTypes.LITERAL_instanceof; /** - * The << (shift left) operator. + * The {@code <<} (shift left) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.19">Java * Language Specification, §15.19 * @see #EXPR **/ public static final int SL = GeneratedJavaTokenTypes.SL; /** - * The >> (signed shift right) operator. + * The {@code >>} (signed shift right) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.19">Java * Language Specification, §15.19 * @see #EXPR **/ public static final int SR = GeneratedJavaTokenTypes.SR; /** - * The >>> (unsigned shift right) operator. + * The {@code >>>} (unsigned shift right) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.19">Java * Language Specification, §15.19 * @see #EXPR **/ public static final int BSR = GeneratedJavaTokenTypes.BSR; /** - * The + (addition) operator. + * The {@code +} (addition) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.18">Java * Language Specification, §15.18 * @see #EXPR **/ public static final int PLUS = GeneratedJavaTokenTypes.PLUS; /** - * The - (subtraction) operator. + * The {@code -} (subtraction) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.18">Java * Language Specification, §15.18 * @see #EXPR **/ public static final int MINUS = GeneratedJavaTokenTypes.MINUS; /** - * The / (division) operator. + * The {@code /} (division) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.17.2">Java * Language Specification, §15.17.2 * @see #EXPR **/ public static final int DIV = GeneratedJavaTokenTypes.DIV; /** - * The % (remainder) operator. + * The {@code %} (remainder) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.17.3">Java * Language Specification, §15.17.3 * @see #EXPR **/ public static final int MOD = GeneratedJavaTokenTypes.MOD; /** - * The ++ (prefix increment) operator. + * The {@code ++} (prefix increment) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.15.1">Java * Language Specification, §15.15.1 * @see #EXPR * @see #POST_INC **/ public static final int INC = GeneratedJavaTokenTypes.INC; /** - * The -- (prefix decrement) operator. + * The {@code --} (prefix decrement) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.15.2">Java * Language Specification, §15.15.2 * @see #EXPR * @see #POST_DEC **/ public static final int DEC = GeneratedJavaTokenTypes.DEC; /** - * The ~ (bitwise complement) operator. + * The {@code ~} (bitwise complement) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.15.5">Java * Language Specification, §15.15.5 * @see #EXPR **/ @@ -2400,16 +2491,17 @@ * The ! (logical complement) operator. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.15.6">Java * Language Specification, §15.15.6 * @see #EXPR + * @noinspection HtmlTagCanBeJavadocTag **/ public static final int LNOT = GeneratedJavaTokenTypes.LNOT; /** - * The true keyword. + * The {@code true} keyword. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.3">Java * Language Specification, §3.10.3 * @see #EXPR * @see #LITERAL_FALSE @@ -2418,10 +2510,10 @@ GeneratedJavaTokenTypes.LITERAL_true; /** - * The false keyword. + * The {@code false} keyword. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.3">Java * Language Specification, §3.10.3 * @see #EXPR * @see #LITERAL_TRUE @@ -2430,10 +2522,10 @@ GeneratedJavaTokenTypes.LITERAL_false; /** - * The null keyword. + * The {@code null} keyword. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.7">Java * Language Specification, §3.10.7 * @see #EXPR **/ @@ -2441,7 +2533,7 @@ GeneratedJavaTokenTypes.LITERAL_null; /** - * The new keyword. This element is used to define + * The {@code new} keyword. This element is used to define * new instances of objects, new arrays, and new anonymous inner * classes. * @@ -2578,7 +2670,7 @@ * hexadecimal, or octal form. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.1">Java * Language Specification, §3.10.1 * @see #EXPR * @see #NUM_LONG @@ -2589,7 +2681,7 @@ * enclosed in single quotes. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.4">Java * Language Specification, §3.10.4 * @see #EXPR **/ @@ -2601,7 +2693,7 @@ * characters enclosed in double quotes. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5">Java * Language Specification, §3.10.5 * @see #EXPR **/ @@ -2610,10 +2702,10 @@ /** * A single precision floating point literal. This is a floating - * point number with an F or f suffix. + * point number with an {@code F} or {@code f} suffix. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.2">Java * Language Specification, §3.10.2 * @see #EXPR * @see #NUM_DOUBLE @@ -2621,11 +2713,11 @@ public static final int NUM_FLOAT = GeneratedJavaTokenTypes.NUM_FLOAT; /** * A long integer literal. These are almost the same as integer - * literals, but they have an L or l + * literals, but they have an {@code L} or {@code l} * (ell) suffix. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.1">Java * Language Specification, §3.10.1 * @see #EXPR * @see #NUM_INT @@ -2633,11 +2725,11 @@ public static final int NUM_LONG = GeneratedJavaTokenTypes.NUM_LONG; /** * A double precision floating point literal. This is a floating - * point number with an optional D or d + * point number with an optional {@code D} or {@code d} * suffix. * * @see Java + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.2">Java * Language Specification, §3.10.2 * @see #EXPR * @see #NUM_FLOAT @@ -2645,7 +2737,7 @@ public static final int NUM_DOUBLE = GeneratedJavaTokenTypes.NUM_DOUBLE; /** - * The assert keyword. This is only for Java 1.4 and + * The {@code assert} keyword. This is only for Java 1.4 and * later. * *

    For example:

    @@ -2783,7 +2875,7 @@ GeneratedJavaTokenTypes.ENUM_DEF; /** - * The enum keyword. This element appears + * The {@code enum} keyword. This element appears * as part of an enum declaration. **/ public static final int ENUM = @@ -2851,9 +2943,40 @@ /** * A for-each clause. This is a child of - * LITERAL_FOR. The children of this element may be + * {@code LITERAL_FOR}. The children of this element may be * a parameter definition, the colon literal and an expression. * + *

    For example:

    + *
    +     * for (int value : values) {
    +     *     doSmth();
    +     * }
    +     * 
    + *

    parses as:

    + *
    +     * --LITERAL_FOR (for)
    +     *    |--LPAREN (()
    +     *    |--FOR_EACH_CLAUSE
    +     *    |   |--VARIABLE_DEF
    +     *    |   |   |--MODIFIERS
    +     *    |   |   |--TYPE
    +     *    |   |   |   `--LITERAL_INT (int)
    +     *    |   |   `--IDENT (value)
    +     *    |   |--COLON (:)
    +     *    |   `--EXPR
    +     *    |       `--IDENT (values
    +     *    |--RPAREN ())
    +     *    `--SLIST ({)
    +     *        |--EXPR
    +     *        |   `--METHOD_CALL (()
    +     *        |       |--IDENT (doSmth)
    +     *        |       |--ELIST
    +     *        |       `--RPAREN ())
    +     *        |--SEMI (;)
    +     *        `--RCURLY (})
    +     *
    +     * 
    + * * @see #VARIABLE_DEF * @see #ELIST * @see #LITERAL_FOR @@ -3037,7 +3160,7 @@ GeneratedJavaTokenTypes.ANNOTATION; /** - * An initialisation of an annotation member with a value. + * An initialization of an annotation member with a value. * Its children are the name of the member, the assignment literal * and the (compile-time constant conditional expression) value. * @@ -3050,9 +3173,9 @@ GeneratedJavaTokenTypes.ANNOTATION_MEMBER_VALUE_PAIR; /** - * An annotation array member initialisation. + * An annotation array member initialization. * Initializers can not be nested. - * Am initializer may be present as a default to a annotation + * An initializer may be present as a default to an annotation * member, as the single default value to an annotation * (e.g. @Annotation({1,2})) or as the value of an annotation * member value pair. @@ -3280,7 +3403,7 @@ GeneratedJavaTokenTypes.TYPE_LOWER_BOUNDS; /** - * An 'at' symbol - signifying an annotation instance or the prefix + * An {@code @} symbol - signifying an annotation instance or the prefix * to the interface literal signifying the definition of an annotation * declaration. * @@ -3299,26 +3422,26 @@ public static final int ELLIPSIS = GeneratedJavaTokenTypes.ELLIPSIS; /** - * '&' symbol when used in a generic upper or lower bounds constrain - * e.g. {@code Comparable<}. + * The {@code &} symbol when used in a generic upper or lower bounds constrain + * e.g. Comparable<T extends Serializable & CharSequence>. + * @noinspection HtmlTagCanBeJavadocTag */ public static final int TYPE_EXTENSION_AND = GeneratedJavaTokenTypes.TYPE_EXTENSION_AND; /** - * '<' symbol signifying the start of type arguments or type - * parameters. + * A {@code <} symbol signifying the start of type arguments or type parameters. */ public static final int GENERIC_START = GeneratedJavaTokenTypes.GENERIC_START; /** - * '>' symbol signifying the end of type arguments or type parameters. + * A {@code >} symbol signifying the end of type arguments or type parameters. */ public static final int GENERIC_END = GeneratedJavaTokenTypes.GENERIC_END; /** - * Special lambda symbol '->'. + * Special lambda symbol {@code ->}. */ public static final int LAMBDA = GeneratedJavaTokenTypes.LAMBDA; @@ -3348,7 +3471,7 @@ GeneratedJavaTokenTypes.BLOCK_COMMENT_BEGIN; /** - * End of block comment: '* /'. + * End of block comment: '*/'. * *
          * +--BLOCK_COMMENT_BEGIN
    @@ -3363,7 +3486,7 @@
         /**
          * Text of single-line or block comment.
          *
    -     *
    +     * 
          * +--SINGLE_LINE_COMMENT
          *         |
          *         +--COMMENT_CONTENT
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinter.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinter.java	1970-01-01 00:00:00.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/AstTreeStringPrinter.java	2018-01-28 04:16:51.000000000 +0000
    @@ -0,0 +1,209 @@
    +////////////////////////////////////////////////////////////////////////////////
    +// checkstyle: Checks Java source code for adherence to a set of rules.
    +// Copyright (C) 2001-2018 the original author or authors.
    +//
    +// This library is free software; you can redistribute it and/or
    +// modify it under the terms of the GNU Lesser General Public
    +// License as published by the Free Software Foundation; either
    +// version 2.1 of the License, or (at your option) any later version.
    +//
    +// This library is distributed in the hope that it will be useful,
    +// but WITHOUT ANY WARRANTY; without even the implied warranty of
    +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    +// Lesser General Public License for more details.
    +//
    +// You should have received a copy of the GNU Lesser General Public
    +// License along with this library; if not, write to the Free Software
    +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    +////////////////////////////////////////////////////////////////////////////////
    +
    +package com.puppycrawl.tools.checkstyle;
    +
    +import java.io.File;
    +import java.io.IOException;
    +import java.util.regex.Pattern;
    +
    +import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
    +import com.puppycrawl.tools.checkstyle.api.DetailAST;
    +import com.puppycrawl.tools.checkstyle.api.DetailNode;
    +import com.puppycrawl.tools.checkstyle.api.FileText;
    +import com.puppycrawl.tools.checkstyle.api.TokenTypes;
    +import com.puppycrawl.tools.checkstyle.utils.JavadocUtils;
    +import com.puppycrawl.tools.checkstyle.utils.TokenUtils;
    +
    +/**
    + * Class for printing AST to String.
    + * @author Vladislav Lisetskii
    + */
    +public final class AstTreeStringPrinter {
    +
    +    /** Newline pattern. */
    +    private static final Pattern NEWLINE = Pattern.compile("\n");
    +    /** Return pattern. */
    +    private static final Pattern RETURN = Pattern.compile("\r");
    +    /** Tab pattern. */
    +    private static final Pattern TAB = Pattern.compile("\t");
    +
    +    /** OS specific line separator. */
    +    private static final String LINE_SEPARATOR = System.getProperty("line.separator");
    +
    +    /** Prevent instances. */
    +    private AstTreeStringPrinter() {
    +        // no code
    +    }
    +
    +    /**
    +     * Parse a file and print the parse tree.
    +     * @param file the file to print.
    +     * @param options {@link JavaParser.Options} to control the inclusion of comment nodes.
    +     * @return the AST of the file in String form.
    +     * @throws IOException if the file could not be read.
    +     * @throws CheckstyleException if the file is not a Java source.
    +     */
    +    public static String printFileAst(File file, JavaParser.Options options)
    +            throws IOException, CheckstyleException {
    +        return printTree(JavaParser.parseFile(file, options));
    +    }
    +
    +    /**
    +     * Prints full AST (java + comments + javadoc) of the java file.
    +     * @param file java file
    +     * @return Full tree
    +     * @throws IOException Failed to open a file
    +     * @throws CheckstyleException error while parsing the file
    +     */
    +    public static String printJavaAndJavadocTree(File file)
    +            throws IOException, CheckstyleException {
    +        final DetailAST tree = JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS);
    +        return printJavaAndJavadocTree(tree);
    +    }
    +
    +    /**
    +     * Prints full tree (java + comments + javadoc) of the DetailAST.
    +     * @param ast root DetailAST
    +     * @return Full tree
    +     */
    +    private static String printJavaAndJavadocTree(DetailAST ast) {
    +        final StringBuilder messageBuilder = new StringBuilder(1024);
    +        DetailAST node = ast;
    +        while (node != null) {
    +            messageBuilder.append(getIndentation(node))
    +                .append(getNodeInfo(node))
    +                .append(LINE_SEPARATOR);
    +            if (node.getType() == TokenTypes.COMMENT_CONTENT
    +                    && JavadocUtils.isJavadocComment(node.getParent())) {
    +                final String javadocTree = parseAndPrintJavadocTree(node);
    +                messageBuilder.append(javadocTree);
    +            }
    +            else {
    +                messageBuilder.append(printJavaAndJavadocTree(node.getFirstChild()));
    +            }
    +            node = node.getNextSibling();
    +        }
    +        return messageBuilder.toString();
    +    }
    +
    +    /**
    +     * Parses block comment as javadoc and prints its tree.
    +     * @param node block comment begin
    +     * @return string javadoc tree
    +     */
    +    private static String parseAndPrintJavadocTree(DetailAST node) {
    +        final DetailAST javadocBlock = node.getParent();
    +        final DetailNode tree = DetailNodeTreeStringPrinter.parseJavadocAsDetailNode(javadocBlock);
    +
    +        String baseIndentation = getIndentation(node);
    +        baseIndentation = baseIndentation.substring(0, baseIndentation.length() - 2);
    +        final String rootPrefix = baseIndentation + "   `--";
    +        final String prefix = baseIndentation + "       ";
    +        return DetailNodeTreeStringPrinter.printTree(tree, rootPrefix, prefix);
    +    }
    +
    +    /**
    +     * Parse a file and print the parse tree.
    +     * @param text the text to parse.
    +     * @param options {@link JavaParser.Options} to control the inclusion of comment nodes.
    +     * @return the AST of the file in String form.
    +     * @throws CheckstyleException if the file is not a Java source.
    +     */
    +    public static String printAst(FileText text, JavaParser.Options options)
    +            throws CheckstyleException {
    +        final DetailAST ast = JavaParser.parseFileText(text, options);
    +        return printTree(ast);
    +    }
    +
    +    /**
    +     * Print AST.
    +     * @param ast the root AST node.
    +     * @return string AST.
    +     */
    +    private static String printTree(DetailAST ast) {
    +        final StringBuilder messageBuilder = new StringBuilder(1024);
    +        DetailAST node = ast;
    +        while (node != null) {
    +            messageBuilder.append(getIndentation(node))
    +                    .append(getNodeInfo(node))
    +                    .append(LINE_SEPARATOR)
    +                    .append(printTree(node.getFirstChild()));
    +            node = node.getNextSibling();
    +        }
    +        return messageBuilder.toString();
    +    }
    +
    +    /**
    +     * Get string representation of the node as token name,
    +     * node text, line number and column number.
    +     * @param node DetailAST
    +     * @return node info
    +     */
    +    private static String getNodeInfo(DetailAST node) {
    +        return TokenUtils.getTokenName(node.getType())
    +                + " -> " + escapeAllControlChars(node.getText())
    +                + " [" + node.getLineNo() + ':' + node.getColumnNo() + ']';
    +    }
    +
    +    /**
    +     * Get indentation for an AST node.
    +     * @param ast the AST to get the indentation for.
    +     * @return the indentation in String format.
    +     */
    +    private static String getIndentation(DetailAST ast) {
    +        final boolean isLastChild = ast.getNextSibling() == null;
    +        DetailAST node = ast;
    +        final StringBuilder indentation = new StringBuilder(1024);
    +        while (node.getParent() != null) {
    +            node = node.getParent();
    +            if (node.getParent() == null) {
    +                if (isLastChild) {
    +                    // only ASCII symbols must be used due to
    +                    // problems with running tests on Windows
    +                    indentation.append("`--");
    +                }
    +                else {
    +                    indentation.append("|--");
    +                }
    +            }
    +            else {
    +                if (node.getNextSibling() == null) {
    +                    indentation.insert(0, "    ");
    +                }
    +                else {
    +                    indentation.insert(0, "|   ");
    +                }
    +            }
    +        }
    +        return indentation.toString();
    +    }
    +
    +    /**
    +     * Replace all control chars with escaped symbols.
    +     * @param text the String to process.
    +     * @return the processed String with all control chars escaped.
    +     */
    +    private static String escapeAllControlChars(String text) {
    +        final String textWithoutNewlines = NEWLINE.matcher(text).replaceAll("\\\\n");
    +        final String textWithoutReturns = RETURN.matcher(textWithoutNewlines).replaceAll("\\\\r");
    +        return TAB.matcher(textWithoutReturns).replaceAll("\\\\t");
    +    }
    +
    +}
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/AuditEventDefaultFormatter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/AuditEventDefaultFormatter.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/AuditEventDefaultFormatter.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/AuditEventDefaultFormatter.java	2018-01-14 13:38:20.000000000 +0000
    @@ -1,6 +1,6 @@
     ////////////////////////////////////////////////////////////////////////////////
     // checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    +// Copyright (C) 2001-2018 the original author or authors.
     //
     // This library is free software; you can redistribute it and/or
     // modify it under the terms of the GNU Lesser General Public
    @@ -26,7 +26,10 @@
     
     /**
      * Represents the default formatter for log message.
    - * Default log message format is: [SEVERITY LEVEL] filePath:lineNo:columnNo: message. [CheckName]
    + * Default log message format is:
    + * [SEVERITY LEVEL] filePath:lineNo:columnNo: message. [CheckName]
    + * When the module id of the message has been set, the format is:
    + * [SEVERITY LEVEL] filePath:lineNo:columnNo: message. [ModuleId]
      * @author Andrei Selkin
      */
     public class AuditEventDefaultFormatter implements AuditEventFormatter {
    @@ -62,9 +65,15 @@
             if (event.getColumn() > 0) {
                 sb.append(':').append(event.getColumn());
             }
    -        sb.append(": ").append(message);
    -        final String checkShortName = getCheckShortName(event);
    -        sb.append(" [").append(checkShortName).append(']');
    +        sb.append(": ").append(message).append(" [");
    +        if (event.getModuleId() == null) {
    +            final String checkShortName = getCheckShortName(event);
    +            sb.append(checkShortName);
    +        }
    +        else {
    +            sb.append(event.getModuleId());
    +        }
    +        sb.append(']');
     
             return sb.toString();
         }
    @@ -85,7 +94,7 @@
     
         /**
          * Returns check name without 'Check' suffix.
    -     * @param event audit ivent.
    +     * @param event audit event.
          * @return check name without 'Check' suffix.
          */
         private static String getCheckShortName(AuditEvent event) {
    @@ -111,4 +120,5 @@
             }
             return checkShortName;
         }
    +
     }
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/AuditEventFormatter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/AuditEventFormatter.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/AuditEventFormatter.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/AuditEventFormatter.java	2018-01-14 13:38:20.000000000 +0000
    @@ -1,6 +1,6 @@
     ////////////////////////////////////////////////////////////////////////////////
     // checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    +// Copyright (C) 2001-2018 the original author or authors.
     //
     // This library is free software; you can redistribute it and/or
     // modify it under the terms of the GNU Lesser General Public
    @@ -25,11 +25,14 @@
      * Represents the formatter interface for log message.
      * @author Andrei Selkin
      */
    +@FunctionalInterface
     public interface AuditEventFormatter {
    +
         /**
          * Formats an error message.
          * @param event audit event.
          * @return string representation of error message.
          */
         String format(AuditEvent event);
    +
     }
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/Checker.java	2018-01-14 13:38:20.000000000 +0000
    @@ -1,6 +1,6 @@
     ////////////////////////////////////////////////////////////////////////////////
     // checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    +// Copyright (C) 2001-2018 the original author or authors.
     //
     // This library is free software; you can redistribute it and/or
     // modify it under the terms of the GNU Lesser General Public
    @@ -21,31 +21,38 @@
     
     import java.io.File;
     import java.io.IOException;
    +import java.io.PrintWriter;
    +import java.io.StringWriter;
     import java.io.UnsupportedEncodingException;
     import java.nio.charset.Charset;
    +import java.nio.charset.StandardCharsets;
    +import java.util.ArrayList;
    +import java.util.HashSet;
     import java.util.List;
     import java.util.Locale;
     import java.util.Set;
     import java.util.SortedSet;
    +import java.util.TreeSet;
     
    -import org.apache.commons.lang3.ArrayUtils;
     import org.apache.commons.logging.Log;
     import org.apache.commons.logging.LogFactory;
     
    -import com.google.common.collect.Lists;
    -import com.google.common.collect.Sets;
     import com.puppycrawl.tools.checkstyle.api.AuditEvent;
     import com.puppycrawl.tools.checkstyle.api.AuditListener;
     import com.puppycrawl.tools.checkstyle.api.AutomaticBean;
    +import com.puppycrawl.tools.checkstyle.api.BeforeExecutionFileFilter;
    +import com.puppycrawl.tools.checkstyle.api.BeforeExecutionFileFilterSet;
     import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
     import com.puppycrawl.tools.checkstyle.api.Configuration;
     import com.puppycrawl.tools.checkstyle.api.Context;
    +import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder;
     import com.puppycrawl.tools.checkstyle.api.FileSetCheck;
     import com.puppycrawl.tools.checkstyle.api.FileText;
     import com.puppycrawl.tools.checkstyle.api.Filter;
     import com.puppycrawl.tools.checkstyle.api.FilterSet;
     import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
     import com.puppycrawl.tools.checkstyle.api.MessageDispatcher;
    +import com.puppycrawl.tools.checkstyle.api.RootModule;
     import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
     import com.puppycrawl.tools.checkstyle.api.SeverityLevelCounter;
     import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
    @@ -55,20 +62,29 @@
      * @author Oliver Burn
      * @author Stephane Bailliez
      * @author lkuehne
    + * @author Andrei Selkin
      */
    -public class Checker extends AutomaticBean implements MessageDispatcher {
    +public class Checker extends AutomaticBean implements MessageDispatcher, RootModule {
    +
    +    /** Message to use when an exception occurs and should be printed as a violation. */
    +    public static final String EXCEPTION_MSG = "general.exception";
    +
         /** Logger for Checker. */
    -    private static final Log LOG = LogFactory.getLog(Checker.class);
    +    private final Log log;
     
         /** Maintains error count. */
         private final SeverityLevelCounter counter = new SeverityLevelCounter(
                 SeverityLevel.ERROR);
     
         /** Vector of listeners. */
    -    private final List listeners = Lists.newArrayList();
    +    private final List listeners = new ArrayList<>();
     
         /** Vector of fileset checks. */
    -    private final List fileSetChecks = Lists.newArrayList();
    +    private final List fileSetChecks = new ArrayList<>();
    +
    +    /** The audit event before execution file filters. */
    +    private final BeforeExecutionFileFilterSet beforeExecutionFileFilters =
    +            new BeforeExecutionFileFilterSet();
     
         /** The audit event filters. */
         private final FilterSet filters = new FilterSet();
    @@ -95,7 +111,7 @@
         private Context childContext;
     
         /** The file extensions that are accepted. */
    -    private String[] fileExtensions = ArrayUtils.EMPTY_STRING_ARRAY;
    +    private String[] fileExtensions = CommonUtils.EMPTY_STRING_ARRAY;
     
         /**
          * The severity level of any violations found by submodules.
    @@ -107,10 +123,16 @@
          * here. Consequently Checker does not extend AbstractViolationReporter,
          * leading to a bit of duplicated code for severity level setting.
          */
    -    private SeverityLevel severityLevel = SeverityLevel.ERROR;
    +    private SeverityLevel severity = SeverityLevel.ERROR;
     
         /** Name of a charset. */
    -    private String charset = System.getProperty("file.encoding", "UTF-8");
    +    private String charset = System.getProperty("file.encoding", StandardCharsets.UTF_8.name());
    +
    +    /** Cache file. **/
    +    private PropertyCacheFile cacheFile;
    +
    +    /** Controls whether exceptions should halt execution or not. */
    +    private boolean haltOnException = true;
     
         /**
          * Creates a new {@code Checker} instance.
    @@ -118,90 +140,26 @@
          */
         public Checker() {
             addListener(counter);
    -    }
    -
    -    @Override
    -    public void finishLocalSetup() throws CheckstyleException {
    -        final Locale locale = new Locale(localeLanguage, localeCountry);
    -        LocalizedMessage.setLocale(locale);
    -
    -        if (moduleFactory == null) {
    -
    -            if (moduleClassLoader == null) {
    -                throw new CheckstyleException(
    -                        "if no custom moduleFactory is set, "
    -                                + "moduleClassLoader must be specified");
    -            }
    -
    -            final Set packageNames = PackageNamesLoader
    -                    .getPackageNames(moduleClassLoader);
    -            moduleFactory = new PackageObjectFactory(packageNames,
    -                    moduleClassLoader);
    -        }
    -
    -        final DefaultContext context = new DefaultContext();
    -        context.add("charset", charset);
    -        context.add("classLoader", classLoader);
    -        context.add("moduleFactory", moduleFactory);
    -        context.add("severity", severityLevel.getName());
    -        context.add("basedir", basedir);
    -        childContext = context;
    -    }
    -
    -    @Override
    -    protected void setupChild(Configuration childConf)
    -        throws CheckstyleException {
    -        final String name = childConf.getName();
    -        final Object child;
    -
    -        try {
    -            child = moduleFactory.createModule(name);
    -
    -            if (child instanceof AutomaticBean) {
    -                final AutomaticBean bean = (AutomaticBean) child;
    -                bean.contextualize(childContext);
    -                bean.configure(childConf);
    -            }
    -        }
    -        catch (final CheckstyleException ex) {
    -            throw new CheckstyleException("cannot initialize module " + name
    -                    + " - " + ex.getMessage(), ex);
    -        }
    -        if (child instanceof FileSetCheck) {
    -            final FileSetCheck fsc = (FileSetCheck) child;
    -            fsc.init();
    -            addFileSetCheck(fsc);
    -        }
    -        else if (child instanceof Filter) {
    -            final Filter filter = (Filter) child;
    -            addFilter(filter);
    -        }
    -        else if (child instanceof AuditListener) {
    -            final AuditListener listener = (AuditListener) child;
    -            addListener(listener);
    -        }
    -        else {
    -            throw new CheckstyleException(name
    -                    + " is not allowed as a child in Checker");
    -        }
    +        log = LogFactory.getLog(Checker.class);
         }
     
         /**
    -     * Adds a FileSetCheck to the list of FileSetChecks
    -     * that is executed in process().
    -     * @param fileSetCheck the additional FileSetCheck
    +     * Sets cache file.
    +     * @param fileName the cache file.
    +     * @throws IOException if there are some problems with file loading.
          */
    -    public void addFileSetCheck(FileSetCheck fileSetCheck) {
    -        fileSetCheck.setMessageDispatcher(this);
    -        fileSetChecks.add(fileSetCheck);
    +    public void setCacheFile(String fileName) throws IOException {
    +        final Configuration configuration = getConfiguration();
    +        cacheFile = new PropertyCacheFile(configuration, fileName);
    +        cacheFile.load();
         }
     
         /**
    -     * Adds a filter to the end of the audit event filter chain.
    -     * @param filter the additional filter
    +     * Removes before execution file filter.
    +     * @param filter before execution file filter to remove.
          */
    -    public void addFilter(Filter filter) {
    -        filters.addFilter(filter);
    +    public void removeBeforeExecutionFileFilter(BeforeExecutionFileFilter filter) {
    +        beforeExecutionFileFilters.removeBeforeExecutionFileFilter(filter);
         }
     
         /**
    @@ -212,18 +170,20 @@
             filters.removeFilter(filter);
         }
     
    -    /** Cleans up the object. **/
    +    @Override
         public void destroy() {
             listeners.clear();
    +        fileSetChecks.clear();
    +        beforeExecutionFileFilters.clear();
             filters.clear();
    -    }
    -
    -    /**
    -     * Add the listener that will be used to receive events from the audit.
    -     * @param listener the nosy thing
    -     */
    -    public final void addListener(AuditListener listener) {
    -        listeners.add(listener);
    +        if (cacheFile != null) {
    +            try {
    +                cacheFile.persist();
    +            }
    +            catch (IOException ex) {
    +                throw new IllegalStateException("Unable to persist cache file.", ex);
    +            }
    +        }
         }
     
         /**
    @@ -235,64 +195,33 @@
         }
     
         /**
    -     * Processes a set of files with all FileSetChecks.
    -     * Once this is done, it is highly recommended to call for
    -     * the destroy method to close and remove the listeners.
    -     * @param files the list of files to be audited.
    -     * @return the total number of errors found
    -     * @throws CheckstyleException if error condition within Checkstyle occurs
    -     * @see #destroy()
    +     * Sets base directory.
    +     * @param basedir the base directory to strip off in file names
          */
    +    public void setBasedir(String basedir) {
    +        this.basedir = basedir;
    +    }
    +
    +    @Override
         public int process(List files) throws CheckstyleException {
    +        if (cacheFile != null) {
    +            cacheFile.putExternalResources(getExternalResourceLocations());
    +        }
    +
             // Prepare to start
             fireAuditStarted();
             for (final FileSetCheck fsc : fileSetChecks) {
                 fsc.beginProcessing(charset);
             }
     
    -        // Process each file
    -        for (final File file : files) {
    -            try {
    -                if (!CommonUtils.matchesFileExtension(file, fileExtensions)) {
    -                    continue;
    -                }
    -                final String fileName = file.getAbsolutePath();
    -                fireFileStarted(fileName);
    -                final SortedSet fileMessages = Sets.newTreeSet();
    -                try {
    -                    final FileText theText = new FileText(file.getAbsoluteFile(),
    -                            charset);
    -                    for (final FileSetCheck fsc : fileSetChecks) {
    -                        fileMessages.addAll(fsc.process(file, theText));
    -                    }
    -                }
    -                catch (final IOException ioe) {
    -                    LOG.debug("IOException occurred.", ioe);
    -                    fileMessages.add(new LocalizedMessage(0,
    -                            Definitions.CHECKSTYLE_BUNDLE, "general.exception",
    -                            new String[] {ioe.getMessage()}, null, getClass(),
    -                            null));
    -                }
    -                fireErrors(fileName, fileMessages);
    -                fireFileFinished(fileName);
    -            }
    -            catch (Exception ex) {
    -                // We need to catch all exception to put a reason failure(file name) in exception
    -                throw new CheckstyleException("Exception was thrown while processing "
    -                        + file.getPath(), ex);
    -            }
    -        }
    +        processFiles(files);
     
             // Finish up
    -        for (final FileSetCheck fsc : fileSetChecks) {
    -            // It may also log!!!
    -            fsc.finishProcessing();
    -        }
    +        // It may also log!!!
    +        fileSetChecks.forEach(FileSetCheck::finishProcessing);
     
    -        for (final FileSetCheck fsc : fileSetChecks) {
    -            // It may also log!!!
    -            fsc.destroy();
    -        }
    +        // It may also log!!!
    +        fileSetChecks.forEach(FileSetCheck::destroy);
     
             final int errorCount = counter.getCount();
             fireAuditFinished();
    @@ -300,15 +229,30 @@
         }
     
         /**
    -     * Sets base directory.
    -     * @param basedir the base directory to strip off in file names
    -     */
    -    public void setBasedir(String basedir) {
    -        this.basedir = basedir;
    +     * Returns a set of external configuration resource locations which are used by all file set
    +     * checks and filters.
    +     * @return a set of external configuration resource locations which are used by all file set
    +     *         checks and filters.
    +     */
    +    private Set getExternalResourceLocations() {
    +        final Set externalResources = new HashSet<>();
    +        fileSetChecks.stream().filter(check -> check instanceof ExternalResourceHolder)
    +            .forEach(check -> {
    +                final Set locations =
    +                    ((ExternalResourceHolder) check).getExternalResourceLocations();
    +                externalResources.addAll(locations);
    +            });
    +        filters.getFilters().stream().filter(filter -> filter instanceof ExternalResourceHolder)
    +            .forEach(filter -> {
    +                final Set locations =
    +                    ((ExternalResourceHolder) filter).getExternalResourceLocations();
    +                externalResources.addAll(locations);
    +            });
    +        return externalResources;
         }
     
         /** Notify all listeners about the audit start. */
    -    void fireAuditStarted() {
    +    private void fireAuditStarted() {
             final AuditEvent event = new AuditEvent(this);
             for (final AuditListener listener : listeners) {
                 listener.auditStarted(event);
    @@ -316,7 +260,7 @@
         }
     
         /** Notify all listeners about the audit end. */
    -    void fireAuditFinished() {
    +    private void fireAuditFinished() {
             final AuditEvent event = new AuditEvent(this);
             for (final AuditListener listener : listeners) {
                 listener.auditFinished(event);
    @@ -324,32 +268,109 @@
         }
     
         /**
    -     * Notify all listeners about the beginning of a file audit.
    +     * Processes a list of files with all FileSetChecks.
    +     * @param files a list of files to process.
    +     * @throws CheckstyleException if error condition within Checkstyle occurs.
    +     * @noinspection ProhibitedExceptionThrown
    +     */
    +    private void processFiles(List files) throws CheckstyleException {
    +        for (final File file : files) {
    +            try {
    +                final String fileName = file.getAbsolutePath();
    +                final long timestamp = file.lastModified();
    +                if (cacheFile != null && cacheFile.isInCache(fileName, timestamp)
    +                        || !CommonUtils.matchesFileExtension(file, fileExtensions)
    +                        || !acceptFileStarted(fileName)) {
    +                    continue;
    +                }
    +                if (cacheFile != null) {
    +                    cacheFile.put(fileName, timestamp);
    +                }
    +                fireFileStarted(fileName);
    +                final SortedSet fileMessages = processFile(file);
    +                fireErrors(fileName, fileMessages);
    +                fireFileFinished(fileName);
    +            }
    +            // -@cs[IllegalCatch] There is no other way to deliver filename that was under
    +            // processing. See https://github.com/checkstyle/checkstyle/issues/2285
    +            catch (Exception ex) {
    +                // We need to catch all exceptions to put a reason failure (file name) in exception
    +                throw new CheckstyleException("Exception was thrown while processing "
    +                        + file.getPath(), ex);
    +            }
    +            catch (Error error) {
    +                // We need to catch all errors to put a reason failure (file name) in error
    +                throw new Error("Error was thrown while processing " + file.getPath(), error);
    +            }
    +        }
    +    }
    +
    +    /**
    +     * Processes a file with all FileSetChecks.
    +     * @param file a file to process.
    +     * @return a sorted set of messages to be logged.
    +     * @throws CheckstyleException if error condition within Checkstyle occurs.
    +     * @noinspection ProhibitedExceptionThrown
    +     */
    +    private SortedSet processFile(File file) throws CheckstyleException {
    +        final SortedSet fileMessages = new TreeSet<>();
    +        try {
    +            final FileText theText = new FileText(file.getAbsoluteFile(), charset);
    +            for (final FileSetCheck fsc : fileSetChecks) {
    +                fileMessages.addAll(fsc.process(file, theText));
    +            }
    +        }
    +        catch (final IOException ioe) {
    +            log.debug("IOException occurred.", ioe);
    +            fileMessages.add(new LocalizedMessage(0,
    +                    Definitions.CHECKSTYLE_BUNDLE, EXCEPTION_MSG,
    +                    new String[] {ioe.getMessage()}, null, getClass(), null));
    +        }
    +        // -@cs[IllegalCatch] There is no other way to obey haltOnException field
    +        catch (Exception ex) {
    +            if (haltOnException) {
    +                throw ex;
    +            }
    +
    +            log.debug("Exception occurred.", ex);
    +
    +            final StringWriter sw = new StringWriter();
    +            final PrintWriter pw = new PrintWriter(sw, true);
    +
    +            ex.printStackTrace(pw);
    +
    +            fileMessages.add(new LocalizedMessage(0,
    +                    Definitions.CHECKSTYLE_BUNDLE, EXCEPTION_MSG,
    +                    new String[] {sw.getBuffer().toString()},
    +                    null, getClass(), null));
    +        }
    +        return fileMessages;
    +    }
    +
    +    /**
    +     * Check if all before execution file filters accept starting the file.
          *
          * @param fileName
          *            the file to be audited
    +     * @return {@code true} if the file is accepted.
          */
    -    @Override
    -    public void fireFileStarted(String fileName) {
    +    private boolean acceptFileStarted(String fileName) {
             final String stripped = CommonUtils.relativizeAndNormalizePath(basedir, fileName);
    -        final AuditEvent event = new AuditEvent(this, stripped);
    -        for (final AuditListener listener : listeners) {
    -            listener.fileStarted(event);
    -        }
    +        return beforeExecutionFileFilters.accept(stripped);
         }
     
         /**
    -     * Notify all listeners about the end of a file audit.
    +     * Notify all listeners about the beginning of a file audit.
          *
          * @param fileName
    -     *            the audited file
    +     *            the file to be audited
          */
         @Override
    -    public void fireFileFinished(String fileName) {
    +    public void fireFileStarted(String fileName) {
             final String stripped = CommonUtils.relativizeAndNormalizePath(basedir, fileName);
             final AuditEvent event = new AuditEvent(this, stripped);
             for (final AuditListener listener : listeners) {
    -            listener.fileFinished(event);
    +            listener.fileStarted(event);
             }
         }
     
    @@ -362,14 +383,138 @@
         @Override
         public void fireErrors(String fileName, SortedSet errors) {
             final String stripped = CommonUtils.relativizeAndNormalizePath(basedir, fileName);
    +        boolean hasNonFilteredViolations = false;
             for (final LocalizedMessage element : errors) {
                 final AuditEvent event = new AuditEvent(this, stripped, element);
                 if (filters.accept(event)) {
    +                hasNonFilteredViolations = true;
                     for (final AuditListener listener : listeners) {
                         listener.addError(event);
                     }
                 }
             }
    +        if (hasNonFilteredViolations && cacheFile != null) {
    +            cacheFile.remove(fileName);
    +        }
    +    }
    +
    +    /**
    +     * Notify all listeners about the end of a file audit.
    +     *
    +     * @param fileName
    +     *            the audited file
    +     */
    +    @Override
    +    public void fireFileFinished(String fileName) {
    +        final String stripped = CommonUtils.relativizeAndNormalizePath(basedir, fileName);
    +        final AuditEvent event = new AuditEvent(this, stripped);
    +        for (final AuditListener listener : listeners) {
    +            listener.fileFinished(event);
    +        }
    +    }
    +
    +    @Override
    +    protected void finishLocalSetup() throws CheckstyleException {
    +        final Locale locale = new Locale(localeLanguage, localeCountry);
    +        LocalizedMessage.setLocale(locale);
    +
    +        if (moduleFactory == null) {
    +            if (moduleClassLoader == null) {
    +                throw new CheckstyleException(
    +                        "if no custom moduleFactory is set, "
    +                                + "moduleClassLoader must be specified");
    +            }
    +
    +            final Set packageNames = PackageNamesLoader
    +                    .getPackageNames(moduleClassLoader);
    +            moduleFactory = new PackageObjectFactory(packageNames,
    +                    moduleClassLoader);
    +        }
    +
    +        final DefaultContext context = new DefaultContext();
    +        context.add("charset", charset);
    +        context.add("classLoader", classLoader);
    +        context.add("moduleFactory", moduleFactory);
    +        context.add("severity", severity.getName());
    +        context.add("basedir", basedir);
    +        childContext = context;
    +    }
    +
    +    /**
    +     * {@inheritDoc} Creates child module.
    +     * @noinspection ChainOfInstanceofChecks
    +     */
    +    @Override
    +    protected void setupChild(Configuration childConf)
    +            throws CheckstyleException {
    +        final String name = childConf.getName();
    +        final Object child;
    +
    +        try {
    +            child = moduleFactory.createModule(name);
    +
    +            if (child instanceof AutomaticBean) {
    +                final AutomaticBean bean = (AutomaticBean) child;
    +                bean.contextualize(childContext);
    +                bean.configure(childConf);
    +            }
    +        }
    +        catch (final CheckstyleException ex) {
    +            throw new CheckstyleException("cannot initialize module " + name
    +                    + " - " + ex.getMessage(), ex);
    +        }
    +        if (child instanceof FileSetCheck) {
    +            final FileSetCheck fsc = (FileSetCheck) child;
    +            fsc.init();
    +            addFileSetCheck(fsc);
    +        }
    +        else if (child instanceof BeforeExecutionFileFilter) {
    +            final BeforeExecutionFileFilter filter = (BeforeExecutionFileFilter) child;
    +            addBeforeExecutionFileFilter(filter);
    +        }
    +        else if (child instanceof Filter) {
    +            final Filter filter = (Filter) child;
    +            addFilter(filter);
    +        }
    +        else if (child instanceof AuditListener) {
    +            final AuditListener listener = (AuditListener) child;
    +            addListener(listener);
    +        }
    +        else {
    +            throw new CheckstyleException(name
    +                    + " is not allowed as a child in Checker");
    +        }
    +    }
    +
    +    /**
    +     * Adds a FileSetCheck to the list of FileSetChecks
    +     * that is executed in process().
    +     * @param fileSetCheck the additional FileSetCheck
    +     */
    +    public void addFileSetCheck(FileSetCheck fileSetCheck) {
    +        fileSetCheck.setMessageDispatcher(this);
    +        fileSetChecks.add(fileSetCheck);
    +    }
    +
    +    /**
    +     * Adds a before execution file filter to the end of the event chain.
    +     * @param filter the additional filter
    +     */
    +    public void addBeforeExecutionFileFilter(BeforeExecutionFileFilter filter) {
    +        beforeExecutionFileFilters.addBeforeExecutionFileFilter(filter);
    +    }
    +
    +    /**
    +     * Adds a filter to the end of the audit event filter chain.
    +     * @param filter the additional filter
    +     */
    +    public void addFilter(Filter filter) {
    +        filters.addFilter(filter);
    +    }
    +
    +    @Override
    +    public final void addListener(AuditListener listener) {
    +        listeners.add(listener);
         }
     
         /**
    @@ -381,17 +526,17 @@
         public final void setFileExtensions(String... extensions) {
             if (extensions == null) {
                 fileExtensions = null;
    -            return;
             }
    -
    -        fileExtensions = new String[extensions.length];
    -        for (int i = 0; i < extensions.length; i++) {
    -            final String extension = extensions[i];
    -            if (CommonUtils.startsWithChar(extension, '.')) {
    -                fileExtensions[i] = extension;
    -            }
    -            else {
    -                fileExtensions[i] = "." + extension;
    +        else {
    +            fileExtensions = new String[extensions.length];
    +            for (int i = 0; i < extensions.length; i++) {
    +                final String extension = extensions[i];
    +                if (CommonUtils.startsWithChar(extension, '.')) {
    +                    fileExtensions[i] = extension;
    +                }
    +                else {
    +                    fileExtensions[i] = "." + extension;
    +                }
                 }
             }
         }
    @@ -429,7 +574,7 @@
          * @see SeverityLevel
          */
         public final void setSeverity(String severity) {
    -        severityLevel = SeverityLevel.getInstance(severity);
    +        this.severity = SeverityLevel.getInstance(severity);
         }
     
         /**
    @@ -443,26 +588,7 @@
             this.classLoader = classLoader;
         }
     
    -    /**
    -     * Sets the classloader that is used to contextualize fileset checks.
    -     * Some Check implementations will use that classloader to improve the
    -     * quality of their reports, e.g. to load a class and then analyze it via
    -     * reflection.
    -     * @param loader the new classloader
    -     * @deprecated use {@link #setClassLoader(ClassLoader loader)} instead.
    -     */
    -    @Deprecated
    -    public final void setClassloader(ClassLoader loader) {
    -        classLoader = loader;
    -    }
    -
    -    /**
    -     * Sets the classloader used to load Checkstyle core and custom module
    -     * classes when the module tree is being built up.
    -     * If no custom ModuleFactory is being set for the Checker module then
    -     * this module classloader must be specified.
    -     * @param moduleClassLoader the classloader used to load module classes
    -     */
    +    @Override
         public final void setModuleClassLoader(ClassLoader moduleClassLoader) {
             this.moduleClassLoader = moduleClassLoader;
         }
    @@ -473,11 +599,29 @@
          * @throws UnsupportedEncodingException if charset is unsupported.
          */
         public void setCharset(String charset)
    -        throws UnsupportedEncodingException {
    +            throws UnsupportedEncodingException {
             if (!Charset.isSupported(charset)) {
                 final String message = "unsupported charset: '" + charset + "'";
                 throw new UnsupportedEncodingException(message);
             }
             this.charset = charset;
         }
    +
    +    /**
    +     * Sets the field haltOnException.
    +     * @param haltOnException the new value.
    +     */
    +    public void setHaltOnException(boolean haltOnException) {
    +        this.haltOnException = haltOnException;
    +    }
    +
    +    /**
    +     * Clears the cache.
    +     */
    +    public void clearCache() {
    +        if (cacheFile != null) {
    +            cacheFile.reset();
    +        }
    +    }
    +
     }
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractDeclarationCollector.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractDeclarationCollector.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractDeclarationCollector.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractDeclarationCollector.java	1970-01-01 00:00:00.000000000 +0000
    @@ -1,414 +0,0 @@
    -////////////////////////////////////////////////////////////////////////////////
    -// checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    -//
    -// This library is free software; you can redistribute it and/or
    -// modify it under the terms of the GNU Lesser General Public
    -// License as published by the Free Software Foundation; either
    -// version 2.1 of the License, or (at your option) any later version.
    -//
    -// This library is distributed in the hope that it will be useful,
    -// but WITHOUT ANY WARRANTY; without even the implied warranty of
    -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    -// Lesser General Public License for more details.
    -//
    -// You should have received a copy of the GNU Lesser General Public
    -// License along with this library; if not, write to the Free Software
    -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    -////////////////////////////////////////////////////////////////////////////////
    -
    -package com.puppycrawl.tools.checkstyle.checks;
    -
    -import java.util.Deque;
    -import java.util.Map;
    -import java.util.Queue;
    -import java.util.Set;
    -
    -import com.google.common.collect.Lists;
    -import com.google.common.collect.Maps;
    -import com.google.common.collect.Sets;
    -import com.puppycrawl.tools.checkstyle.api.Check;
    -import com.puppycrawl.tools.checkstyle.api.DetailAST;
    -import com.puppycrawl.tools.checkstyle.api.TokenTypes;
    -import com.puppycrawl.tools.checkstyle.utils.ScopeUtils;
    -
    -/**
    - * Abstract class for checks which need to collect information about
    - * declared members/parameters/variables.
    - * @deprecated Checkstyle will not support abstract checks anymore. Use {@link Check} instead.
    - * @author o_sukhodolsky
    - * @noinspection AbstractClassNeverImplemented
    - */
    -@Deprecated
    -public abstract class AbstractDeclarationCollector extends Check {
    -    /**
    -     * Tree of all the parsed frames.
    -     */
    -    private Map frames;
    -
    -    /**
    -     * Frame for the currently processed AST.
    -     */
    -    private LexicalFrame current;
    -
    -    @Override
    -    public void beginTree(DetailAST rootAST) {
    -        final Deque frameStack = Lists.newLinkedList();
    -        frameStack.add(new GlobalFrame());
    -
    -        frames = Maps.newHashMap();
    -
    -        DetailAST curNode = rootAST;
    -        while (curNode != null) {
    -            collectDeclarations(frameStack, curNode);
    -            DetailAST toVisit = curNode.getFirstChild();
    -            while (curNode != null && toVisit == null) {
    -                endCollectingDeclarations(frameStack, curNode);
    -                toVisit = curNode.getNextSibling();
    -                if (toVisit == null) {
    -                    curNode = curNode.getParent();
    -                }
    -            }
    -            curNode = toVisit;
    -        }
    -    }
    -
    -    @Override
    -    public void visitToken(DetailAST ast) {
    -        switch (ast.getType()) {
    -            case TokenTypes.CLASS_DEF :
    -            case TokenTypes.INTERFACE_DEF :
    -            case TokenTypes.ENUM_DEF :
    -            case TokenTypes.ANNOTATION_DEF :
    -            case TokenTypes.SLIST :
    -            case TokenTypes.METHOD_DEF :
    -            case TokenTypes.CTOR_DEF :
    -                current = frames.get(ast);
    -                break;
    -            default :
    -                // do nothing
    -        }
    -    }
    -
    -    /**
    -     * Parse the next AST for declarations.
    -     *
    -     * @param frameStack Stack containing the FrameTree being built
    -     * @param ast AST to parse
    -     */
    -    private static void collectDeclarations(Deque frameStack,
    -        DetailAST ast) {
    -        final LexicalFrame frame = frameStack.peek();
    -        switch (ast.getType()) {
    -            case TokenTypes.VARIABLE_DEF :
    -                collectVariableDeclarations(ast, frame);
    -                break;
    -            case TokenTypes.PARAMETER_DEF :
    -                final DetailAST parameterAST = ast.findFirstToken(TokenTypes.IDENT);
    -                frame.addName(parameterAST.getText());
    -                break;
    -            case TokenTypes.CLASS_DEF :
    -            case TokenTypes.INTERFACE_DEF :
    -            case TokenTypes.ENUM_DEF :
    -            case TokenTypes.ANNOTATION_DEF :
    -                final DetailAST classAST = ast.findFirstToken(TokenTypes.IDENT);
    -                frame.addName(classAST.getText());
    -                frameStack.addFirst(new ClassFrame(frame));
    -                break;
    -            case TokenTypes.SLIST :
    -                frameStack.addFirst(new BlockFrame(frame));
    -                break;
    -            case TokenTypes.METHOD_DEF :
    -                final String name = ast.findFirstToken(TokenTypes.IDENT).getText();
    -                if (frame instanceof ClassFrame) {
    -                    final DetailAST mods =
    -                            ast.findFirstToken(TokenTypes.MODIFIERS);
    -                    if (mods.branchContains(TokenTypes.LITERAL_STATIC)) {
    -                        ((ClassFrame) frame).addStaticMethod(name);
    -                    }
    -                    else {
    -                        ((ClassFrame) frame).addInstanceMethod(name);
    -                    }
    -                }
    -                frameStack.addFirst(new MethodFrame(frame));
    -                break;
    -            case TokenTypes.CTOR_DEF :
    -                frameStack.addFirst(new MethodFrame(frame));
    -                break;
    -            default:
    -                // do nothing
    -        }
    -    }
    -
    -    /**
    -     * Collect Variable Declarations.
    -     * @param ast variable token
    -     * @param frame current frame
    -     */
    -    private static void collectVariableDeclarations(DetailAST ast, LexicalFrame frame) {
    -        final String name =
    -                ast.findFirstToken(TokenTypes.IDENT).getText();
    -        if (frame instanceof ClassFrame) {
    -            final DetailAST mods =
    -                    ast.findFirstToken(TokenTypes.MODIFIERS);
    -            if (ScopeUtils.isInInterfaceBlock(ast)
    -                    || mods.branchContains(TokenTypes.LITERAL_STATIC)) {
    -                ((ClassFrame) frame).addStaticMember(name);
    -            }
    -            else {
    -                ((ClassFrame) frame).addInstanceMember(name);
    -            }
    -        }
    -        else {
    -            frame.addName(name);
    -        }
    -    }
    -
    -    /**
    -     * End parsing of the AST for declarations.
    -     *
    -     * @param frameStack Stack containing the FrameTree being built
    -     * @param ast AST that was parsed
    -     */
    -    private void endCollectingDeclarations(Queue frameStack,
    -        DetailAST ast) {
    -        switch (ast.getType()) {
    -            case TokenTypes.CLASS_DEF :
    -            case TokenTypes.INTERFACE_DEF :
    -            case TokenTypes.ENUM_DEF :
    -            case TokenTypes.ANNOTATION_DEF :
    -            case TokenTypes.SLIST :
    -            case TokenTypes.METHOD_DEF :
    -            case TokenTypes.CTOR_DEF :
    -                frames.put(ast, frameStack.poll());
    -                break;
    -            default :
    -                // do nothing
    -        }
    -    }
    -
    -    /**
    -     * Check if given name is a name for class field in current environment.
    -     * @param name a name to check
    -     * @return true is the given name is name of member.
    -     */
    -    protected final boolean isClassField(String name) {
    -        final LexicalFrame frame = findFrame(name);
    -        return frame instanceof ClassFrame
    -                && ((ClassFrame) frame).hasInstanceMember(name);
    -    }
    -
    -    /**
    -     * Check if given name is a name for class method in current environment.
    -     * @param name a name to check
    -     * @return true is the given name is name of method.
    -     */
    -    protected final boolean isClassMethod(String name) {
    -        final LexicalFrame frame = findFrame(name);
    -        return frame instanceof ClassFrame
    -                && ((ClassFrame) frame).hasInstanceMethod(name);
    -    }
    -
    -    /**
    -     * Find frame containing declaration.
    -     * @param name name of the declaration to find
    -     * @return LexicalFrame containing declaration or null
    -     */
    -    private LexicalFrame findFrame(String name) {
    -        if (current == null) {
    -            return null;
    -        }
    -        else {
    -            return current.getIfContains(name);
    -        }
    -    }
    -
    -    /**
    -     * A declaration frame.
    -     * @author Stephen Bloch
    -     */
    -    private static class LexicalFrame {
    -        /** Set of name of variables declared in this frame. */
    -        private final Set varNames;
    -        /**
    -         * Parent frame.
    -         */
    -        private final LexicalFrame parent;
    -
    -        /**
    -         * Constructor -- invokable only via super() from subclasses.
    -         *
    -         * @param parent parent frame
    -         */
    -        protected LexicalFrame(LexicalFrame parent) {
    -            this.parent = parent;
    -            varNames = Sets.newHashSet();
    -        }
    -
    -        /** Add a name to the frame.
    -         * @param nameToAdd the name we're adding
    -         */
    -        private void addName(String nameToAdd) {
    -            varNames.add(nameToAdd);
    -        }
    -
    -        /** Check whether the frame contains a given name.
    -         * @param nameToFind the name we're looking for
    -         * @return whether it was found
    -         */
    -        boolean contains(String nameToFind) {
    -            return varNames.contains(nameToFind);
    -        }
    -
    -        /** Check whether the frame contains a given name.
    -         * @param nameToFind the name we're looking for
    -         * @return whether it was found
    -         */
    -        private LexicalFrame getIfContains(String nameToFind) {
    -            LexicalFrame frame = null;
    -
    -            if (contains(nameToFind)) {
    -                frame = this;
    -            }
    -            else if (parent != null) {
    -                frame = parent.getIfContains(nameToFind);
    -            }
    -            return frame;
    -        }
    -    }
    -
    -    /**
    -     * The global frame; should hold only class names.
    -     * @author Stephen Bloch
    -     */
    -    private static class GlobalFrame extends LexicalFrame {
    -
    -        /**
    -         * Constructor for the root of the FrameTree.
    -         */
    -        protected GlobalFrame() {
    -            super(null);
    -        }
    -    }
    -
    -    /**
    -     * A frame initiated at method definition; holds parameter names.
    -     * @author Stephen Bloch
    -     */
    -    private static class MethodFrame extends LexicalFrame {
    -        /**
    -         * Creates method frame.
    -         * @param parent parent frame
    -         */
    -        protected MethodFrame(LexicalFrame parent) {
    -            super(parent);
    -        }
    -    }
    -
    -    /**
    -     * A frame initiated at class definition; holds instance variable
    -     * names.  For the present, I'm not worried about other class names,
    -     * method names, etc.
    -     * @author Stephen Bloch
    -     */
    -    private static class ClassFrame extends LexicalFrame {
    -        /** Set of name of instance members declared in this frame. */
    -        private final Set instanceMembers;
    -        /** Set of name of instance methods declared in this frame. */
    -        private final Set instanceMethods;
    -        /** Set of name of variables declared in this frame. */
    -        private final Set staticMembers;
    -        /** Set of name of static methods declared in this frame. */
    -        private final Set staticMethods;
    -
    -        /**
    -         * Creates new instance of ClassFrame.
    -         * @param parent parent frame
    -         */
    -        ClassFrame(LexicalFrame parent) {
    -            super(parent);
    -            instanceMembers = Sets.newHashSet();
    -            instanceMethods = Sets.newHashSet();
    -            staticMembers = Sets.newHashSet();
    -            staticMethods = Sets.newHashSet();
    -        }
    -
    -        /**
    -         * Adds static member's name.
    -         * @param name a name of static member of the class
    -         */
    -        public void addStaticMember(final String name) {
    -            staticMembers.add(name);
    -        }
    -
    -        /**
    -         * Adds static method's name.
    -         * @param name a name of static method of the class
    -         */
    -        public void addStaticMethod(final String name) {
    -            staticMethods.add(name);
    -        }
    -
    -        /**
    -         * Adds instance member's name.
    -         * @param name a name of instance member of the class
    -         */
    -        public void addInstanceMember(final String name) {
    -            instanceMembers.add(name);
    -        }
    -
    -        /**
    -         * Adds instance method's name.
    -         * @param name a name of instance method of the class
    -         */
    -        public void addInstanceMethod(final String name) {
    -            instanceMethods.add(name);
    -        }
    -
    -        /**
    -         * Checks if a given name is a known instance member of the class.
    -         * @param name a name to check
    -         * @return true is the given name is a name of a known
    -         *         instance member of the class
    -         */
    -        public boolean hasInstanceMember(final String name) {
    -            return instanceMembers.contains(name);
    -        }
    -
    -        /**
    -         * Checks if a given name is a known instance method of the class.
    -         * @param name a name to check
    -         * @return true is the given name is a name of a known
    -         *         instance method of the class
    -         */
    -        public boolean hasInstanceMethod(final String name) {
    -            return instanceMethods.contains(name);
    -        }
    -
    -        @Override
    -        boolean contains(String nameToFind) {
    -            return super.contains(nameToFind)
    -                    || instanceMembers.contains(nameToFind)
    -                    || instanceMethods.contains(nameToFind)
    -                    || staticMembers.contains(nameToFind)
    -                    || staticMethods.contains(nameToFind);
    -        }
    -    }
    -
    -    /**
    -     * A frame initiated on entering a statement list; holds local variable
    -     * names.  For the present, I'm not worried about other class names,
    -     * method names, etc.
    -     * @author Stephen Bloch
    -     */
    -    private static class BlockFrame extends LexicalFrame {
    -
    -        /**
    -         * Creates block frame.
    -         * @param parent parent frame
    -         */
    -        protected BlockFrame(LexicalFrame parent) {
    -            super(parent);
    -        }
    -    }
    -}
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractFormatCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractFormatCheck.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractFormatCheck.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractFormatCheck.java	1970-01-01 00:00:00.000000000 +0000
    @@ -1,118 +0,0 @@
    -////////////////////////////////////////////////////////////////////////////////
    -// checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    -//
    -// This library is free software; you can redistribute it and/or
    -// modify it under the terms of the GNU Lesser General Public
    -// License as published by the Free Software Foundation; either
    -// version 2.1 of the License, or (at your option) any later version.
    -//
    -// This library is distributed in the hope that it will be useful,
    -// but WITHOUT ANY WARRANTY; without even the implied warranty of
    -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    -// Lesser General Public License for more details.
    -//
    -// You should have received a copy of the GNU Lesser General Public
    -// License along with this library; if not, write to the Free Software
    -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    -////////////////////////////////////////////////////////////////////////////////
    -
    -package com.puppycrawl.tools.checkstyle.checks;
    -
    -import java.util.regex.Pattern;
    -import java.util.regex.PatternSyntaxException;
    -
    -import org.apache.commons.beanutils.ConversionException;
    -
    -import com.puppycrawl.tools.checkstyle.api.Check;
    -
    -/**
    - * 

    Abstract class for checks that verify strings using a - * {@link Pattern regular expression}. It - * provides support for setting the regular - * expression using the property name {@code format}.

    - * @deprecated Checkstyle will not support abstract checks anymore. Use {@link Check} instead. - * @author Oliver Burn - * @noinspection AbstractClassNeverImplemented - */ -@Deprecated -public abstract class AbstractFormatCheck - extends Check { - /** The flags to create the regular expression with. */ - private int compileFlags; - /** The regexp to match against. */ - private Pattern regexp; - /** The format string of the regexp. */ - private String format; - - /** - * Creates a new {@code AbstractFormatCheck} instance. Defaults the - * compile flag to 0 (the default). - * @param defaultFormat default format - * @throws ConversionException unable to parse defaultFormat - */ - protected AbstractFormatCheck(String defaultFormat) { - this(defaultFormat, 0); - } - - /** - * Creates a new {@code AbstractFormatCheck} instance. - * @param defaultFormat default format - * @param compileFlags the Pattern flags to compile the regexp with. - * See {@link Pattern#compile(String, int)} - * @throws ConversionException unable to parse defaultFormat - */ - protected AbstractFormatCheck(String defaultFormat, int compileFlags) { - updateRegexp(defaultFormat, compileFlags); - } - - /** - * Set the format to the specified regular expression. - * @param format a {@code String} value - * @throws ConversionException unable to parse format - */ - public final void setFormat(String format) { - updateRegexp(format, compileFlags); - } - - /** - * Set the compile flags for the regular expression. - * @param compileFlags the compile flags to use. - */ - public final void setCompileFlags(int compileFlags) { - updateRegexp(format, compileFlags); - } - - /** - * Gets the regexp. - * @return the regexp to match against - */ - public final Pattern getRegexp() { - return regexp; - } - - /** - * Gets the regexp format. - * @return the regexp format - */ - public final String getFormat() { - return format; - } - - /** - * Updates the regular expression using the supplied format and compiler - * flags. Will also update the member variables. - * @param regexpFormat the format of the regular expression. - * @param compileFlagsParam the compiler flags to use. - */ - private void updateRegexp(String regexpFormat, int compileFlagsParam) { - try { - regexp = Pattern.compile(regexpFormat, compileFlagsParam); - format = regexpFormat; - compileFlags |= compileFlagsParam; - } - catch (final PatternSyntaxException ex) { - throw new ConversionException("unable to parse " + regexpFormat, ex); - } - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractOptionCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractOptionCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractOptionCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractOptionCheck.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,87 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.checks; - -import java.util.Locale; - -import org.apache.commons.beanutils.ConversionException; - -import com.puppycrawl.tools.checkstyle.api.Check; - -/** - * Abstract class for checks with a parameter named option, where the - * option is identified by a {@link Enum}. The logic to convert from a string - * representation to the {@link Enum} is to {@link String#trim()} the string - * and convert using {@link String#toUpperCase()} and then look up using - * {@link Enum#valueOf}. - * @deprecated Checkstyle will not support abstract checks anymore. Use {@link Check} instead. - * @author Oliver Burn - * @author Rick Giles - * @param the type of the option. - * @noinspection AbstractClassNeverImplemented - */ -@Deprecated -public abstract class AbstractOptionCheck> - extends Check { - - /** Semicolon literal. */ - protected static final String SEMICOLON = ";"; - - /** Since I cannot get this by going T.class. */ - private final Class optionClass; - /** The policy to enforce. */ - private T abstractOption; - - /** - * Creates a new {@code AbstractOptionCheck} instance. - * @param literalDefault the default option. - * @param optionClass the class for the option. Required due to a quirk - * in the Java language. - */ - protected AbstractOptionCheck(T literalDefault, Class optionClass) { - abstractOption = literalDefault; - this.optionClass = optionClass; - } - - /** - * Set the option to enforce. - * @param optionStr string to decode option from - * @throws ConversionException if unable to decode - */ - public void setOption(String optionStr) { - try { - abstractOption = - Enum.valueOf(optionClass, optionStr.trim().toUpperCase(Locale.ENGLISH)); - } - catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + optionStr, iae); - } - } - - /** - * Gets AbstractOption set. - * @return the {@code AbstractOption} set - */ - public T getAbstractOption() { - // WARNING!! Do not rename this method to getOption(). It breaks - // BeanUtils, which will silently not call setOption. Very annoying! - return abstractOption; - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractTypeAwareCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractTypeAwareCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractTypeAwareCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/AbstractTypeAwareCheck.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,562 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.checks; - -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; -import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.api.FullIdent; -import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; - -/** - * Abstract class that endeavours to maintain type information for the Java - * file being checked. It provides helper methods for performing type - * information functions. - * - * @author Oliver Burn - * @deprecated Checkstyle is not type aware tool and all Checks derived from this - * class are potentially unstable. - */ -@Deprecated -public abstract class AbstractTypeAwareCheck extends Check { - /** Stack of maps for type params. */ - private final Deque> typeParams = new ArrayDeque<>(); - - /** Imports details. **/ - private final Set imports = Sets.newHashSet(); - - /** Full identifier for package of the method. **/ - private FullIdent packageFullIdent; - - /** Name of current class. */ - private String currentClassName; - - /** {@code ClassResolver} instance for current tree. */ - private ClassResolver classResolver; - - /** - * Whether to log class loading errors to the checkstyle report - * instead of throwing a RTE. - * - *

    Logging errors will avoid stopping checkstyle completely - * because of a typo in javadoc. However, with modern IDEs that - * support automated refactoring and generate javadoc this will - * occur rarely, so by default we assume a configuration problem - * in the checkstyle classpath and throw an exception. - * - *

    This configuration option was triggered by bug 1422462. - */ - private boolean logLoadErrors = true; - - /** - * Whether to show class loading errors in the checkstyle report. - * Request ID 1491630 - */ - private boolean suppressLoadErrors; - - /** - * Called to process an AST when visiting it. - * @param ast the AST to process. Guaranteed to not be PACKAGE_DEF or - * IMPORT tokens. - */ - protected abstract void processAST(DetailAST ast); - - /** - * Logs error if unable to load class information. - * Abstract, should be overridden in subclasses. - * @param ident class name for which we can no load class. - */ - protected abstract void logLoadError(Token ident); - - /** - * Controls whether to log class loading errors to the checkstyle report - * instead of throwing a RTE. - * - * @param logLoadErrors true if errors should be logged - */ - public final void setLogLoadErrors(boolean logLoadErrors) { - this.logLoadErrors = logLoadErrors; - } - - /** - * Controls whether to show class loading errors in the checkstyle report. - * - * @param suppressLoadErrors true if errors shouldn't be shown - */ - public final void setSuppressLoadErrors(boolean suppressLoadErrors) { - this.suppressLoadErrors = suppressLoadErrors; - } - - @Override - public final int[] getRequiredTokens() { - return new int[] { - TokenTypes.PACKAGE_DEF, - TokenTypes.IMPORT, - TokenTypes.CLASS_DEF, - TokenTypes.INTERFACE_DEF, - TokenTypes.ENUM_DEF, - }; - } - - @Override - public void beginTree(DetailAST rootAST) { - packageFullIdent = FullIdent.createFullIdent(null); - imports.clear(); - // add java.lang.* since it's always imported - imports.add("java.lang.*"); - classResolver = null; - currentClassName = ""; - typeParams.clear(); - } - - @Override - public final void visitToken(DetailAST ast) { - if (ast.getType() == TokenTypes.PACKAGE_DEF) { - processPackage(ast); - } - else if (ast.getType() == TokenTypes.IMPORT) { - processImport(ast); - } - else if (ast.getType() == TokenTypes.CLASS_DEF - || ast.getType() == TokenTypes.INTERFACE_DEF - || ast.getType() == TokenTypes.ENUM_DEF) { - processClass(ast); - } - else { - if (ast.getType() == TokenTypes.METHOD_DEF) { - processTypeParams(ast); - } - processAST(ast); - } - } - - @Override - public final void leaveToken(DetailAST ast) { - if (ast.getType() == TokenTypes.CLASS_DEF - || ast.getType() == TokenTypes.ENUM_DEF) { - // perhaps it was inner class - int dotIdx = currentClassName.lastIndexOf('$'); - if (dotIdx == -1) { - // perhaps just a class - dotIdx = currentClassName.lastIndexOf('.'); - } - if (dotIdx == -1) { - // looks like a topmost class - currentClassName = ""; - } - else { - currentClassName = currentClassName.substring(0, dotIdx); - } - typeParams.pop(); - } - else if (ast.getType() == TokenTypes.METHOD_DEF) { - typeParams.pop(); - } - } - - /** - * Is exception is unchecked (subclass of {@code RuntimeException} - * or {@code Error}. - * - * @param exception {@code Class} of exception to check - * @return true if exception is unchecked - * false if exception is checked - */ - protected static boolean isUnchecked(Class exception) { - return isSubclass(exception, RuntimeException.class) - || isSubclass(exception, Error.class); - } - - /** - * Checks if one class is subclass of another. - * - * @param child {@code Class} of class - * which should be child - * @param parent {@code Class} of class - * which should be parent - * @return true if aChild is subclass of aParent - * false otherwise - */ - protected static boolean isSubclass(Class child, Class parent) { - return parent != null && child != null - && parent.isAssignableFrom(child); - } - - /** - * @return {@code ClassResolver} for current tree. - */ - private ClassResolver getClassResolver() { - if (classResolver == null) { - classResolver = - new ClassResolver(getClassLoader(), - packageFullIdent.getText(), - imports); - } - return classResolver; - } - - /** - * Attempts to resolve the Class for a specified name. - * @param resolvableClassName name of the class to resolve - * @param className name of surrounding class. - * @return the resolved class or {@code null} - * if unable to resolve the class. - */ - protected final Class resolveClass(String resolvableClassName, - String className) { - try { - return getClassResolver().resolve(resolvableClassName, className); - } - catch (final ClassNotFoundException ignored) { - return null; - } - } - - /** - * Tries to load class. Logs error if unable. - * @param ident name of class which we try to load. - * @param className name of surrounding class. - * @return {@code Class} for a ident. - */ - protected final Class tryLoadClass(Token ident, String className) { - final Class clazz = resolveClass(ident.getText(), className); - if (clazz == null) { - logLoadError(ident); - } - return clazz; - } - - /** - * Common implementation for logLoadError() method. - * @param lineNo line number of the problem. - * @param columnNo column number of the problem. - * @param msgKey message key to use. - * @param values values to fill the message out. - */ - protected final void logLoadErrorImpl(int lineNo, int columnNo, - String msgKey, Object... values) { - if (!logLoadErrors) { - final LocalizedMessage msg = new LocalizedMessage(lineNo, - columnNo, - getMessageBundle(), - msgKey, - values, - getSeverityLevel(), - getId(), - getClass(), - null); - throw new IllegalStateException(msg.getMessage()); - } - - if (!suppressLoadErrors) { - log(lineNo, columnNo, msgKey, values); - } - } - - /** - * Collects the details of a package. - * @param ast node containing the package details - */ - private void processPackage(DetailAST ast) { - final DetailAST nameAST = ast.getLastChild().getPreviousSibling(); - packageFullIdent = FullIdent.createFullIdent(nameAST); - } - - /** - * Collects the details of imports. - * @param ast node containing the import details - */ - private void processImport(DetailAST ast) { - final FullIdent name = FullIdent.createFullIdentBelow(ast); - imports.add(name.getText()); - } - - /** - * Process type params (if any) for given class, enum or method. - * @param ast class, enum or method to process. - */ - private void processTypeParams(DetailAST ast) { - final DetailAST params = - ast.findFirstToken(TokenTypes.TYPE_PARAMETERS); - - final Map paramsMap = Maps.newHashMap(); - typeParams.push(paramsMap); - - if (params == null) { - return; - } - - for (DetailAST child = params.getFirstChild(); - child != null; - child = child.getNextSibling()) { - if (child.getType() == TokenTypes.TYPE_PARAMETER) { - final String alias = - child.findFirstToken(TokenTypes.IDENT).getText(); - final DetailAST bounds = - child.findFirstToken(TokenTypes.TYPE_UPPER_BOUNDS); - if (bounds != null) { - final FullIdent name = - FullIdent.createFullIdentBelow(bounds); - final AbstractClassInfo classInfo = - createClassInfo(new Token(name), currentClassName); - paramsMap.put(alias, classInfo); - } - } - } - } - - /** - * Processes class definition. - * @param ast class definition to process. - */ - private void processClass(DetailAST ast) { - final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT); - String innerClass = ident.getText(); - - if (!currentClassName.isEmpty()) { - innerClass = "$" + innerClass; - } - currentClassName += innerClass; - processTypeParams(ast); - } - - /** - * Returns current class. - * @return name of current class. - */ - protected final String getCurrentClassName() { - return currentClassName; - } - - /** - * Creates class info for given name. - * @param name name of type. - * @param surroundingClass name of surrounding class. - * @return class info for given name. - */ - protected final AbstractClassInfo createClassInfo(final Token name, - final String surroundingClass) { - final AbstractClassInfo classInfo = findClassAlias(name.getText()); - if (classInfo != null) { - return new ClassAlias(name, classInfo); - } - return new RegularClass(name, surroundingClass, this); - } - - /** - * Looking if a given name is alias. - * @param name given name - * @return ClassInfo for alias if it exists, null otherwise - */ - protected final AbstractClassInfo findClassAlias(final String name) { - AbstractClassInfo classInfo = null; - final Iterator> iterator = typeParams.descendingIterator(); - while (iterator.hasNext()) { - final Map paramMap = iterator.next(); - classInfo = paramMap.get(name); - if (classInfo != null) { - break; - } - } - return classInfo; - } - - /** - * Contains class's {@code Token}. - */ - protected abstract static class AbstractClassInfo { - /** {@code FullIdent} associated with this class. */ - private final Token name; - - /** - * Creates new instance of class information object. - * @param className token which represents class name. - */ - protected AbstractClassInfo(final Token className) { - if (className == null) { - throw new IllegalArgumentException( - "ClassInfo's name should be non-null"); - } - name = className; - } - - /** - * @return {@code Class} associated with an object. - */ - public abstract Class getClazz(); - - /** - * Gets class name. - * @return class name - */ - public final Token getName() { - return name; - } - } - - /** Represents regular classes/enums. */ - private static final class RegularClass extends AbstractClassInfo { - /** Name of surrounding class. */ - private final String surroundingClass; - /** The check we use to resolve classes. */ - private final AbstractTypeAwareCheck check; - /** Is class loadable. */ - private boolean loadable = true; - /** {@code Class} object of this class if it's loadable. */ - private Class classObj; - - /** - * Creates new instance of of class information object. - * @param name {@code FullIdent} associated with new object. - * @param surroundingClass name of current surrounding class. - * @param check the check we use to load class. - */ - RegularClass(final Token name, - final String surroundingClass, - final AbstractTypeAwareCheck check) { - super(name); - this.surroundingClass = surroundingClass; - this.check = check; - } - - @Override - public Class getClazz() { - if (loadable && classObj == null) { - setClazz(check.tryLoadClass(getName(), surroundingClass)); - } - return classObj; - } - - /** - * Associates {@code Class} with an object. - * @param clazz {@code Class} to associate with. - */ - private void setClazz(Class clazz) { - classObj = clazz; - loadable = clazz != null; - } - - @Override - public String toString() { - return "RegularClass[name=" + getName() - + ", in class=" + surroundingClass - + ", loadable=" + loadable - + ", class=" + classObj + "]"; - } - } - - /** Represents type param which is "alias" for real type. */ - private static class ClassAlias extends AbstractClassInfo { - /** Class information associated with the alias. */ - private final AbstractClassInfo classInfo; - - /** - * Creates new instance of the class. - * @param name token which represents name of class alias. - * @param classInfo class information associated with the alias. - */ - ClassAlias(final Token name, AbstractClassInfo classInfo) { - super(name); - this.classInfo = classInfo; - } - - @Override - public final Class getClazz() { - return classInfo.getClazz(); - } - - @Override - public String toString() { - return "ClassAlias[alias " + getName() + " for " + classInfo.getName() + "]"; - } - } - - /** - * Represents text element with location in the text. - */ - protected static class Token { - /** Token's column number. */ - private final int columnNo; - /** Token's line number. */ - private final int lineNo; - /** Token's text. */ - private final String text; - - /** - * Creates token. - * @param text token's text - * @param lineNo token's line number - * @param columnNo token's column number - */ - public Token(String text, int lineNo, int columnNo) { - this.text = text; - this.lineNo = lineNo; - this.columnNo = columnNo; - } - - /** - * Converts FullIdent to Token. - * @param fullIdent full ident to convert. - */ - public Token(FullIdent fullIdent) { - text = fullIdent.getText(); - lineNo = fullIdent.getLineNo(); - columnNo = fullIdent.getColumnNo(); - } - - /** - * Gets line number of the token. - * @return line number of the token - */ - public int getLineNo() { - return lineNo; - } - - /** - * Gets column number of the token. - * @return column number of the token - */ - public int getColumnNo() { - return columnNo; - } - - /** - * Gets text of the token. - * @return text of the token - */ - public String getText() { - return text; - } - - @Override - public String toString() { - return "Token[" + text + "(" + lineNo - + "x" + columnNo + ")]"; - } - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationLocationCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,17 +19,26 @@ package com.puppycrawl.tools.checkstyle.checks.annotation; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * Check location of annotation on language elements. * By default, Check enforce to locate annotations immediately after * documentation block and before target element, annotation should be located * on separate line from target element. + *

    + * Attention: Annotations among modifiers are ignored (looks like false-negative) + * as there might be a problem with annotations for return types. + *

    + *
    public @Nullable Long getStartTimeOrNull() { ... }
    . + *

    + * Such annotations are better to keep close to type. + * Due to limitations, Checkstyle can not examine the target of an annotation. + *

    * *

    * Example: @@ -42,21 +51,21 @@ *

    * *

    - * Check have following options: + * The check has the following options: *

    *
      *
    • allowSamelineMultipleAnnotations - to allow annotation to be located on - * the same line as target element. Default value is false. + * the same line as the target element. Default value is false. *
    • * *
    • * allowSamelineSingleParameterlessAnnotation - to allow single parameterless - * annotation to be located on the same line as target element. Default value is false. + * annotation to be located on the same line as the target element. Default value is false. *
    • * *
    • * allowSamelineParameterizedAnnotation - to allow parameterized annotation - * to be located on the same line as target element. Default value is false. + * to be located on the same line as the target element. Default value is false. *
    • *
    *
    @@ -67,7 +76,7 @@ * @Override public int hashCode() { ... } *
    * - *

    Use following configuration: + *

    Use the following configuration: *

      * <module name="AnnotationLocation">
      *    <property name="allowSamelineMultipleAnnotations" value="false"/>
    @@ -85,7 +94,7 @@
      * @SuppressWarnings("deprecation") @Mock DataLoader loader;
      * 
    * - *

    Use following configuration: + *

    Use the following configuration: *

      * <module name="AnnotationLocation">
      *    <property name="allowSamelineMultipleAnnotations" value="true"/>
    @@ -103,7 +112,7 @@
      * @Partial @Mock DataLoader loader;
      * 
    * - *

    Use following configuration: + *

    Use the following configuration: *

      * <module name="AnnotationLocation">
      *    <property name="allowSamelineMultipleAnnotations" value="true"/>
    @@ -113,10 +122,46 @@
      *    />
      * </module>
      * 
    + *
    + *

    + * The following example demonstrates how the check validates annotation of method parameters, + * catch parameters, foreach, for-loop variable definitions. + *

    + * + *

    Configuration: + *

    + * <module name="AnnotationLocation">
    + *    <property name="allowSamelineMultipleAnnotations" value="false"/>
    + *    <property name="allowSamelineSingleParameterlessAnnotation"
    + *    value="false"/>
    + *    <property name="allowSamelineParameterizedAnnotation" value="false"
    + *    />
    + *    <property name="tokens" value="VARIABLE_DEF, PARAMETER_DEF"/>
    + * </module>
    + * 
    + * + *

    Code example + * {@code + * ... + * public void test(@MyAnnotation String s) { // OK + * ... + * for (@MyAnnotation char c : s.toCharArray()) { ... } // OK + * ... + * try { ... } + * catch (@MyAnnotation Exception ex) { ... } // OK + * ... + * for (@MyAnnotation int i = 0; i < 10; i++) { ... } // OK + * ... + * MathOperation c = (@MyAnnotation int a, @MyAnnotation int b) -> a + b; // OK + * ... + * } + * } * * @author maxvetrenko */ -public class AnnotationLocationCheck extends Check { +@StatelessCheck +public class AnnotationLocationCheck extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -129,40 +174,50 @@ */ public static final String MSG_KEY_ANNOTATION_LOCATION = "annotation.location"; + /** Array of single line annotation parents. */ + private static final int[] SINGLELINE_ANNOTATION_PARENTS = {TokenTypes.FOR_EACH_CLAUSE, + TokenTypes.PARAMETER_DEF, + TokenTypes.FOR_INIT, }; + /** - * Some javadoc. + * If true, it allows single prameterless annotation to be located on the same line as + * target element. */ private boolean allowSamelineSingleParameterlessAnnotation = true; /** - * Some javadoc. + * If true, it allows parameterized annotation to be located on the same line as + * target element. */ private boolean allowSamelineParameterizedAnnotation; /** - * Some javadoc. + * If true, it allows annotation to be located on the same line as + * target element. */ private boolean allowSamelineMultipleAnnotations; /** - * Some javadoc. - * @param allow Some javadoc. + * Sets if allow same line single parameterless annotation. + * @param allow User's value of allowSamelineSingleParameterlessAnnotation. */ public final void setAllowSamelineSingleParameterlessAnnotation(boolean allow) { allowSamelineSingleParameterlessAnnotation = allow; } /** - * Some javadoc. - * @param allow Some javadoc. + * Sets if allow parameterized annotation to be located on the same line as + * target element. + * @param allow User's value of allowSamelineParameterizedAnnotation. */ public final void setAllowSamelineParameterizedAnnotation(boolean allow) { allowSamelineParameterizedAnnotation = allow; } /** - * Some javadoc. - * @param allow Some javadoc. + * Sets if allow annotation to be located on the same line as + * target element. + * @param allow User's value of allowSamelineMultipleAnnotations. */ public final void setAllowSamelineMultipleAnnotations(boolean allow) { allowSamelineMultipleAnnotations = allow; @@ -203,7 +258,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -211,16 +266,39 @@ final DetailAST modifiersNode = ast.findFirstToken(TokenTypes.MODIFIERS); if (hasAnnotations(modifiersNode)) { - checkAnnotations(modifiersNode, getAnnotationLevel(modifiersNode)); + checkAnnotations(modifiersNode, getExpectedAnnotationIndentation(modifiersNode)); } } /** - * Some javadoc. - * @param modifierNode Some javadoc. - * @param correctLevel Some javadoc. + * Checks whether a given modifier node has an annotation. + * @param modifierNode modifier node. + * @return true if the given modifier node has the annotation. */ - private void checkAnnotations(DetailAST modifierNode, int correctLevel) { + private static boolean hasAnnotations(DetailAST modifierNode) { + return modifierNode != null + && modifierNode.findFirstToken(TokenTypes.ANNOTATION) != null; + } + + /** + * Returns an expected annotation indentation. + * The expected indentation should be the same as the indentation of the node + * which is the parent of the target modifier node. + * @param modifierNode modifier node. + * @return the annotation indentation. + */ + private static int getExpectedAnnotationIndentation(DetailAST modifierNode) { + return modifierNode.getParent().getColumnNo(); + } + + /** + * Checks annotations positions in code: + * 1) Checks whether the annotations locations are correct. + * 2) Checks whether the annotations have the valid indentation level. + * @param modifierNode modifiers node. + * @param correctIndentation correct indentation of the annotation. + */ + private void checkAnnotations(DetailAST modifierNode, int correctIndentation) { DetailAST annotation = modifierNode.getFirstChild(); while (annotation != null && annotation.getType() == TokenTypes.ANNOTATION) { @@ -230,38 +308,27 @@ log(annotation.getLineNo(), MSG_KEY_ANNOTATION_LOCATION_ALONE, getAnnotationName(annotation)); } - else if (annotation.getColumnNo() != correctLevel && !hasNodeBefore(annotation)) { + else if (annotation.getColumnNo() != correctIndentation && !hasNodeBefore(annotation)) { log(annotation.getLineNo(), MSG_KEY_ANNOTATION_LOCATION, - getAnnotationName(annotation), annotation.getColumnNo(), correctLevel); + getAnnotationName(annotation), annotation.getColumnNo(), correctIndentation); } annotation = annotation.getNextSibling(); } } /** - * Some javadoc. - * @param annotation Some javadoc. - * @param hasParams Some javadoc. - * @return Some javadoc. + * Checks whether an annotation has parameters. + * @param annotation annotation node. + * @return true if the annotation has parameters. */ - private boolean isCorrectLocation(DetailAST annotation, boolean hasParams) { - final boolean allowingCondition; - - if (hasParams) { - allowingCondition = allowSamelineParameterizedAnnotation; - } - else { - allowingCondition = allowSamelineSingleParameterlessAnnotation; - } - return allowSamelineMultipleAnnotations - || allowingCondition && !hasNodeBefore(annotation) - || !allowingCondition && !hasNodeBeside(annotation); + private static boolean isParameterized(DetailAST annotation) { + return annotation.findFirstToken(TokenTypes.EXPR) != null; } /** - * Some javadoc. - * @param annotation Some javadoc. - * @return Some javadoc. + * Returns the name of the given annotation. + * @param annotation annotation node. + * @return annotation name. */ private static String getAnnotationName(DetailAST annotation) { DetailAST identNode = annotation.findFirstToken(TokenTypes.IDENT); @@ -272,25 +339,39 @@ } /** - * Some javadoc. - * @param annotation Some javadoc. - * @return Some javadoc. + * Checks whether an annotation has a correct location. + * Annotation location is considered correct + * if {@link AnnotationLocationCheck#allowSamelineMultipleAnnotations} is set to true. + * The method also: + * 1) checks parameterized annotation location considering + * the value of {@link AnnotationLocationCheck#allowSamelineParameterizedAnnotation}; + * 2) checks parameterless annotation location considering + * the value of {@link AnnotationLocationCheck#allowSamelineSingleParameterlessAnnotation}; + * 3) checks annotation location considering the elements + * of {@link AnnotationLocationCheck#SINGLELINE_ANNOTATION_PARENTS}; + * @param annotation annotation node. + * @param hasParams whether an annotation has parameters. + * @return true if the annotation has a correct location. */ - private static boolean hasNodeAfter(DetailAST annotation) { - final int annotationLineNo = annotation.getLineNo(); - DetailAST nextNode = annotation.getNextSibling(); + private boolean isCorrectLocation(DetailAST annotation, boolean hasParams) { + final boolean allowingCondition; - if (nextNode == null) { - nextNode = annotation.getParent().getNextSibling(); + if (hasParams) { + allowingCondition = allowSamelineParameterizedAnnotation; } - - return annotationLineNo == nextNode.getLineNo(); + else { + allowingCondition = allowSamelineSingleParameterlessAnnotation; + } + return allowSamelineMultipleAnnotations + || allowingCondition && !hasNodeBefore(annotation) + || !allowingCondition && (!hasNodeBeside(annotation) + || isAllowedPosition(annotation, SINGLELINE_ANNOTATION_PARENTS)); } /** - * Some javadoc. - * @param annotation Some javadoc. - * @return Some javadoc. + * Checks whether an annotation node has any node before on the same line. + * @param annotation annotation node. + * @return true if an annotation node has any node before on the same line. */ private static boolean hasNodeBefore(DetailAST annotation) { final int annotationLineNo = annotation.getLineNo(); @@ -300,38 +381,63 @@ } /** - * Some javadoc. - * @param annotation Some javadoc. - * @return Some javadoc. + * Checks whether an annotation node has any node before or after on the same line. + * @param annotation annotation node. + * @return true if an annotation node has any node before or after on the same line. */ private static boolean hasNodeBeside(DetailAST annotation) { return hasNodeBefore(annotation) || hasNodeAfter(annotation); } /** - * Some javadoc. - * @param modifierNode Some javadoc. - * @return Some javadoc. + * Checks whether an annotation node has any node after on the same line. + * @param annotation annotation node. + * @return true if an annotation node has any node after on the same line. */ - private static int getAnnotationLevel(DetailAST modifierNode) { - return modifierNode.getParent().getColumnNo(); + private static boolean hasNodeAfter(DetailAST annotation) { + final int annotationLineNo = annotation.getLineNo(); + DetailAST nextNode = annotation.getNextSibling(); + + if (nextNode == null) { + nextNode = annotation.getParent().getNextSibling(); + } + + return annotationLineNo == nextNode.getLineNo(); } /** - * Some javadoc. - * @param annotation Some javadoc. - * @return Some javadoc. - */ - private static boolean isParameterized(DetailAST annotation) { - return annotation.findFirstToken(TokenTypes.EXPR) != null; + * Checks whether position of annotation is allowed. + * @param annotation annotation token. + * @param allowedPositions an array of allowed annotation positions. + * @return true if position of annotation is allowed. + */ + private static boolean isAllowedPosition(DetailAST annotation, int... allowedPositions) { + boolean allowed = false; + for (int position : allowedPositions) { + if (isInSpecificCodeBlock(annotation, position)) { + allowed = true; + break; + } + } + return allowed; } /** - * Some javadoc. - * @param modifierNode Some javadoc. - * @return Some javadoc. - */ - private static boolean hasAnnotations(DetailAST modifierNode) { - return modifierNode.findFirstToken(TokenTypes.ANNOTATION) != null; + * Checks whether the scope of a node is restricted to a specific code block. + * @param node node. + * @param blockType block type. + * @return true if the scope of a node is restricted to a specific code block. + */ + private static boolean isInSpecificCodeBlock(DetailAST node, int blockType) { + boolean returnValue = false; + for (DetailAST token = node.getParent(); token != null; token = token.getParent()) { + final int type = token.getType(); + if (type == blockType) { + returnValue = true; + break; + } + } + return returnValue; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationOnSameLineCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationOnSameLineCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationOnSameLineCheck.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationOnSameLineCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,124 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.annotation; + +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; + +/** + * The check does verifying that annotations are located on the same line with their targets. + * Verifying with this check is not good practice, but it is using by some style guides. + * @author zenigata + */ +public class AnnotationOnSameLineCheck extends AbstractCheck { + + /** A key is pointing to the warning message text in "messages.properties" file. */ + public static final String MSG_KEY_ANNOTATION_ON_SAME_LINE = "annotation.same.line"; + + @Override + public int[] getDefaultTokens() { + return new int[] { + TokenTypes.CLASS_DEF, + TokenTypes.INTERFACE_DEF, + TokenTypes.ENUM_DEF, + TokenTypes.METHOD_DEF, + TokenTypes.CTOR_DEF, + TokenTypes.VARIABLE_DEF, + }; + } + + @Override + public int[] getAcceptableTokens() { + return new int[] { + TokenTypes.CLASS_DEF, + TokenTypes.INTERFACE_DEF, + TokenTypes.ENUM_DEF, + TokenTypes.METHOD_DEF, + TokenTypes.CTOR_DEF, + TokenTypes.VARIABLE_DEF, + TokenTypes.PARAMETER_DEF, + TokenTypes.ANNOTATION_DEF, + TokenTypes.TYPECAST, + TokenTypes.LITERAL_THROWS, + TokenTypes.IMPLEMENTS_CLAUSE, + TokenTypes.TYPE_ARGUMENT, + TokenTypes.LITERAL_NEW, + TokenTypes.DOT, + TokenTypes.ANNOTATION_FIELD_DEF, + }; + } + + @Override + public int[] getRequiredTokens() { + return CommonUtils.EMPTY_INT_ARRAY; + } + + @Override + public void visitToken(DetailAST ast) { + DetailAST nodeWithAnnotations = ast; + if (ast.getType() == TokenTypes.TYPECAST) { + nodeWithAnnotations = ast.findFirstToken(TokenTypes.TYPE); + } + DetailAST modifiersNode = nodeWithAnnotations.findFirstToken(TokenTypes.MODIFIERS); + if (modifiersNode == null) { + modifiersNode = nodeWithAnnotations.findFirstToken(TokenTypes.ANNOTATIONS); + } + if (modifiersNode != null) { + for (DetailAST annotationNode = modifiersNode.getFirstChild(); + annotationNode != null; + annotationNode = annotationNode.getNextSibling()) { + if (annotationNode.getType() == TokenTypes.ANNOTATION + && annotationNode.getLineNo() != getNextNode(annotationNode).getLineNo()) { + log(annotationNode.getLineNo(), MSG_KEY_ANNOTATION_ON_SAME_LINE, + getAnnotationName(annotationNode)); + } + } + } + } + + /** + * Finds next node of ast tree. + * @param node current node + * @return node that is next to given + */ + private static DetailAST getNextNode(DetailAST node) { + DetailAST nextNode = node.getNextSibling(); + if (nextNode == null) { + nextNode = node.getParent().getNextSibling(); + } + return nextNode; + } + + /** + * Returns the name of the given annotation. + * @param annotation annotation node. + * @return annotation name. + */ + private static String getAnnotationName(DetailAST annotation) { + DetailAST identNode = annotation.findFirstToken(TokenTypes.IDENT); + if (identNode == null) { + identNode = annotation.findFirstToken(TokenTypes.DOT).getLastChild(); + } + return identNode.getText(); + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationUseStyleCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationUseStyleCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationUseStyleCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/AnnotationUseStyleCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,7 +23,8 @@ import org.apache.commons.beanutils.ConversionException; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -69,8 +70,8 @@ * array comma preference a {@link TrailingArrayComma#IGNORE IGNORE} type * is provided. Set this through the {@code trailingArrayComma} property. * - *

    By default the ElementStyle is set to EXPANDED, the TrailingArrayComma - * is set to NEVER, and the ClosingParens is set to ALWAYS. + *

    By default the ElementStyle is set to COMPACT_NO_ARRAY, the + * TrailingArrayComma is set to NEVER, and the ClosingParens is set to NEVER. * *

    According to the JLS, it is legal to include a trailing comma * in arrays used in annotations but Sun's Java 5 & 6 compilers will not @@ -81,7 +82,7 @@ * 3.4.1. * *

    See + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.7"> * Java Language specification, §9.7. * *

    An example shown below is set to enforce an EXPANDED style, with a @@ -101,7 +102,8 @@ * * @author Travis Schneeberger */ -public final class AnnotationUseStyleCheck extends Check { +@StatelessCheck +public final class AnnotationUseStyleCheck extends AbstractCheck { /** * Defines the styles for defining elements in an annotation. @@ -136,6 +138,7 @@ * Mixed styles. */ IGNORE, + } /** @@ -164,6 +167,7 @@ * Mixed styles. */ IGNORE, + } /** @@ -192,6 +196,7 @@ * Mixed styles. */ IGNORE, + } /** @@ -236,9 +241,6 @@ private static final String ANNOTATION_ELEMENT_SINGLE_NAME = "value"; - //not extending AbstractOptionCheck because check - //has more than one option type. - /** * ElementStyle option. * @see #setElementStyle(String) @@ -301,7 +303,7 @@ return Enum.valueOf(enumClass, value.trim().toUpperCase(Locale.ENGLISH)); } catch (final IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + value, iae); + throw new IllegalArgumentException("unable to parse " + value, iae); } } @@ -337,7 +339,6 @@ * @param annotation the annotation token */ private void checkStyleType(final DetailAST annotation) { - switch (elementStyle) { case COMPACT_NO_ARRAY: checkCompactNoArrayStyle(annotation); @@ -404,9 +405,6 @@ final int valuePairCount = annotation.getChildCount(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR); - final DetailAST valuePair = - annotation.findFirstToken(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR); - //in compact style with one value if (arrayInit != null && arrayInit.getChildCount(TokenTypes.EXPR) == 1) { @@ -415,6 +413,8 @@ } //in expanded style with one value and the correct element name else if (valuePairCount == 1) { + final DetailAST valuePair = + annotation.findFirstToken(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR); final DetailAST nestedArrayInit = valuePair.findFirstToken(TokenTypes.ANNOTATION_ARRAY_INIT); @@ -435,26 +435,24 @@ * @param annotation the annotation token */ private void checkTrailingComma(final DetailAST annotation) { - if (trailingArrayComma == TrailingArrayComma.IGNORE) { - return; - } - - DetailAST child = annotation.getFirstChild(); + if (trailingArrayComma != TrailingArrayComma.IGNORE) { + DetailAST child = annotation.getFirstChild(); - while (child != null) { - DetailAST arrayInit = null; + while (child != null) { + DetailAST arrayInit = null; - if (child.getType() == TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) { - arrayInit = child.findFirstToken(TokenTypes.ANNOTATION_ARRAY_INIT); + if (child.getType() == TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) { + arrayInit = child.findFirstToken(TokenTypes.ANNOTATION_ARRAY_INIT); + } + else if (child.getType() == TokenTypes.ANNOTATION_ARRAY_INIT) { + arrayInit = child; + } + + if (arrayInit != null) { + logCommaViolation(arrayInit); + } + child = child.getNextSibling(); } - else if (child.getType() == TokenTypes.ANNOTATION_ARRAY_INIT) { - arrayInit = child; - } - - if (arrayInit != null) { - logCommaViolation(arrayInit); - } - child = child.getNextSibling(); } } @@ -489,23 +487,22 @@ * @param ast the annotation token */ private void checkCheckClosingParens(final DetailAST ast) { - if (closingParens == ClosingParens.IGNORE) { - return; - } - - final DetailAST paren = ast.getLastChild(); - final boolean parenExists = paren.getType() == TokenTypes.RPAREN; - - if (closingParens == ClosingParens.ALWAYS - && !parenExists) { - log(ast.getLineNo(), MSG_KEY_ANNOTATION_PARENS_MISSING); - } - else if (closingParens == ClosingParens.NEVER - && parenExists - && !ast.branchContains(TokenTypes.EXPR) - && !ast.branchContains(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) - && !ast.branchContains(TokenTypes.ANNOTATION_ARRAY_INIT)) { - log(ast.getLineNo(), MSG_KEY_ANNOTATION_PARENS_PRESENT); + if (closingParens != ClosingParens.IGNORE) { + final DetailAST paren = ast.getLastChild(); + final boolean parenExists = paren.getType() == TokenTypes.RPAREN; + + if (closingParens == ClosingParens.ALWAYS + && !parenExists) { + log(ast.getLineNo(), MSG_KEY_ANNOTATION_PARENS_MISSING); + } + else if (closingParens == ClosingParens.NEVER + && parenExists + && !ast.branchContains(TokenTypes.EXPR) + && !ast.branchContains(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) + && !ast.branchContains(TokenTypes.ANNOTATION_ARRAY_INIT)) { + log(ast.getLineNo(), MSG_KEY_ANNOTATION_PARENS_PRESENT); + } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/MissingDeprecatedCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/MissingDeprecatedCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/MissingDeprecatedCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/MissingDeprecatedCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TextBlock; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -70,9 +71,35 @@ * <module name="JavadocDeprecated"/> *

    * + *

    + * In addition you can configure this check with skipNoJavadoc + * option to allow it to ignore cases when JavaDoc is missing, + * but still warns when JavaDoc is present but either + * {@link Deprecated Deprecated} is missing from JavaDoc or + * {@link Deprecated Deprecated} is missing from the element. + * To configure this check to allow it use: + *

    + * + *
       <property name="skipNoJavadoc" value="true" />
    + * + *

    Examples of validating source code with skipNoJavadoc:

    + * + *
    + * 
    + * {@literal @}deprecated
    + * public static final int MY_CONST = 123456; // no violation
    + *
    + * /** This javadoc is missing deprecated tag. */
    + * {@literal @}deprecated
    + * public static final int COUNTER = 10; // violation as javadoc exists
    + * 
    + * 
    + * * @author Travis Schneeberger */ -public final class MissingDeprecatedCheck extends Check { +@StatelessCheck +public final class MissingDeprecatedCheck extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -116,13 +143,29 @@ /** Multiline finished at next Javadoc. */ private static final String NEXT_TAG = "@"; + /** Is deprecated element valid without javadoc. */ + private boolean skipNoJavadoc; + + /** + * Set skipJavadoc value. + * @param skipNoJavadoc user's value of skipJavadoc + */ + public void setSkipNoJavadoc(boolean skipNoJavadoc) { + this.skipNoJavadoc = skipNoJavadoc; + } + @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { return new int[] { TokenTypes.INTERFACE_DEF, TokenTypes.CLASS_DEF, @@ -137,11 +180,6 @@ } @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); - } - - @Override public void visitToken(final DetailAST ast) { final TextBlock javadoc = getFileContents().getJavadocBefore(ast.getLineNo()); @@ -152,7 +190,7 @@ final boolean containsJavadocTag = containsJavadocTag(javadoc); - if (containsAnnotation ^ containsJavadocTag) { + if (containsAnnotation ^ containsJavadocTag && !(skipNoJavadoc && javadoc == null)) { log(ast.getLineNo(), MSG_KEY_ANNOTATION_MISSING_DEPRECATED); } } @@ -164,33 +202,28 @@ * @return true if contains the tag */ private boolean containsJavadocTag(final TextBlock javadoc) { - if (javadoc == null) { - return false; - } - - final String[] lines = javadoc.getText(); - boolean found = false; + if (javadoc != null) { + final String[] lines = javadoc.getText(); + int currentLine = javadoc.getStartLineNo() - 1; + + for (int i = 0; i < lines.length; i++) { + currentLine++; + final String line = lines[i]; - int currentLine = javadoc.getStartLineNo() - 1; + final Matcher javadocNoArgMatcher = MATCH_DEPRECATED.matcher(line); + final Matcher noArgMultilineStart = MATCH_DEPRECATED_MULTILINE_START.matcher(line); - for (int i = 0; i < lines.length; i++) { - currentLine++; - final String line = lines[i]; - - final Matcher javadocNoArgMatcher = - MATCH_DEPRECATED.matcher(line); - final Matcher noArgMultilineStart = MATCH_DEPRECATED_MULTILINE_START.matcher(line); - - if (javadocNoArgMatcher.find()) { - if (found) { - log(currentLine, MSG_KEY_JAVADOC_DUPLICATE_TAG, - JavadocTagInfo.DEPRECATED.getText()); + if (javadocNoArgMatcher.find()) { + if (found) { + log(currentLine, MSG_KEY_JAVADOC_DUPLICATE_TAG, + JavadocTagInfo.DEPRECATED.getText()); + } + found = true; + } + else if (noArgMultilineStart.find()) { + found = checkTagAtTheRestOfComment(lines, found, currentLine, i); } - found = true; - } - else if (noArgMultilineStart.find()) { - found = checkTagAtTheRestOfComment(lines, found, currentLine, i); } } return found; @@ -209,10 +242,9 @@ */ private boolean checkTagAtTheRestOfComment(String[] lines, boolean foundBefore, int currentLine, int index) { - boolean found = false; - for (int reindex = index + 1; - reindex < lines.length;) { + int reindex = index + 1; + while (reindex <= lines.length - 1) { final Matcher multilineCont = MATCH_DEPRECATED_MULTILINE_CONT.matcher(lines[reindex]); if (multilineCont.find()) { @@ -238,4 +270,5 @@ } return found; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/MissingOverrideCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/MissingOverrideCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/MissingOverrideCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/MissingOverrideCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TextBlock; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -75,7 +76,9 @@ * * @author Travis Schneeberger */ -public final class MissingOverrideCheck extends Check { +@StatelessCheck +public final class MissingOverrideCheck extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -141,6 +144,7 @@ {TokenTypes.METHOD_DEF, }; } + // -@cs[CyclomaticComplexity] Too complex to break apart. @Override public void visitToken(final DetailAST ast) { final TextBlock javadoc = @@ -150,23 +154,26 @@ if (containsTag && !JavadocTagInfo.INHERIT_DOC.isValidOn(ast)) { log(ast.getLineNo(), MSG_KEY_TAG_NOT_VALID_ON, JavadocTagInfo.INHERIT_DOC.getText()); - return; } + else { + boolean check = true; - if (javaFiveCompatibility) { - final DetailAST defOrNew = ast.getParent().getParent(); + if (javaFiveCompatibility) { + final DetailAST defOrNew = ast.getParent().getParent(); - if (defOrNew.branchContains(TokenTypes.EXTENDS_CLAUSE) - || defOrNew.branchContains(TokenTypes.IMPLEMENTS_CLAUSE) - || defOrNew.getType() == TokenTypes.LITERAL_NEW) { - return; + if (defOrNew.findFirstToken(TokenTypes.EXTENDS_CLAUSE) != null + || defOrNew.findFirstToken(TokenTypes.IMPLEMENTS_CLAUSE) != null + || defOrNew.getType() == TokenTypes.LITERAL_NEW) { + check = false; + } } - } - if (containsTag - && !AnnotationUtility.containsAnnotation(ast, OVERRIDE) - && !AnnotationUtility.containsAnnotation(ast, FQ_OVERRIDE)) { - log(ast.getLineNo(), MSG_KEY_ANNOTATION_MISSING_OVERRIDE); + if (check + && containsTag + && !AnnotationUtility.containsAnnotation(ast, OVERRIDE) + && !AnnotationUtility.containsAnnotation(ast, FQ_OVERRIDE)) { + log(ast.getLineNo(), MSG_KEY_ANNOTATION_MISSING_OVERRIDE); + } } } @@ -194,4 +201,5 @@ } return javadocTag; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/PackageAnnotationCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/PackageAnnotationCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/PackageAnnotationCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/PackageAnnotationCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.annotation; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.AnnotationUtility; @@ -39,12 +40,13 @@ * placed in the package-info.java file. * * See + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-7.html#jls-7.4.1"> * Java Language Specification, section 7.4.1. *

    * @author Travis Schneeberger */ -public class PackageAnnotationCheck extends Check { +@StatelessCheck +public class PackageAnnotationCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -80,4 +82,5 @@ log(ast.getLine(), MSG_KEY); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/SuppressWarningsCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/SuppressWarningsCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/SuppressWarningsCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/annotation/SuppressWarningsCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,9 +22,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.AnnotationUtility; @@ -49,7 +48,7 @@ * By default, any warning specified will be disallowed on * all legal TokenTypes unless otherwise specified via * the - * {@link Check#setTokens(String[]) tokens} + * {@link AbstractCheck#setTokens(String[]) tokens} * property. * * Also, by default warnings that are empty strings or all @@ -91,7 +90,9 @@ *
    * @author Travis Schneeberger */ -public class SuppressWarningsCheck extends Check { +@StatelessCheck +public class SuppressWarningsCheck extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -109,20 +110,15 @@ private static final String FQ_SUPPRESS_WARNINGS = "java.lang." + SUPPRESS_WARNINGS; - /** The format string of the regexp. */ - private String format = "^$|^\\s+$"; - /** The regexp to match against. */ - private Pattern regexp = Pattern.compile(format); + private Pattern format = Pattern.compile("^$|^\\s+$"); /** - * Set the format to the specified regular expression. - * @param format a {@code String} value - * @throws org.apache.commons.beanutils.ConversionException unable to parse format + * Set the format for the specified regular expression. + * @param pattern the new pattern */ - public final void setFormat(String format) { - this.format = format; - regexp = CommonUtils.createPattern(format); + public final void setFormat(Pattern pattern) { + format = pattern; } @Override @@ -148,69 +144,70 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override public void visitToken(final DetailAST ast) { final DetailAST annotation = getSuppressWarnings(ast); - if (annotation == null) { - return; - } - - final DetailAST warningHolder = - findWarningsHolder(annotation); + if (annotation != null) { + final DetailAST warningHolder = + findWarningsHolder(annotation); + + final DetailAST token = + warningHolder.findFirstToken(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR); + DetailAST warning; - final DetailAST token = - warningHolder.findFirstToken(TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR); - DetailAST warning; - - if (token == null) { - warning = warningHolder.findFirstToken(TokenTypes.EXPR); - } - else { - // case like '@SuppressWarnings(value = UNUSED)' - warning = token.findFirstToken(TokenTypes.EXPR); - } - - //rare case with empty array ex: @SuppressWarnings({}) - if (warning == null) { - //check to see if empty warnings are forbidden -- are by default - logMatch(warningHolder.getLineNo(), - warningHolder.getColumnNo(), ""); - return; - } + if (token == null) { + warning = warningHolder.findFirstToken(TokenTypes.EXPR); + } + else { + // case like '@SuppressWarnings(value = UNUSED)' + warning = token.findFirstToken(TokenTypes.EXPR); + } - while (warning != null) { - if (warning.getType() == TokenTypes.EXPR) { - final DetailAST fChild = warning.getFirstChild(); - switch (fChild.getType()) { - //typical case - case TokenTypes.STRING_LITERAL: - final String warningText = - removeQuotes(warning.getFirstChild().getText()); - logMatch(warning.getLineNo(), - warning.getColumnNo(), warningText); - break; - // conditional case - // ex: @SuppressWarnings((false) ? (true) ? "unchecked" : "foo" : "unused") - case TokenTypes.QUESTION: - walkConditional(fChild); - break; - // param in constant case - // ex: public static final String UNCHECKED = "unchecked"; - // @SuppressWarnings(UNCHECKED) or @SuppressWarnings(SomeClass.UNCHECKED) - case TokenTypes.IDENT: - case TokenTypes.DOT: - break; - default: - // Known limitation: cases like @SuppressWarnings("un" + "used") or - // @SuppressWarnings((String) "unused") are not properly supported, - // but they should not cause exceptions. + //rare case with empty array ex: @SuppressWarnings({}) + if (warning == null) { + //check to see if empty warnings are forbidden -- are by default + logMatch(warningHolder.getLineNo(), + warningHolder.getColumnNo(), ""); + } + else { + while (warning != null) { + if (warning.getType() == TokenTypes.EXPR) { + final DetailAST fChild = warning.getFirstChild(); + switch (fChild.getType()) { + //typical case + case TokenTypes.STRING_LITERAL: + final String warningText = + removeQuotes(warning.getFirstChild().getText()); + logMatch(warning.getLineNo(), + warning.getColumnNo(), warningText); + break; + // conditional case + // ex: + // @SuppressWarnings((false) ? (true) ? "unchecked" : "foo" : "unused") + case TokenTypes.QUESTION: + walkConditional(fChild); + break; + // param in constant case + // ex: public static final String UNCHECKED = "unchecked"; + // @SuppressWarnings(UNCHECKED) + // or + // @SuppressWarnings(SomeClass.UNCHECKED) + case TokenTypes.IDENT: + case TokenTypes.DOT: + break; + default: + // Known limitation: cases like @SuppressWarnings("un" + "used") or + // @SuppressWarnings((String) "unused") are not properly supported, + // but they should not cause exceptions. + } + } + warning = warning.getNextSibling(); } } - warning = warning.getNextSibling(); } } @@ -223,15 +220,12 @@ * @return the {@link SuppressWarnings SuppressWarnings} annotation */ private static DetailAST getSuppressWarnings(DetailAST ast) { - final DetailAST annotation = AnnotationUtility.getAnnotation( - ast, SUPPRESS_WARNINGS); + DetailAST annotation = AnnotationUtility.getAnnotation(ast, SUPPRESS_WARNINGS); if (annotation == null) { - return AnnotationUtility.getAnnotation(ast, FQ_SUPPRESS_WARNINGS); - } - else { - return annotation; + annotation = AnnotationUtility.getAnnotation(ast, FQ_SUPPRESS_WARNINGS); } + return annotation; } /** @@ -244,7 +238,7 @@ */ private void logMatch(final int lineNo, final int colNum, final String warningText) { - final Matcher matcher = regexp.matcher(warningText); + final Matcher matcher = format.matcher(warningText); if (matcher.matches()) { log(lineNo, colNum, MSG_KEY_SUPPRESSED_WARNING_NOT_ALLOWED, warningText); @@ -271,11 +265,12 @@ annValuePair.findFirstToken(TokenTypes.ANNOTATION_ARRAY_INIT); } + DetailAST warningsHolder = annotation; if (annArrayInit != null) { - return annArrayInit; + warningsHolder = annArrayInit; } - return annotation; + return warningsHolder; } /** @@ -303,15 +298,15 @@ * {@link TokenTypes#QUESTION QUESTION} */ private void walkConditional(final DetailAST cond) { - if (cond.getType() != TokenTypes.QUESTION) { + if (cond.getType() == TokenTypes.QUESTION) { + walkConditional(getCondLeft(cond)); + walkConditional(getCondRight(cond)); + } + else { final String warningText = - removeQuotes(cond.getText()); + removeQuotes(cond.getText()); logMatch(cond.getLineNo(), cond.getColumnNo(), warningText); - return; } - - walkConditional(getCondLeft(cond)); - walkConditional(getCondRight(cond)); } /** @@ -339,4 +334,5 @@ final DetailAST colon = cond.findFirstToken(TokenTypes.COLON); return colon.getNextSibling(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/ArrayTypeStyleCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/ArrayTypeStyleCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/ArrayTypeStyleCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/ArrayTypeStyleCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -31,7 +32,9 @@ *

    By default the Check enforces Java style. * @author lkuehne */ -public class ArrayTypeStyleCheck extends Check { +@StatelessCheck +public class ArrayTypeStyleCheck extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -43,40 +46,35 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.ARRAY_DECLARATOR}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.ARRAY_DECLARATOR}; } @Override public void visitToken(DetailAST ast) { final DetailAST typeAST = ast.getParent(); - if (typeAST.getType() != TokenTypes.TYPE) { - return; - } - final DetailAST parentAst = typeAST.getParent(); - if (parentAst.getType() == TokenTypes.METHOD_DEF) { - // Do not check method's return type. - // We have no alternatives here. - return; - } - - final DetailAST variableAST = typeAST.getNextSibling(); - if (variableAST != null) { - final boolean isJavaStyle = - variableAST.getLineNo() > ast.getLineNo() - || variableAST.getColumnNo() > ast.getColumnNo(); - - if (isJavaStyle != javaStyle) { - log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY); + if (typeAST.getType() == TokenTypes.TYPE + // Do not check method's return type. + // We have no alternatives here. + && typeAST.getParent().getType() != TokenTypes.METHOD_DEF) { + final DetailAST variableAST = typeAST.getNextSibling(); + if (variableAST != null) { + final boolean isJavaStyle = + variableAST.getLineNo() > ast.getLineNo() + || variableAST.getColumnNo() - ast.getColumnNo() > -1; + + if (isJavaStyle != javaStyle) { + log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY); + } } } } @@ -88,4 +86,5 @@ public void setJavaStyle(boolean javaStyle) { this.javaStyle = javaStyle; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/AvoidEscapedUnicodeCharactersCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/AvoidEscapedUnicodeCharactersCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/AvoidEscapedUnicodeCharactersCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/AvoidEscapedUnicodeCharactersCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,18 +19,23 @@ package com.puppycrawl.tools.checkstyle.checks; +import java.util.List; +import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.TextBlock; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    * Restrict using - * Unicode escapes (e.g. \u221e). + * "https://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.3"> + * Unicode escapes (such as \u221e). * It is possible to allow using escapes for * * non-printable(control) characters. @@ -42,8 +47,8 @@ *

    * Examples of using Unicode:

    *
    - * String unitAbbrev = "μs"; //Best: perfectly clear even without a comment.
    - * String unitAbbrev = "\u03bcs"; //Poor: the reader has no idea what this is.
    + * String unitAbbrev = "μs";      // Best: perfectly clear even without a comment.
    + * String unitAbbrev = "\u03bcs"; // Poor: the reader has no idea what this is.
      * 
    *

    * An example of how to configure the check is: @@ -55,7 +60,7 @@ * An example of non-printable(control) characters. *

    *
    - * return '\ufeff' + content; // byte order mark
    + * return '\ufeff' + content; // byte order mark
      * 
    *

    * An example of how to configure the check to allow using escapes @@ -70,7 +75,7 @@ * Example of using escapes with trail comment: *

    *
    - * String unitAbbrev = "\u03bcs"; // Greek letter mu, "s"
    + * String unitAbbrev = "\u03bcs"; // Greek letter mu, "s"
      * 
    *

    An example of how to configure the check to allow using escapes * if trail comment is present: @@ -83,7 +88,7 @@ *

    Example of using escapes if literal contains only them: *

    *
    - * String unitAbbrev = "\u03bc\u03bc\u03bc";
    + * String unitAbbrev = "\u03bc\u03bc\u03bc";
      * 
    *

    An example of how to configure the check to allow escapes * if literal contains only them: @@ -102,10 +107,12 @@ *

    * * @author maxvetrenko - * + * @noinspection HtmlTagCanBeJavadocTag */ +@FileStatefulCheck public class AvoidEscapedUnicodeCharactersCheck - extends Check { + extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -115,42 +122,51 @@ /** Regular expression for Unicode chars. */ private static final Pattern UNICODE_REGEXP = Pattern.compile("\\\\u[a-fA-F0-9]{4}"); - /** Regular expression Unicode control characters. */ - private static final Pattern UNICODE_CONTROL = Pattern.compile("\\\\(u|U)" - + "(00[0-1][0-1A-Fa-f]|00[8-9][0-9A-Fa-f]|034(f|F)|070(f|F)" - + "|180(e|E)|200[b-fB-F]|202[b-eB-E]|206[0-4a-fA-F]" + /** + * Regular expression Unicode control characters. + * + * @see + * Appendix:Control characters + */ + private static final Pattern UNICODE_CONTROL = Pattern.compile("\\\\[uU]" + + "(00[0-1][0-9A-Fa-f]|00[8-9][0-9A-Fa-f]|00[aA][dD]|034[fF]|070[fF]" + + "|180[eE]|200[b-fB-F]|202[a-eA-E]|206[0-4a-fA-F]" + "|[fF]{3}[9a-bA-B]|[fF][eE][fF]{2})"); - /** Regular expression for trail comment. */ - private static final Pattern COMMENT_REGEXP = Pattern.compile(";[ ]*//+" - + "[a-zA-Z0-9 ]*|;[ ]*/[*]+[a-zA-Z0-9 ]*"); - /** Regular expression for all escaped chars. */ private static final Pattern ALL_ESCAPED_CHARS = Pattern.compile("^((\\\\u)[a-fA-F0-9]{4}" - + "||\\\\b|\\\\t|\\\\n|\\\\f|\\\\r|\\\\|\"|\')+$"); + + "|\\\\b|\\\\t|\\\\n|\\\\f|\\\\r|\\\\|\"|\')+$"); + + /** Regular expression for escaped backslash. */ + private static final Pattern ESCAPED_BACKSLASH = Pattern.compile("\\\\\\\\"); /** Regular expression for non-printable unicode chars. */ private static final Pattern NON_PRINTABLE_CHARS = Pattern.compile("\\\\u1680|\\\\u2028" - + "|\\\\u2029|\\\\u205(f|F)|\\\\u3000|\\\\u2007|\\\\u2000|\\\\u200(a|A)" - + "|\\\\u007(F|f)|\\\\u009(f|F)|\\\\u(f|F){4}|\\\\u007(F|f)|\\\\u00(a|A)(d|D)" - + "|\\\\u0600|\\\\u061(c|C)|\\\\u06(d|D){2}|\\\\u070(f|F)|\\\\u1680|\\\\u180(e|E)" - + "|\\\\u2000|\\\\u2028|\\\\u205(f|F)|\\\\u2066|\\\\u2067|\\\\u2068|\\\\u2069" - + "|\\\\u206(a|A)|\\\\u(d|D)800|\\\\u(f|F)(e|E)(f|F){2}|\\\\u(f|F){3}9" - + "|\\\\u(f|F){3}(a|A)|\\\\u0020|\\\\u00(a|A)0|\\\\u00(a|A)(d|D)|\\\\u0604" - + "|\\\\u061(c|C)|\\\\u06(d|D){2}|\\\\u070(f|F)|\\\\u1680|\\\\u180(e|E)|\\\\u200(f|F)" - + "|\\\\u202(f|F)|\\\\u2064|\\\\u2066|\\\\u2067|\\\\u2068|\\\\u2069|\\\\u206(f|F)" - + "|\\\\u(f|F)8(f|F){2}|\\\\u(f|F)(e|E)(f|F){2}|\\\\u(f|F){3}9|\\\\u(f|F){3}(b|B)" - + "|\\\\u05(d|D)0|\\\\u05(f|F)3|\\\\u0600|\\\\u0750|\\\\u0(e|E)00|\\\\u1(e|E)00" - + "|\\\\u2100|\\\\u(f|F)(b|B)50|\\\\u(f|F)(e|E)70|\\\\u(F|f){2}61|\\\\u04(f|F)9" - + "|\\\\u05(b|B)(e|E)|\\\\u05(e|E)(a|A)|\\\\u05(f|F)4|\\\\u06(f|F){2}" - + "|\\\\u077(f|F)|\\\\u0(e|E)7(f|F)|\\\\u20(a|A)(f|F)|\\\\u213(a|A)|\\\\u0000" - + "|\\\\u(f|F)(d|D)(f|F){2}|\\\\u(f|F)(e|E)(f|F){2}|\\\\u(f|F){2}(d|D)(c|C)" - + "|\\\\u2002|\\\\u0085|\\\\u200(a|A)|\\\\u2005|\\\\u2000|\\\\u2029|\\\\u000(B|b)" - + "|\\\\u2008|\\\\u2003|\\\\u205(f|F)|\\\\u1680|\\\\u0009|\\\\u0020|\\\\u2006" - + "|\\\\u2001|\\\\u202(f|F)|\\\\u00(a|A)0|\\\\u000(c|C)|\\\\u2009|\\\\u2004|\\\\u2028" - + "|\\\\u2028|\\\\u2007|\\\\u2004|\\\\u2028|\\\\u2007|\\\\u2025" - + "|\\\\u(f|F){2}0(e|E)|\\\\u(f|F){2}61"); + + "|\\\\u2029|\\\\u205[fF]|\\\\u3000|\\\\u2007|\\\\u2000|\\\\u200[aA]" + + "|\\\\u007[fF]|\\\\u009[fF]|\\\\u[fF]{4}|\\\\u00[aA][dD]" + + "|\\\\u0600|\\\\u061[cC]|\\\\u06[dD]{2}|\\\\u070[fF]|\\\\u180[eE]" + + "|\\\\u2066|\\\\u2067|\\\\u2068|\\\\u2069" + + "|\\\\u206[aA]|\\\\u[dD]800|\\\\u[fF][eE][fF]{2}|\\\\u[fF]{3}9" + + "|\\\\u[fF]{3}[aA]|\\\\u0020|\\\\u00[aA]0|\\\\u0604" + + "|\\\\u200[fF]" + + "|\\\\u202[fF]|\\\\u2064|\\\\u206[fF]" + + "|\\\\u[fF]8[fF]{2}|\\\\u[fF]{3}[bB]" + + "|\\\\u05[dD]0|\\\\u05[fF]3|\\\\u0750|\\\\u0[eE]00|\\\\u1[eE]00" + + "|\\\\u2100|\\\\u[fF][bB]50|\\\\u[fF][eE]70|\\\\u[fF]{2}61|\\\\u04[fF]9" + + "|\\\\u05[bB][eE]|\\\\u05[eE][aA]|\\\\u05[fF]4|\\\\u06[fF]{2}" + + "|\\\\u077[fF]|\\\\u0[eE]7[fF]|\\\\u20[aA][fF]|\\\\u213[aA]|\\\\u0000" + + "|\\\\u[fF][dD][fF]{2}|\\\\u[fF]{2}[dD][cC]" + + "|\\\\u2002|\\\\u0085|\\\\u2005|\\\\u000[bB]" + + "|\\\\u2008|\\\\u2003|\\\\u0009|\\\\u2006" + + "|\\\\u2001|\\\\u000[cC]|\\\\u2009|\\\\u2004" + + "|\\\\u2025" + + "|\\\\u[fF]{2}0[eE]"); + + /** Cpp style comments. */ + private Map singlelineComments; + /** C style comments. */ + private Map> blockComments; /** Allow use escapes for non-printable(control) characters. */ private boolean allowEscapesForControlCharacters; @@ -198,22 +214,27 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.STRING_LITERAL, TokenTypes.CHAR_LITERAL}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.STRING_LITERAL, TokenTypes.CHAR_LITERAL}; } @Override - public void visitToken(DetailAST ast) { + public void beginTree(DetailAST rootAST) { + singlelineComments = getFileContents().getSingleLineComments(); + blockComments = getFileContents().getBlockComments(); + } + @Override + public void visitToken(DetailAST ast) { final String literal = ast.getText(); if (hasUnicodeChar(literal) && !(allowByTailComment && hasTrailComment(ast) @@ -232,7 +253,9 @@ * @return true if literal has Unicode chars. */ private static boolean hasUnicodeChar(String literal) { - return UNICODE_REGEXP.matcher(literal).find(); + final String literalWithoutEscapedBackslashes = + ESCAPED_BACKSLASH.matcher(literal).replaceAll(""); + return UNICODE_REGEXP.matcher(literalWithoutEscapedBackslashes).find(); } /** @@ -255,34 +278,34 @@ * @return true if trail comment is present after ast token. */ private boolean hasTrailComment(DetailAST ast) { - final DetailAST variableDef = getVariableDef(ast); - DetailAST semi; - - if (variableDef == null) { - semi = getSemi(ast); + boolean result = false; + final int lineNo = ast.getLineNo(); + if (singlelineComments.containsKey(lineNo)) { + result = true; } else { - semi = variableDef.getNextSibling(); - - if (semi.getType() != TokenTypes.SEMI) { - semi = variableDef.getLastChild(); - } - } - - boolean result = false; - if (semi != null) { - final int lineNo = semi.getLineNo(); - final String currentLine = getLine(lineNo - 1); - - if (COMMENT_REGEXP.matcher(currentLine).find()) { - result = true; + final List commentList = blockComments.get(lineNo); + if (commentList != null) { + final TextBlock comment = commentList.get(commentList.size() - 1); + final String line = getLines()[lineNo - 1]; + result = isTrailingBlockComment(comment, line); } } - return result; } /** + * Whether the C style comment is trailing. + * @param comment the comment to check. + * @param line the line where the comment starts. + * @return true if the comment is trailing. + */ + private static boolean isTrailingBlockComment(TextBlock comment, String line) { + return comment.getText().length != 1 + || CommonUtils.isBlank(line.substring(comment.getEndColNo() + 1)); + } + + /** * Count regexp matches into String literal. * @param pattern pattern. * @param target String literal. @@ -298,37 +321,6 @@ } /** - * Get variable definition. - * @param ast current token. - * @return variable definition. - */ - private static DetailAST getVariableDef(DetailAST ast) { - DetailAST result = ast.getParent(); - while (result != null - && result.getType() != TokenTypes.VARIABLE_DEF) { - result = result.getParent(); - } - return result; - } - - /** - * Get semi token. - * @param ast current token. - * @return semi token or null. - */ - private static DetailAST getSemi(DetailAST ast) { - DetailAST result = ast.getParent(); - while (result != null - && result.getLastChild().getType() != TokenTypes.SEMI) { - result = result.getParent(); - } - if (result != null) { - result = result.getLastChild(); - } - return result; - } - - /** * Checks if all characters in String literal is escaped. * @param literal current literal. * @return true if all characters in String literal is escaped. @@ -338,4 +330,5 @@ && ALL_ESCAPED_CHARS.matcher(literal.substring(1, literal.length() - 1)).find(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/AvoidNestedBlocksCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/AvoidNestedBlocksCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/AvoidNestedBlocksCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/AvoidNestedBlocksCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.blocks; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -84,7 +85,9 @@ * * @author lkuehne */ -public class AvoidNestedBlocksCheck extends Check { +@StatelessCheck +public class AvoidNestedBlocksCheck extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -99,28 +102,26 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.SLIST}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.SLIST}; } @Override public void visitToken(DetailAST ast) { final DetailAST parent = ast.getParent(); - if (parent.getType() == TokenTypes.SLIST) { - if (allowInSwitchCase - && parent.getParent().getType() == TokenTypes.CASE_GROUP - && parent.getNumberOfChildren() == 1) { - return; - } + if (parent.getType() == TokenTypes.SLIST + && (!allowInSwitchCase + || parent.getParent().getType() != TokenTypes.CASE_GROUP + || parent.getNumberOfChildren() != 1)) { log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY_BLOCK_NESTED); } } @@ -133,4 +134,5 @@ public void setAllowInSwitchCase(boolean allowInSwitchCase) { this.allowInSwitchCase = allowInSwitchCase; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/BlockOption.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/BlockOption.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/BlockOption.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/BlockOption.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,7 @@ * @see EmptyBlockCheck */ public enum BlockOption { + /** * Represents the policy that there is some text in the block. For example: * @@ -46,5 +47,6 @@ * } *
    */ - STMT + STATEMENT + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyBlockCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyBlockCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyBlockCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyBlockCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,17 +21,16 @@ import java.util.Locale; -import org.apache.commons.beanutils.ConversionException; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** - * Checks for empty blocks. The policy to verify is specified using the {@link - * BlockOption} class and defaults to {@link BlockOption#STMT}. + * Checks for empty blocks. This check does not validate sequential blocks. + * The policy to verify is specified using the {@link + * BlockOption} class and defaults to {@link BlockOption#STATEMENT}. * *

    By default the check will check the following blocks: * {@link TokenTypes#LITERAL_WHILE LITERAL_WHILE}, @@ -65,13 +64,15 @@ * * @author Lars Kühne */ +@StatelessCheck public class EmptyBlockCheck - extends Check { + extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. */ - public static final String MSG_KEY_BLOCK_NO_STMT = "block.noStmt"; + public static final String MSG_KEY_BLOCK_NO_STATEMENT = "block.noStatement"; /** * A key is pointing to the warning message text in "messages.properties" @@ -80,19 +81,19 @@ public static final String MSG_KEY_BLOCK_EMPTY = "block.empty"; /** The policy to enforce. */ - private BlockOption option = BlockOption.STMT; + private BlockOption option = BlockOption.STATEMENT; /** * Set the option to enforce. * @param optionStr string to decode option from - * @throws ConversionException if unable to decode + * @throws IllegalArgumentException if unable to decode */ public void setOption(String optionStr) { try { option = BlockOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + optionStr, iae); + throw new IllegalArgumentException("unable to parse " + optionStr, iae); } } @@ -136,23 +137,14 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override public void visitToken(DetailAST ast) { - final DetailAST slistToken = ast.findFirstToken(TokenTypes.SLIST); - final DetailAST leftCurly; - - if (slistToken == null) { - leftCurly = ast.findFirstToken(TokenTypes.LCURLY); - } - else { - leftCurly = slistToken; - } - + final DetailAST leftCurly = findLeftCurly(ast); if (leftCurly != null) { - if (option == BlockOption.STMT) { + if (option == BlockOption.STATEMENT) { final boolean emptyBlock; if (leftCurly.getType() == TokenTypes.LCURLY) { emptyBlock = leftCurly.getNextSibling().getType() != TokenTypes.CASE_GROUP; @@ -163,7 +155,7 @@ if (emptyBlock) { log(leftCurly.getLineNo(), leftCurly.getColumnNo(), - MSG_KEY_BLOCK_NO_STMT, + MSG_KEY_BLOCK_NO_STATEMENT, ast.getText()); } } @@ -177,10 +169,11 @@ } /** + * Checks if SLIST token contains any text. * @param slistAST a {@code DetailAST} value * @return whether the SLIST token contains any text. */ - protected boolean hasText(final DetailAST slistAST) { + private boolean hasText(final DetailAST slistAST) { final DetailAST rightCurly = slistAST.findFirstToken(TokenTypes.RCURLY); final DetailAST rcurlyAST; @@ -200,20 +193,16 @@ // Handle braces on the same line final String txt = lines[slistLineNo - 1] .substring(slistColNo + 1, rcurlyColNo); - if (StringUtils.isNotBlank(txt)) { + if (!CommonUtils.isBlank(txt)) { returnValue = true; } } else { - // check only whitespace of first & last lines - if (lines[slistLineNo - 1].substring(slistColNo + 1).trim().isEmpty() - && lines[rcurlyLineNo - 1].substring(0, rcurlyColNo).trim().isEmpty()) { - // check if all lines are also only whitespace - returnValue = !checkIsAllLinesAreWhitespace(lines, slistLineNo, rcurlyLineNo); - } - else { - returnValue = true; - } + final String firstLine = lines[slistLineNo - 1].substring(slistColNo + 1); + final String lastLine = lines[rcurlyLineNo - 1].substring(0, rcurlyColNo); + // check if all lines are also only whitespace + returnValue = !(CommonUtils.isBlank(firstLine) && CommonUtils.isBlank(lastLine)) + || !checkIsAllLinesAreWhitespace(lines, slistLineNo, rcurlyLineNo); } return returnValue; } @@ -232,11 +221,37 @@ private static boolean checkIsAllLinesAreWhitespace(String[] lines, int lineFrom, int lineTo) { boolean result = true; for (int i = lineFrom; i < lineTo - 1; i++) { - if (!lines[i].trim().isEmpty()) { + if (!CommonUtils.isBlank(lines[i])) { result = false; break; } } return result; } + + /** + * Calculates the left curly corresponding to the block to be checked. + * + * @param ast a {@code DetailAST} value + * @return the left curly corresponding to the block to be checked + */ + private static DetailAST findLeftCurly(DetailAST ast) { + final DetailAST leftCurly; + final DetailAST slistAST = ast.findFirstToken(TokenTypes.SLIST); + if ((ast.getType() == TokenTypes.LITERAL_CASE + || ast.getType() == TokenTypes.LITERAL_DEFAULT) + && ast.getNextSibling() != null + && ast.getNextSibling().getFirstChild() != null + && ast.getNextSibling().getFirstChild().getType() == TokenTypes.SLIST) { + leftCurly = ast.getNextSibling().getFirstChild(); + } + else if (slistAST == null) { + leftCurly = ast.findFirstToken(TokenTypes.LCURLY); + } + else { + leftCurly = slistAST; + } + return leftCurly; + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/EmptyCatchBlockCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,7 +21,8 @@ import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -124,7 +125,8 @@ *

    * @author Aleksey Nesterenko */ -public class EmptyCatchBlockCheck extends Check { +@StatelessCheck +public class EmptyCatchBlockCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -174,19 +176,19 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.LITERAL_CATCH, - }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] { + TokenTypes.LITERAL_CATCH, + }; } @Override diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/LeftCurlyCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/LeftCurlyCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/LeftCurlyCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/LeftCurlyCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,10 +21,8 @@ import java.util.Locale; -import org.apache.commons.beanutils.ConversionException; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -40,14 +38,13 @@ * LITERAL_IF}, {@link TokenTypes#LITERAL_SWITCH LITERAL_SWITCH}, {@link * TokenTypes#LITERAL_SYNCHRONIZED LITERAL_SYNCHRONIZED}, {@link * TokenTypes#LITERAL_TRY LITERAL_TRY}, {@link TokenTypes#LITERAL_WHILE - * LITERAL_WHILE}, {@link TokenTypes#STATIC_INIT STATIC_INIT}. + * LITERAL_WHILE}, {@link TokenTypes#STATIC_INIT STATIC_INIT}, + * {@link TokenTypes#LAMBDA LAMBDA}. *

    * *

    * The policy to verify is specified using the {@link LeftCurlyOption} class and - * defaults to {@link LeftCurlyOption#EOL}. Policies {@link LeftCurlyOption#EOL} - * and {@link LeftCurlyOption#NLOW} take into account property maxLineLength. - * The default value for maxLineLength is 80. + * defaults to {@link LeftCurlyOption#EOL}. *

    *

    * An example of how to configure the check is: @@ -57,13 +54,12 @@ * *

    * An example of how to configure the check with policy - * {@link LeftCurlyOption#NLOW} and maxLineLength 120 is: + * {@link LeftCurlyOption#NLOW} is: *

    *
      * <module name="LeftCurly">
    - *      <property name="option"
    - * value="nlow"/>     <property name="maxLineLength" value="120"/> <
    - * /module>
    + *      <property name="option" value="nlow"/>
    + * </module>
      * 
    *

    * An example of how to configure the check to validate enum definitions: @@ -78,8 +74,10 @@ * @author lkuehne * @author maxvetrenko */ +@StatelessCheck public class LeftCurlyCheck - extends Check { + extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -110,29 +108,18 @@ /** * Set the option to enforce. * @param optionStr string to decode option from - * @throws ConversionException if unable to decode + * @throws IllegalArgumentException if unable to decode */ public void setOption(String optionStr) { try { option = LeftCurlyOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + optionStr, iae); + throw new IllegalArgumentException("unable to parse " + optionStr, iae); } } /** - * Sets the maximum line length used in calculating the placement of the - * left curly brace. - * @param maxLineLength the max allowed line length - * @deprecated since 6.10 release, option is not required for the Check. - */ - @Deprecated - public void setMaxLineLength(int maxLineLength) { - // do nothing, option is deprecated - } - - /** * Sets whether check should ignore enums when left curly brace policy is EOL. * @param ignoreEnums check's option for ignoring enums. */ @@ -167,12 +154,13 @@ TokenTypes.LITERAL_FOR, TokenTypes.STATIC_INIT, TokenTypes.OBJBLOCK, + TokenTypes.LAMBDA, }; } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -208,6 +196,7 @@ case TokenTypes.LITERAL_DO: case TokenTypes.LITERAL_IF: case TokenTypes.STATIC_INIT: + case TokenTypes.LAMBDA: startToken = ast; brace = ast.findFirstToken(TokenTypes.SLIST); break; @@ -286,7 +275,6 @@ while (previousAnnotation.getPreviousSibling() != null && previousAnnotation.getPreviousSibling().getLineNo() == lastAnnotationLineNumber) { - previousAnnotation = previousAnnotation.getPreviousSibling(); } return previousAnnotation; @@ -326,13 +314,10 @@ } } else if (option == LeftCurlyOption.EOL) { - validateEol(brace, braceLine); } else if (startToken.getLineNo() != brace.getLineNo()) { - validateNewLinePosition(brace, startToken, braceLine); - } } } @@ -394,4 +379,5 @@ || nextToken.getType() == TokenTypes.RCURLY || leftCurly.getLineNo() != nextToken.getLineNo(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/LeftCurlyOption.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/LeftCurlyOption.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/LeftCurlyOption.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/LeftCurlyOption.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,11 +20,13 @@ package com.puppycrawl.tools.checkstyle.checks.blocks; /** - * Represents the options for placing the left curly brace {@code '{'}. + * Represents the options for placing the left curly brace '{'. * * @author Oliver Burn + * @noinspection HtmlTagCanBeJavadocTag */ public enum LeftCurlyOption { + /** * Represents the policy for placing the brace at the end of line. For * example: @@ -70,4 +72,5 @@ * */ NL + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/NeedBracesCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,11 +19,11 @@ package com.puppycrawl.tools.checkstyle.checks.blocks; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    @@ -134,7 +134,9 @@ * @author Aleksey Nesterenko * @author Andrei Selkin */ -public class NeedBracesCheck extends Check { +@StatelessCheck +public class NeedBracesCheck extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -194,7 +196,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -205,16 +207,31 @@ && ast.findFirstToken(TokenTypes.LITERAL_IF) != null) { isElseIf = true; } - + final boolean isDefaultInAnnotation = isDefaultInAnnotation(ast); final boolean skipStatement = isSkipStatement(ast); final boolean skipEmptyLoopBody = allowEmptyLoopBody && isEmptyLoopBody(ast); - if (slistAST == null && !isElseIf && !skipStatement && !skipEmptyLoopBody) { + if (slistAST == null && !isElseIf && !isDefaultInAnnotation + && !skipStatement && !skipEmptyLoopBody) { log(ast.getLineNo(), MSG_KEY_NEED_BRACES, ast.getText()); } } /** + * Checks if ast is the default token of an annotation field. + * @param ast ast to test. + * @return true if current ast is default and it is part of annotation. + */ + private static boolean isDefaultInAnnotation(DetailAST ast) { + boolean isDefaultInAnnotation = false; + if (ast.getType() == TokenTypes.LITERAL_DEFAULT + && ast.getParent().getType() == TokenTypes.ANNOTATION_FIELD_DEF) { + isDefaultInAnnotation = true; + } + return isDefaultInAnnotation; + } + + /** * Checks if current statement can be skipped by "need braces" warning. * @param statement if, for, while, do-while, lambda, else, case, default statements. * @return true if current statement can be skipped by Check. @@ -235,7 +252,7 @@ * @param ast ast token. * @return true if current loop statement does not have body. */ - private boolean isEmptyLoopBody(DetailAST ast) { + private static boolean isEmptyLoopBody(DetailAST ast) { boolean noBodyLoop = false; if (ast.getType() == TokenTypes.LITERAL_FOR @@ -371,7 +388,6 @@ */ private static boolean isSingleLineIf(DetailAST literalIf) { boolean result = false; - final DetailAST ifCondition = literalIf.findFirstToken(TokenTypes.EXPR); if (literalIf.getParent().getType() == TokenTypes.SLIST) { final DetailAST literalIfLastChild = literalIf.getLastChild(); final DetailAST block; @@ -381,6 +397,7 @@ else { block = literalIfLastChild; } + final DetailAST ifCondition = literalIf.findFirstToken(TokenTypes.EXPR); result = ifCondition.getLineNo() == block.getLineNo(); } return result; @@ -411,6 +428,7 @@ * {@code * case 1: doSomeStuff(); break; * case 2: doSomeStuff(); break; + * case 3: ; * } *

    * @param literalCase {@link TokenTypes#LITERAL_CASE case statement}. @@ -419,12 +437,17 @@ private static boolean isSingleLineCase(DetailAST literalCase) { boolean result = false; final DetailAST slist = literalCase.getNextSibling(); - final DetailAST block = slist.getFirstChild(); - if (block.getType() != TokenTypes.SLIST) { - final DetailAST caseBreak = slist.findFirstToken(TokenTypes.LITERAL_BREAK); - final boolean atOneLine = literalCase.getLineNo() == block.getLineNo(); - if (caseBreak != null) { - result = atOneLine && block.getLineNo() == caseBreak.getLineNo(); + if (slist == null) { + result = true; + } + else { + final DetailAST block = slist.getFirstChild(); + if (block.getType() != TokenTypes.SLIST) { + final DetailAST caseBreak = slist.findFirstToken(TokenTypes.LITERAL_BREAK); + if (caseBreak != null) { + final boolean atOneLine = literalCase.getLineNo() == block.getLineNo(); + result = atOneLine && block.getLineNo() == caseBreak.getLineNo(); + } } } return result; @@ -443,9 +466,14 @@ private static boolean isSingleLineDefault(DetailAST literalDefault) { boolean result = false; final DetailAST slist = literalDefault.getNextSibling(); - final DetailAST block = slist.getFirstChild(); - if (block.getType() != TokenTypes.SLIST) { - result = literalDefault.getLineNo() == block.getLineNo(); + if (slist == null) { + result = true; + } + else { + final DetailAST block = slist.getFirstChild(); + if (block != null && block.getType() != TokenTypes.SLIST) { + result = literalDefault.getLineNo() == block.getLineNo(); + } } return result; } @@ -468,4 +496,5 @@ } return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,10 +21,8 @@ import java.util.Locale; -import org.apache.commons.beanutils.ConversionException; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.Scope; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -53,6 +51,7 @@ * {@link TokenTypes#LITERAL_DO LITERAL_DO}. * {@link TokenTypes#STATIC_INIT STATIC_INIT}. * {@link TokenTypes#INSTANCE_INIT INSTANCE_INIT}. + * {@link TokenTypes#LAMBDA LAMBDA}. *

    *

    * shouldStartLine - does the check need to check @@ -83,7 +82,9 @@ * @author Andrei Selkin * @author liscju */ -public class RightCurlyCheck extends Check { +@StatelessCheck +public class RightCurlyCheck extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -115,16 +116,16 @@ private RightCurlyOption option = RightCurlyOption.SAME; /** - * Set the option to enforce. + * Sets the option to enforce. * @param optionStr string to decode option from - * @throws ConversionException if unable to decode + * @throws IllegalArgumentException if unable to decode */ public void setOption(String optionStr) { try { option = RightCurlyOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + optionStr, iae); + throw new IllegalArgumentException("unable to parse " + optionStr, iae); } } @@ -163,78 +164,68 @@ TokenTypes.LITERAL_DO, TokenTypes.STATIC_INIT, TokenTypes.INSTANCE_INIT, + TokenTypes.LAMBDA, }; } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override public void visitToken(DetailAST ast) { - final Details details = getDetails(ast); + final Details details = Details.getDetails(ast); final DetailAST rcurly = details.rcurly; - if (rcurly == null || rcurly.getType() != TokenTypes.RCURLY) { - // we need to have both tokens to perform the check - return; - } - - final String violation; - if (shouldStartLine) { - final String targetSourceLine = getLines()[rcurly.getLineNo() - 1]; - violation = validate(details, option, true, targetSourceLine); - } - else { - violation = validate(details, option, false, ""); - } - - if (!violation.isEmpty()) { - log(rcurly, violation, "}", rcurly.getColumnNo() + 1); + if (rcurly != null) { + final String violation = validate(details); + if (!violation.isEmpty()) { + log(rcurly, violation, "}", rcurly.getColumnNo() + 1); + } } } /** * Does general validation. * @param details for validation. - * @param bracePolicy for placing the right curly brace. - * @param shouldStartLine do we need to check if right curly starts line. - * @param targetSourceLine line that we need to check if shouldStartLine is true. * @return violation message or empty string * if there was not violation during validation. */ - private static String validate(Details details, RightCurlyOption bracePolicy, - boolean shouldStartLine, String targetSourceLine) { - final DetailAST rcurly = details.rcurly; - final DetailAST lcurly = details.lcurly; - final DetailAST nextToken = details.nextToken; - final boolean shouldCheckLastRcurly = details.shouldCheckLastRcurly; + private String validate(Details details) { String violation = ""; - - if (bracePolicy == RightCurlyOption.SAME - && !hasLineBreakBefore(rcurly) - && lcurly.getLineNo() != rcurly.getLineNo()) { + if (shouldHaveLineBreakBefore(option, details)) { violation = MSG_KEY_LINE_BREAK_BEFORE; } - else if (shouldCheckLastRcurly) { - if (rcurly.getLineNo() == nextToken.getLineNo()) { - violation = MSG_KEY_LINE_ALONE; - } - } - else if (shouldBeOnSameLine(bracePolicy, details)) { + else if (shouldBeOnSameLine(option, details)) { violation = MSG_KEY_LINE_SAME; } - else if (shouldBeAloneOnLine(bracePolicy, details)) { + else if (shouldBeAloneOnLine(option, details)) { violation = MSG_KEY_LINE_ALONE; } - else if (shouldStartLine && !isOnStartOfLine(details, targetSourceLine)) { - violation = MSG_KEY_LINE_NEW; + else if (shouldStartLine) { + final String targetSourceLine = getLines()[details.rcurly.getLineNo() - 1]; + if (!isOnStartOfLine(details, targetSourceLine)) { + violation = MSG_KEY_LINE_NEW; + } } return violation; } /** + * Checks whether a right curly should have a line break before. + * @param bracePolicy option for placing the right curly brace. + * @param details details for validation. + * @return true if a right curly should have a line break before. + */ + private static boolean shouldHaveLineBreakBefore(RightCurlyOption bracePolicy, + Details details) { + return bracePolicy == RightCurlyOption.SAME + && !hasLineBreakBefore(details.rcurly) + && details.lcurly.getLineNo() != details.rcurly.getLineNo(); + } + + /** * Checks that a right curly should be on the same line as the next statement. * @param bracePolicy option for placing the right curly brace * @param details Details for validation @@ -242,6 +233,7 @@ */ private static boolean shouldBeOnSameLine(RightCurlyOption bracePolicy, Details details) { return bracePolicy == RightCurlyOption.SAME + && !details.shouldCheckLastRcurly && details.rcurly.getLineNo() != details.nextToken.getLineNo(); } @@ -253,10 +245,31 @@ */ private static boolean shouldBeAloneOnLine(RightCurlyOption bracePolicy, Details details) { return bracePolicy == RightCurlyOption.ALONE - && !isAloneOnLine(details) - && !isEmptyBody(details.lcurly) + && shouldBeAloneOnLineWithAloneOption(details) || bracePolicy == RightCurlyOption.ALONE_OR_SINGLELINE - && !isAloneOnLine(details) + && shouldBeAloneOnLineWithAloneOrSinglelineOption(details) + || details.shouldCheckLastRcurly + && details.rcurly.getLineNo() == details.nextToken.getLineNo(); + } + + /** + * Whether right curly should be alone on line when ALONE option is used. + * @param details details for validation. + * @return true, if right curly should be alone on line when ALONE option is used. + */ + private static boolean shouldBeAloneOnLineWithAloneOption(Details details) { + return !isAloneOnLine(details) + && !isEmptyBody(details.lcurly); + } + + /** + * Whether right curly should be alone on line when ALONE_OR_SINGLELINE option is used. + * @param details details for validation. + * @return true, if right curly should be alone on line + * when ALONE_OR_SINGLELINE option is used. + */ + private static boolean shouldBeAloneOnLineWithAloneOrSinglelineOption(Details details) { + return !isAloneOnLine(details) && !isSingleLineBlock(details) && !isAnonInnerClassInit(details.lcurly) && !isEmptyBody(details.lcurly); @@ -310,24 +323,122 @@ } /** - * Collects validation details. - * @param ast detail ast. - * @return object that contain all details to make a validation. - */ - private static Details getDetails(DetailAST ast) { - // Attempt to locate the tokens to do the check - boolean shouldCheckLastRcurly = false; - DetailAST rcurly = null; - final DetailAST lcurly; - DetailAST nextToken; + * Checks if definition body is empty. + * @param lcurly left curly. + * @return true if definition body is empty. + */ + private static boolean isEmptyBody(DetailAST lcurly) { + boolean result = false; + if (lcurly.getParent().getType() == TokenTypes.OBJBLOCK) { + if (lcurly.getNextSibling().getType() == TokenTypes.RCURLY) { + result = true; + } + } + else if (lcurly.getFirstChild().getType() == TokenTypes.RCURLY) { + result = true; + } + return result; + } + + /** + * Checks if right curly has line break before. + * @param rightCurly right curly token. + * @return true, if right curly has line break before. + */ + private static boolean hasLineBreakBefore(DetailAST rightCurly) { + final DetailAST previousToken = rightCurly.getPreviousSibling(); + return previousToken == null + || rightCurly.getLineNo() != previousToken.getLineNo(); + } - switch (ast.getType()) { - case TokenTypes.LITERAL_TRY: - lcurly = ast.getFirstChild(); + /** + * Structure that contains all details for validation. + */ + private static final class Details { + + /** Right curly. */ + private final DetailAST rcurly; + /** Left curly. */ + private final DetailAST lcurly; + /** Next token. */ + private final DetailAST nextToken; + /** Should check last right curly. */ + private final boolean shouldCheckLastRcurly; + + /** + * Constructor. + * @param lcurly the lcurly of the token whose details are being collected + * @param rcurly the rcurly of the token whose details are being collected + * @param nextToken the token after the token whose details are being collected + * @param shouldCheckLastRcurly boolean value to determine if to check last rcurly + */ + private Details(DetailAST lcurly, DetailAST rcurly, + DetailAST nextToken, boolean shouldCheckLastRcurly) { + this.lcurly = lcurly; + this.rcurly = rcurly; + this.nextToken = nextToken; + this.shouldCheckLastRcurly = shouldCheckLastRcurly; + } + + /** + * Collects validation Details. + * @param ast a {@code DetailAST} value + * @return object containing all details to make a validation + */ + private static Details getDetails(DetailAST ast) { + final Details details; + switch (ast.getType()) { + case TokenTypes.LITERAL_TRY: + case TokenTypes.LITERAL_CATCH: + case TokenTypes.LITERAL_FINALLY: + details = getDetailsForTryCatchFinally(ast); + break; + case TokenTypes.LITERAL_IF: + case TokenTypes.LITERAL_ELSE: + details = getDetailsForIfElse(ast); + break; + case TokenTypes.LITERAL_DO: + case TokenTypes.LITERAL_WHILE: + case TokenTypes.LITERAL_FOR: + details = getDetailsForLoops(ast); + break; + case TokenTypes.LAMBDA: + details = getDetailsForLambda(ast); + break; + default: + details = getDetailsForOthers(ast); + break; + } + return details; + } + + /** + * Collects validation details for LITERAL_TRY, LITERAL_CATCH, and LITERAL_FINALLY. + * @param ast a {@code DetailAST} value + * @return object containing all details to make a validation + */ + private static Details getDetailsForTryCatchFinally(DetailAST ast) { + boolean shouldCheckLastRcurly = false; + final DetailAST rcurly; + final DetailAST lcurly; + DetailAST nextToken; + final int tokenType = ast.getType(); + if (tokenType == TokenTypes.LITERAL_TRY) { + if (ast.getFirstChild().getType() == TokenTypes.RESOURCE_SPECIFICATION) { + lcurly = ast.getFirstChild().getNextSibling(); + } + else { + lcurly = ast.getFirstChild(); + } nextToken = lcurly.getNextSibling(); rcurly = lcurly.getLastChild(); - break; - case TokenTypes.LITERAL_CATCH: + + if (nextToken == null) { + shouldCheckLastRcurly = true; + nextToken = getNextToken(ast); + } + } + else if (tokenType == TokenTypes.LITERAL_CATCH) { nextToken = ast.getNextSibling(); lcurly = ast.getLastChild(); rcurly = lcurly.getLastChild(); @@ -335,120 +446,149 @@ shouldCheckLastRcurly = true; nextToken = getNextToken(ast); } - break; - case TokenTypes.LITERAL_IF: + } + else { + shouldCheckLastRcurly = true; + nextToken = getNextToken(ast); + lcurly = ast.getFirstChild(); + rcurly = lcurly.getLastChild(); + } + return new Details(lcurly, rcurly, nextToken, shouldCheckLastRcurly); + } + + /** + * Collects validation details for LITERAL_IF and LITERAL_ELSE. + * @param ast a {@code DetailAST} value + * @return object containing all details to make a validation + */ + private static Details getDetailsForIfElse(DetailAST ast) { + boolean shouldCheckLastRcurly = false; + DetailAST rcurly = null; + final DetailAST lcurly; + DetailAST nextToken; + final int tokenType = ast.getType(); + if (tokenType == TokenTypes.LITERAL_IF) { nextToken = ast.findFirstToken(TokenTypes.LITERAL_ELSE); if (nextToken == null) { shouldCheckLastRcurly = true; nextToken = getNextToken(ast); lcurly = ast.getLastChild(); - rcurly = lcurly.getLastChild(); } else { lcurly = nextToken.getPreviousSibling(); + } + if (lcurly.getType() == TokenTypes.SLIST) { rcurly = lcurly.getLastChild(); } - break; - case TokenTypes.LITERAL_ELSE: - case TokenTypes.LITERAL_FINALLY: + } + else { shouldCheckLastRcurly = true; nextToken = getNextToken(ast); lcurly = ast.getFirstChild(); - rcurly = lcurly.getLastChild(); - break; - case TokenTypes.CLASS_DEF: + if (lcurly.getType() == TokenTypes.SLIST) { + rcurly = lcurly.getLastChild(); + } + } + return new Details(lcurly, rcurly, nextToken, shouldCheckLastRcurly); + } + + /** + * Collects validation details for CLASS_DEF, METHOD DEF, CTOR_DEF, STATIC_INIT, and + * INSTANCE_INIT. + * @param ast a {@code DetailAST} value + * @return an object containing all details to make a validation + */ + private static Details getDetailsForOthers(DetailAST ast) { + DetailAST rcurly = null; + final DetailAST lcurly; + final DetailAST nextToken; + final int tokenType = ast.getType(); + if (tokenType == TokenTypes.CLASS_DEF) { final DetailAST child = ast.getLastChild(); lcurly = child.getFirstChild(); rcurly = child.getLastChild(); nextToken = ast; - break; - case TokenTypes.CTOR_DEF: - case TokenTypes.STATIC_INIT: - case TokenTypes.INSTANCE_INIT: + } + else if (tokenType == TokenTypes.METHOD_DEF) { + lcurly = ast.findFirstToken(TokenTypes.SLIST); + if (lcurly != null) { + // SLIST could be absent if method is abstract + rcurly = lcurly.getLastChild(); + } + nextToken = getNextToken(ast); + } + else { lcurly = ast.findFirstToken(TokenTypes.SLIST); rcurly = lcurly.getLastChild(); nextToken = getNextToken(ast); - break; - default: - // ATTENTION! We have default here, but we expect case TokenTypes.METHOD_DEF, - // TokenTypes.LITERAL_FOR, TokenTypes.LITERAL_WHILE, TokenTypes.LITERAL_DO only. - // It has been done to improve coverage to 100%. I couldn't replace it with - // if-else-if block because code was ugly and didn't pass pmd check. + } + return new Details(lcurly, rcurly, nextToken, false); + } + /** + * Collects validation details for loops' tokens. + * @param ast a {@code DetailAST} value + * @return an object containing all details to make a validation + */ + private static Details getDetailsForLoops(DetailAST ast) { + DetailAST rcurly = null; + final DetailAST lcurly; + final DetailAST nextToken; + final int tokenType = ast.getType(); + if (tokenType == TokenTypes.LITERAL_DO) { + nextToken = ast.findFirstToken(TokenTypes.DO_WHILE); lcurly = ast.findFirstToken(TokenTypes.SLIST); if (lcurly != null) { - // SLIST could be absent if method is abstract, - // and code like "while(true);" + rcurly = lcurly.getLastChild(); + } + } + else { + lcurly = ast.findFirstToken(TokenTypes.SLIST); + if (lcurly != null) { + // SLIST could be absent in code like "while(true);" rcurly = lcurly.getLastChild(); } nextToken = getNextToken(ast); - break; + } + return new Details(lcurly, rcurly, nextToken, false); } - final Details details = new Details(); - details.rcurly = rcurly; - details.lcurly = lcurly; - details.nextToken = nextToken; - details.shouldCheckLastRcurly = shouldCheckLastRcurly; - - return details; - } - - /** - * Checks if definition body is empty. - * @param lcurly left curly. - * @return true if definition body is empty. - */ - private static boolean isEmptyBody(DetailAST lcurly) { - boolean result = false; - if (lcurly.getParent().getType() == TokenTypes.OBJBLOCK) { - if (lcurly.getNextSibling().getType() == TokenTypes.RCURLY) { - result = true; + /** + * Collects validation details for Lambdas. + * @param ast a {@code DetailAST} value + * @return an object containing all details to make a validation + */ + private static Details getDetailsForLambda(DetailAST ast) { + final DetailAST lcurly = ast.findFirstToken(TokenTypes.SLIST); + boolean shouldCheckLastRcurly = false; + DetailAST nextToken = getNextToken(ast); + if (nextToken.getType() != TokenTypes.RPAREN + && nextToken.getType() != TokenTypes.COMMA) { + shouldCheckLastRcurly = true; + nextToken = getNextToken(nextToken); } + DetailAST rcurly = null; + if (lcurly != null) { + rcurly = lcurly.getLastChild(); + } + return new Details(lcurly, rcurly, nextToken, shouldCheckLastRcurly); } - else if (lcurly.getFirstChild().getType() == TokenTypes.RCURLY) { - result = true; - } - return result; - } - /** - * Finds next token after the given one. - * @param ast the given node. - * @return the token which represents next lexical item. - */ - private static DetailAST getNextToken(DetailAST ast) { - DetailAST next = null; - DetailAST parent = ast; - while (next == null) { - next = parent.getNextSibling(); - parent = parent.getParent(); + /** + * Finds next token after the given one. + * @param ast the given node. + * @return the token which represents next lexical item. + */ + private static DetailAST getNextToken(DetailAST ast) { + DetailAST next = null; + DetailAST parent = ast; + while (next == null) { + next = parent.getNextSibling(); + parent = parent.getParent(); + } + return CheckUtils.getFirstNode(next); } - return CheckUtils.getFirstNode(next); - } - /** - * Checks if right curly has line break before. - * @param rightCurly right curly token. - * @return true, if right curly has line break before. - */ - private static boolean hasLineBreakBefore(DetailAST rightCurly) { - final DetailAST previousToken = rightCurly.getPreviousSibling(); - return previousToken == null - || rightCurly.getLineNo() != previousToken.getLineNo(); } - /** - * Structure that contains all details for validation. - */ - private static class Details { - /** Right curly. */ - private DetailAST rcurly; - /** Left curly. */ - private DetailAST lcurly; - /** Next token. */ - private DetailAST nextToken; - /** Should check last right curly. */ - private boolean shouldCheckLastRcurly; - } } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyOption.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyOption.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyOption.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/blocks/RightCurlyOption.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,10 @@ package com.puppycrawl.tools.checkstyle.checks.blocks; /** - * Represents the options for placing the right curly brace {@code '}'}. + * Represents the options for placing the right curly brace '}'. * * @author Oliver Burn + * @noinspection HtmlTagCanBeJavadocTag */ public enum RightCurlyOption { @@ -64,7 +65,8 @@ /** * Represents the policy that the brace should be on the same line as the * the next part of a multi-block statement (one that directly contains - * multiple blocks: if/else-if/else or try/catch/finally). + * multiple blocks: if/else-if/else or try/catch/finally). It also allows + * single-line format of multi-block statements. * *

    Examples:

    * @@ -117,7 +119,14 @@ * ... * } // this is NOT OK, not on the same line as the next part of a multi-block statement * }); // this is OK, allowed for better code readability + * + * if (a > 0) { ... } // OK, single-line multi-block statement + * if (a > 0) { ... } else { ... } // OK, single-line multi-block statement + * if (a > 0) { + * ... + * } else { ... } // OK, single-line multi-block statement * **/ SAME + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/ClassResolver.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/ClassResolver.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/ClassResolver.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/ClassResolver.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,219 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.checks; - -import java.util.HashSet; -import java.util.Set; - -/** - * Utility class to resolve a class name to an actual class. Note that loaded - * classes are not initialized. - *

    Limitations: this does not handle inner classes very well.

    - * - * @author Oliver Burn - */ -public class ClassResolver { - - /** Period literal. */ - private static final String PERIOD = "."; - /** Dollar sign literal. */ - private static final String DOLLAR_SIGN = "$"; - - /** Name of the package to check if the class belongs to. **/ - private final String pkg; - /** Set of imports to check against. **/ - private final Set imports; - /** Use to load classes. **/ - private final ClassLoader loader; - - /** - * Creates a new {@code ClassResolver} instance. - * - * @param loader the ClassLoader to load classes with. - * @param pkg the name of the package the class may belong to - * @param imports set of imports to check if the class belongs to - */ - public ClassResolver(ClassLoader loader, String pkg, Set imports) { - this.loader = loader; - this.pkg = pkg; - this.imports = new HashSet<>(imports); - this.imports.add("java.lang.*"); - } - - /** - * Attempts to resolve the Class for a specified name. The algorithm is - * to check: - * - fully qualified name - * - explicit imports - * - enclosing package - * - star imports - * @param name name of the class to resolve - * @param currentClass name of current class (for inner classes). - * @return the resolved class - * @throws ClassNotFoundException if unable to resolve the class - */ - public Class resolve(String name, String currentClass) - throws ClassNotFoundException { - // See if the class is full qualified - Class clazz = resolveQualifiedName(name); - if (clazz != null) { - return clazz; - } - - // try matching explicit imports - for (String imp : imports) { - // Very important to add the "." in the check below. Otherwise you - // when checking for "DataException", it will match on - // "SecurityDataException". This has been the cause of a very - // difficult bug to resolve! - if (imp.endsWith(PERIOD + name)) { - clazz = resolveQualifiedName(imp); - if (clazz != null) { - return clazz; - } - - } - } - - // See if in the package - if (pkg != null && !pkg.isEmpty()) { - final Class classFromQualifiedName = resolveQualifiedName(pkg + PERIOD + name); - if (classFromQualifiedName != null) { - return classFromQualifiedName; - } - } - - // see if inner class of this class - final Class innerClass = resolveInnerClass(name, currentClass); - if (innerClass != null) { - return innerClass; - } - - final Class classFromStarImport = resolveByStarImports(name); - if (classFromStarImport != null) { - return classFromStarImport; - } - - // Giving up, the type is unknown, so load the class to generate an - // exception - return safeLoad(name); - } - - /** - * See if inner class of this class. - * @param name name of the search Class to search - * @param currentClass class where search in - * @return class if found , or null if not resolved - * @throws ClassNotFoundException if an error occurs - */ - private Class resolveInnerClass(String name, String currentClass) - throws ClassNotFoundException { - Class clazz = null; - if (!currentClass.isEmpty()) { - String innerClass = currentClass + DOLLAR_SIGN + name; - - if (!pkg.isEmpty()) { - innerClass = pkg + PERIOD + innerClass; - } - - if (isLoadable(innerClass)) { - clazz = safeLoad(innerClass); - } - } - return clazz; - } - - /** - * Try star imports. - * @param name name of the Class to search - * @return class if found , or null if not resolved - */ - private Class resolveByStarImports(String name) { - Class clazz = null; - for (String imp : imports) { - if (imp.endsWith(".*")) { - final String fqn = imp.substring(0, imp.lastIndexOf('.') + 1) - + name; - clazz = resolveQualifiedName(fqn); - if (clazz != null) { - break; - } - } - } - return clazz; - } - - /** - * @param name name of the class to check - * @return whether a specified class is loadable with safeLoad(). - */ - public boolean isLoadable(String name) { - try { - safeLoad(name); - return true; - } - catch (final ClassNotFoundException ignored) { - return false; - } - } - - /** - * Will load a specified class is such a way that it will NOT be - * initialised. - * @param name name of the class to load - * @return the {@code Class} for the specified class - * @throws ClassNotFoundException if an error occurs - */ - public Class safeLoad(String name) throws ClassNotFoundException { - // The next line will load the class using the specified class - // loader. The magic is having the "false" parameter. This means the - // class will not be initialised. Very, very important. - return Class.forName(name, false, loader); - } - - /** - * Tries to resolve a class for fully-specified name. - * @param name a given name of class. - * @return Class object for the given name or null. - */ - private Class resolveQualifiedName(final String name) { - Class classObj = null; - try { - if (isLoadable(name)) { - classObj = safeLoad(name); - } - else { - //Perhaps it's fully-qualified inner class - final int dot = name.lastIndexOf('.'); - if (dot != -1) { - final String innerName = - name.substring(0, dot) + DOLLAR_SIGN + name.substring(dot + 1); - classObj = resolveQualifiedName(innerName); - } - } - } - catch (final ClassNotFoundException ex) { - // we shouldn't get this exception here, - // so this is unexpected runtime exception - throw new IllegalStateException(ex); - } - return classObj; - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalCheck.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,75 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.checks.coding; - -import java.util.Set; - -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; - -/** - * Support for checks that look for usage of illegal types. - * @deprecated Checkstyle will not support abstract checks anymore. Use {@link Check} instead. - * @author Oliver Burn - * @noinspection AbstractClassNeverImplemented - */ -@Deprecated -public abstract class AbstractIllegalCheck extends Check { - /** Illegal class names. */ - private final Set illegalClassNames = Sets.newHashSet(); - - /** - * Constructs an object. - * @param initialNames the initial class names to treat as illegal - */ - protected AbstractIllegalCheck(final String... initialNames) { - setIllegalClassNames(initialNames); - } - - /** - * Checks if given class is illegal. - * - * @param ident - * ident to check. - * @return true if given ident is illegal. - */ - protected final boolean isIllegalClassName(final String ident) { - return illegalClassNames.contains(ident); - } - - /** - * Set the list of illegal classes. - * - * @param classNames - * array of illegal exception classes - */ - public final void setIllegalClassNames(final String... classNames) { - illegalClassNames.clear(); - for (final String name : classNames) { - illegalClassNames.add(name); - final int lastDot = name.lastIndexOf('.'); - if (lastDot > 0 && lastDot < name.length() - 1) { - final String shortName = name - .substring(name.lastIndexOf('.') + 1); - illegalClassNames.add(shortName); - } - } - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalMethodCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalMethodCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalMethodCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractIllegalMethodCheck.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,81 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.checks.coding; - -import com.puppycrawl.tools.checkstyle.api.Check; -import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; - -/** - * Provide support for checking for a method with a specified name and no - * arguments. - * @deprecated Checkstyle will not support abstract checks anymore. Use {@link Check} instead. - * @author Oliver Burn - * @noinspection AbstractClassNeverImplemented - */ -@Deprecated -public abstract class AbstractIllegalMethodCheck extends Check { - /** Name of method to disallow. */ - private final String methodName; - /** The error key to report with. */ - private final String errorKey; - - /** - * Creates an instance. - * @param methodName name of the method to disallow. - * @param errorKey the error key to report with. - */ - protected AbstractIllegalMethodCheck(String methodName, String errorKey) { - this.methodName = methodName; - this.errorKey = errorKey; - } - - @Override - public int[] getDefaultTokens() { - return getAcceptableTokens(); - } - - @Override - public int[] getAcceptableTokens() { - return new int[] {TokenTypes.METHOD_DEF}; - } - - @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); - } - - @Override - public void visitToken(DetailAST aAST) { - final DetailAST mid = aAST.findFirstToken(TokenTypes.IDENT); - final String name = mid.getText(); - - if (methodName.equals(name)) { - - final DetailAST params = aAST.findFirstToken(TokenTypes.PARAMETERS); - final boolean hasEmptyParamList = - !params.branchContains(TokenTypes.PARAMETER_DEF); - - if (hasEmptyParamList) { - log(aAST.getLineNo(), errorKey); - } - } - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractNestedDepthCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractNestedDepthCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractNestedDepthCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractNestedDepthCheck.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,80 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.checks.coding; - -import com.puppycrawl.tools.checkstyle.api.Check; -import com.puppycrawl.tools.checkstyle.api.DetailAST; - -/** - * Abstract class which provides helpers functionality for nested checks. - * @deprecated Checkstyle will not support abstract checks anymore. Use {@link Check} instead. - * @author Simon Harris - * @noinspection AbstractClassNeverImplemented - */ -@Deprecated -public abstract class AbstractNestedDepthCheck extends Check { - /** Maximum allowed nesting depth. */ - private int max; - /** Current nesting depth. */ - private int depth; - - /** - * Creates new instance of checks. - * @param max default allowed nesting depth. - */ - protected AbstractNestedDepthCheck(int max) { - this.max = max; - } - - @Override - public final int[] getRequiredTokens() { - return getDefaultTokens(); - } - - @Override - public void beginTree(DetailAST rootAST) { - depth = 0; - } - - /** - * Setter for maximum allowed nesting depth. - * @param max maximum allowed nesting depth. - */ - public final void setMax(int max) { - this.max = max; - } - - /** - * Increasing current nesting depth. - * @param ast note which increases nesting. - * @param messageId message id for logging error. - */ - protected final void nestIn(DetailAST ast, String messageId) { - if (depth > max) { - log(ast, messageId, depth, max); - } - ++depth; - } - - /** Decreasing current nesting depth. */ - protected final void nestOut() { - --depth; - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AbstractSuperCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,11 +20,11 @@ package com.puppycrawl.tools.checkstyle.checks.coding; import java.util.Deque; +import java.util.LinkedList; import antlr.collections.AST; - -import com.google.common.collect.Lists; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; @@ -36,8 +36,9 @@ *

    * @author Rick Giles */ +@FileStatefulCheck public abstract class AbstractSuperCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -46,7 +47,7 @@ public static final String MSG_KEY = "missing.super.call"; /** Stack of methods. */ - private final Deque methodStack = Lists.newLinkedList(); + private final Deque methodStack = new LinkedList<>(); /** * Returns the name of the overriding method. @@ -56,20 +57,20 @@ @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.METHOD_DEF, - TokenTypes.LITERAL_SUPER, - }; + return getRequiredTokens(); } @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] { + TokenTypes.METHOD_DEF, + TokenTypes.LITERAL_SUPER, + }; } @Override @@ -101,8 +102,7 @@ // dot operator? final DetailAST dotAst = literalSuperAst.getParent(); - if (dotAst.getType() == TokenTypes.DOT - && !isSameNameMethod(literalSuperAst) + if (!isSameNameMethod(literalSuperAst) && !hasArguments(dotAst)) { superCall = isSuperCallInOverridingMethod(dotAst); } @@ -120,16 +120,13 @@ boolean inOverridingMethod = false; DetailAST dotAst = ast; - while (dotAst != null - && dotAst.getType() != TokenTypes.CTOR_DEF + while (dotAst.getType() != TokenTypes.CTOR_DEF && dotAst.getType() != TokenTypes.INSTANCE_INIT) { - if (dotAst.getType() == TokenTypes.METHOD_DEF) { inOverridingMethod = isOverridingMethod(dotAst); break; } dotAst = dotAst.getParent(); - } return inOverridingMethod; } @@ -150,18 +147,13 @@ * @return true if method name is the same */ private boolean isSameNameMethod(DetailAST ast) { - AST sibling = ast.getNextSibling(); // ignore type parameters if (sibling != null && sibling.getType() == TokenTypes.TYPE_ARGUMENTS) { sibling = sibling.getNextSibling(); } - if (sibling == null || sibling.getType() != TokenTypes.IDENT) { - return true; - } - final String name = sibling.getText(); - return !getMethodName().equals(name); + return sibling == null || !getMethodName().equals(sibling.getText()); } @Override @@ -195,7 +187,7 @@ final DetailAST modifiersAST = ast.findFirstToken(TokenTypes.MODIFIERS); if (getMethodName().equals(name) - && !modifiersAST.branchContains(TokenTypes.LITERAL_NATIVE)) { + && modifiersAST.findFirstToken(TokenTypes.LITERAL_NATIVE) == null) { final DetailAST params = ast.findFirstToken(TokenTypes.PARAMETERS); overridingMethod = params.getChildCount() == 0; } @@ -209,6 +201,7 @@ * @author Rick Giles */ private static class MethodNode { + /** Method definition. */ private final DetailAST method; @@ -247,5 +240,7 @@ public DetailAST getMethod() { return method; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ArrayTrailingCommaCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ArrayTrailingCommaCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ArrayTrailingCommaCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ArrayTrailingCommaCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -29,9 +30,57 @@ *

    *

    * Rationale: Putting this comma in make is easier to change the - * order of the elements or add new elements on the end. + * order of the elements or add new elements on the end. Main benefit of a trailing + * comma is that when you add new entry to an array, no surrounding lines are changed. *

    *

    + * The check demands a comma at the end if neither left nor right curly braces + * are on the same line as the last element of the array. + *

    + *
    + * return new int[] { 0 };
    + * return new int[] { 0
    + *     };
    + * return new int[] {
    + *     0 };
    + * 
    + *
    + * {
    + *     100000000000000000000,
    + *     200000000000000000000, // OK
    + * }
    + *
    + * {
    + *     100000000000000000000,
    + *     200000000000000000000,
    + *     300000000000000000000,  // Just this line added, no other changes
    + * }
    + * 
    + *

    + * If closing brace is on the same line as training comma, this benefit is gone + * (as the Check does not demand a certain location of curly braces the following + * two cases will not produce a violation): + *

    + *
    + * {100000000000000000000,
    + *     200000000000000000000,} // Trailing comma not needed, line needs to be modified anyway
    + *
    + * {100000000000000000000,
    + *     200000000000000000000, // Modified line
    + *     300000000000000000000,} // Added line
    + * 
    + *

    + * If opening brace is on the same line as training comma there's also (more arguable) problem: + *

    + *
    + * {100000000000000000000, // Line cannot be just duplicated to slightly modify entry
    + * }
    + *
    + * {100000000000000000000,
    + *     100000000000000000001, // More work needed to duplicate
    + * }
    + * 
    + *

    * An example of how to configure the check is: *

    *
    @@ -39,7 +88,8 @@
      * 
    * @author o_sukhodolsky */ -public class ArrayTrailingCommaCheck extends Check { +@StatelessCheck +public class ArrayTrailingCommaCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -49,33 +99,31 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.ARRAY_INIT}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.ARRAY_INIT}; } @Override public void visitToken(DetailAST arrayInit) { final DetailAST rcurly = arrayInit.findFirstToken(TokenTypes.RCURLY); + final DetailAST previousSibling = rcurly.getPreviousSibling(); - // if curlies are on the same line - // or array is empty then check nothing - if (arrayInit.getLineNo() == rcurly.getLineNo() - || arrayInit.getChildCount() == 1) { - return; - } - - final DetailAST prev = rcurly.getPreviousSibling(); - if (prev.getType() != TokenTypes.COMMA) { + if (arrayInit.getLineNo() != rcurly.getLineNo() + && arrayInit.getChildCount() != 1 + && rcurly.getLineNo() != previousSibling.getLineNo() + && arrayInit.getLineNo() != previousSibling.getLineNo() + && previousSibling.getType() != TokenTypes.COMMA) { log(rcurly.getLineNo(), MSG_KEY); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AvoidInlineConditionalsCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AvoidInlineConditionalsCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AvoidInlineConditionalsCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/AvoidInlineConditionalsCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -36,7 +37,8 @@ * * @author lkuehne */ -public class AvoidInlineConditionalsCheck extends Check { +@StatelessCheck +public class AvoidInlineConditionalsCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -46,17 +48,17 @@ @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.QUESTION}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] {TokenTypes.QUESTION}; } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.QUESTION}; + return getRequiredTokens(); } @Override @@ -66,4 +68,5 @@ log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/CovariantEqualsCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/CovariantEqualsCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/CovariantEqualsCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/CovariantEqualsCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,11 @@ package com.puppycrawl.tools.checkstyle.checks.coding; +import java.util.HashSet; import java.util.Set; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -42,7 +43,8 @@ * * @author Rick Giles */ -public class CovariantEqualsCheck extends Check { +@FileStatefulCheck +public class CovariantEqualsCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -51,21 +53,21 @@ public static final String MSG_KEY = "covariant.equals"; /** Set of equals method definitions. */ - private final Set equalsMethods = Sets.newHashSet(); + private final Set equalsMethods = new HashSet<>(); @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.CLASS_DEF, TokenTypes.LITERAL_NEW, TokenTypes.ENUM_DEF, }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] {TokenTypes.CLASS_DEF, TokenTypes.LITERAL_NEW, TokenTypes.ENUM_DEF, }; } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.CLASS_DEF, TokenTypes.LITERAL_NEW, TokenTypes.ENUM_DEF, }; + return getRequiredTokens(); } @Override @@ -119,4 +121,5 @@ final String name = fullIdent.getText(); return "Object".equals(name) || "java.lang.Object".equals(name); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DeclarationOrderCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DeclarationOrderCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DeclarationOrderCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DeclarationOrderCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,8 +21,11 @@ import java.util.ArrayDeque; import java.util.Deque; +import java.util.HashSet; +import java.util.Set; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.Scope; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -31,9 +34,9 @@ /** * Checks that the parts of a class or interface declaration * appear in the order suggested by the - * Code Conventions for the Java Programming Language. + * + * Code Conventions for the Java Programming Language. * * *
      @@ -47,6 +50,18 @@ *
    1. Methods
    2. *
    * + *

    ATTENTION: the check skips class fields which have + * + * forward references from validation due to the fact that we have Checkstyle's limitations + * to clearly detect user intention of fields location and grouping. For example, + *

    {@code
    + *      public class A {
    + *          private double x = 1.0;
    + *          private double y = 2.0;
    + *          public double slope = x / y; // will be skipped from validation due to forward reference
    + *      }
    + * }
    + * *

    Available options: *

      *
    • ignoreModifiers
    • @@ -93,7 +108,8 @@ * * @author r_auckenthaler */ -public class DeclarationOrderCheck extends Check { +@FileStatefulCheck +public class DeclarationOrderCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -133,9 +149,12 @@ /** * List of Declaration States. This is necessary due to - * inner classes that have their own state + * inner classes that have their own state. */ - private final Deque scopeStates = new ArrayDeque<>(); + private Deque scopeStates; + + /** Set of all class field names.*/ + private Set classFieldNames; /** If true, ignores the check to constructors. */ private boolean ignoreConstructors; @@ -144,22 +163,29 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { return new int[] { TokenTypes.CTOR_DEF, TokenTypes.METHOD_DEF, TokenTypes.MODIFIERS, TokenTypes.OBJBLOCK, + TokenTypes.VARIABLE_DEF, }; } @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); + public void beginTree(DetailAST rootAST) { + scopeStates = new ArrayDeque<>(); + classFieldNames = new HashSet<>(); } @Override @@ -188,17 +214,22 @@ state.currentScopeState = STATE_METHOD_DEF; } break; + case TokenTypes.VARIABLE_DEF: + if (ScopeUtils.isClassFieldDef(ast)) { + final DetailAST fieldDef = ast.findFirstToken(TokenTypes.IDENT); + classFieldNames.add(fieldDef.getText()); + } + break; default: break; } } /** - * Process constructor. - * @param ast constructor AST + * Processes constructor. + * @param ast constructor AST. */ private void processConstructor(DetailAST ast) { - final ScopeState state = scopeStates.peek(); if (state.currentScopeState > STATE_CTOR_DEF) { if (!ignoreConstructors) { @@ -211,15 +242,30 @@ } /** - * Process modifiers. - * @param ast ast of Modifiers + * Processes modifiers. + * @param ast ast of Modifiers. */ private void processModifiers(DetailAST ast) { - final ScopeState state = scopeStates.peek(); - if (ast.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { + final boolean isStateValid = processModifiersState(ast, state); + processModifiersSubState(ast, state, isStateValid); + } + + /** + * Process if given modifiers are appropriate in given state + * ({@code STATE_STATIC_VARIABLE_DEF}, {@code STATE_INSTANCE_VARIABLE_DEF}, + * ({@code STATE_CTOR_DEF}, {@code STATE_METHOD_DEF}), if it is + * it updates states where appropriate or logs violation. + * @param modifierAst modifiers to process + * @param state current state + * @return true if modifierAst is valid in given state, false otherwise + */ + private boolean processModifiersState(DetailAST modifierAst, ScopeState state) { + boolean isStateValid = true; + if (modifierAst.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { if (state.currentScopeState > STATE_INSTANCE_VARIABLE_DEF) { - log(ast, MSG_INSTANCE); + isStateValid = false; + log(modifierAst, MSG_INSTANCE); } else if (state.currentScopeState == STATE_STATIC_VARIABLE_DEF) { state.declarationAccess = Scope.PUBLIC; @@ -230,18 +276,33 @@ if (state.currentScopeState > STATE_STATIC_VARIABLE_DEF) { if (!ignoreModifiers || state.currentScopeState > STATE_INSTANCE_VARIABLE_DEF) { - log(ast, MSG_STATIC); + isStateValid = false; + log(modifierAst, MSG_STATIC); } } else { state.currentScopeState = STATE_STATIC_VARIABLE_DEF; } } + return isStateValid; + } - final Scope access = ScopeUtils.getScopeFromMods(ast); + /** + * Checks if given modifiers are valid in substate of given + * state({@code Scope}), if it is it updates substate or else it + * logs violation. + * @param modifiersAst modifiers to process + * @param state current state + * @param isStateValid is main state for given modifiers is valid + */ + private void processModifiersSubState(DetailAST modifiersAst, ScopeState state, + boolean isStateValid) { + final Scope access = ScopeUtils.getScopeFromMods(modifiersAst); if (state.declarationAccess.compareTo(access) > 0) { - if (!ignoreModifiers) { - log(ast, MSG_ACCESS); + if (isStateValid + && !ignoreModifiers + && !isForwardReference(modifiersAst.getParent())) { + log(modifiersAst, MSG_ACCESS); } } else { @@ -249,6 +310,51 @@ } } + /** + * Checks whether an identifier references a field which has been already defined in class. + * @param fieldDef a field definition. + * @return true if an identifier references a field which has been already defined in class. + */ + private boolean isForwardReference(DetailAST fieldDef) { + final DetailAST exprStartIdent = fieldDef.findFirstToken(TokenTypes.IDENT); + final Set exprIdents = getAllTokensOfType(exprStartIdent, TokenTypes.IDENT); + boolean forwardReference = false; + for (DetailAST ident : exprIdents) { + if (classFieldNames.contains(ident.getText())) { + forwardReference = true; + break; + } + } + return forwardReference; + } + + /** + * Collects all tokens of specific type starting with the current ast node. + * @param ast ast node. + * @param tokenType token type. + * @return a set of all tokens of specific type starting with the current ast node. + */ + private static Set getAllTokensOfType(DetailAST ast, int tokenType) { + DetailAST vertex = ast; + final Set result = new HashSet<>(); + final Deque stack = new ArrayDeque<>(); + while (vertex != null || !stack.isEmpty()) { + if (!stack.isEmpty()) { + vertex = stack.pop(); + } + while (vertex != null) { + if (vertex.getType() == tokenType && !vertex.equals(ast)) { + result.add(vertex); + } + if (vertex.getNextSibling() != null) { + stack.push(vertex.getNextSibling()); + } + vertex = vertex.getFirstChild(); + } + } + return result; + } + @Override public void leaveToken(DetailAST ast) { if (ast.getType() == TokenTypes.OBJBLOCK) { @@ -276,10 +382,13 @@ * Private class to encapsulate the state. */ private static class ScopeState { + /** The state the check is in. */ private int currentScopeState = STATE_STATIC_VARIABLE_DEF; /** The sub-state the check is in. */ private Scope declarationAccess = Scope.PUBLIC; + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/DefaultComesLastCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,10 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import java.util.Objects; + +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -41,7 +44,8 @@ * * @author o_sukhodolsky */ -public class DefaultComesLastCheck extends Check { +@StatelessCheck +public class DefaultComesLastCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -49,21 +53,39 @@ */ public static final String MSG_KEY = "default.comes.last"; + /** + * A key is pointing to the warning message text in "messages.properties" + * file. + */ + public static final String MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE = + "default.comes.last.in.casegroup"; + + /** Whether to process skipIfLastAndSharedWithCaseInSwitch() invocations. */ + private boolean skipIfLastAndSharedWithCase; + @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.LITERAL_DEFAULT, - }; + return getRequiredTokens(); } @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] { + TokenTypes.LITERAL_DEFAULT, + }; + } + + /** + * Whether to allow default keyword not in last but surrounded with case. + * @param newValue whether to ignore checking. + */ + public void setSkipIfLastAndSharedWithCase(boolean newValue) { + skipIfLastAndSharedWithCase = newValue; } @Override @@ -73,15 +95,41 @@ //interested in if (defaultGroupAST.getType() != TokenTypes.ANNOTATION_FIELD_DEF && defaultGroupAST.getType() != TokenTypes.MODIFIERS) { - final DetailAST switchAST = defaultGroupAST.getParent(); - final DetailAST lastGroupAST = - switchAST.getLastChild().getPreviousSibling(); - - if (defaultGroupAST.getLineNo() != lastGroupAST.getLineNo() - || defaultGroupAST.getColumnNo() - != lastGroupAST.getColumnNo()) { + if (skipIfLastAndSharedWithCase) { + if (Objects.nonNull(findNextSibling(ast, TokenTypes.LITERAL_CASE))) { + log(ast, MSG_KEY_SKIP_IF_LAST_AND_SHARED_WITH_CASE); + } + else if (ast.getPreviousSibling() == null + && Objects.nonNull(findNextSibling(defaultGroupAST, + TokenTypes.CASE_GROUP))) { + log(ast, MSG_KEY); + } + } + else if (Objects.nonNull(findNextSibling(defaultGroupAST, + TokenTypes.CASE_GROUP))) { log(ast, MSG_KEY); } } } + + /** + * Return token type only if passed tokenType in argument is found or returns -1. + * + * @param ast root node. + * @param tokenType tokentype to be processed. + * @return token if desired token is found or else null. + */ + private static DetailAST findNextSibling(DetailAST ast, int tokenType) { + DetailAST token = null; + DetailAST node = ast.getNextSibling(); + while (node != null) { + if (node.getType() == tokenType) { + token = node; + break; + } + node = node.getNextSibling(); + } + return token; + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EmptyStatementCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EmptyStatementCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EmptyStatementCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EmptyStatementCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -42,7 +43,8 @@ * * @author Rick Giles */ -public class EmptyStatementCheck extends Check { +@StatelessCheck +public class EmptyStatementCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -52,21 +54,22 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.EMPTY_STAT}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.EMPTY_STAT}; } @Override public void visitToken(DetailAST ast) { log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EqualsAvoidNullCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EqualsAvoidNullCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EqualsAvoidNullCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EqualsAvoidNullCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,10 +20,11 @@ package com.puppycrawl.tools.checkstyle.checks.coding; import java.util.Collections; +import java.util.HashSet; import java.util.Set; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -31,7 +32,7 @@ * Checks that any combination of String literals * is on the left side of an equals() comparison. * Also checks for String literals assigned to some field - * (such as someString.equals(anotherString = "text")). + * (such as {@code someString.equals(anotherString = "text")}). * *

      Rationale: Calling the equals() method on String literals * will avoid a potential NullPointerException. Also, it is @@ -58,7 +59,8 @@ * @author Travis Schneeberger * @author Vladislav Lisetskiy */ -public class EqualsAvoidNullCheck extends Check { +@FileStatefulCheck +public class EqualsAvoidNullCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -86,11 +88,16 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { return new int[] { TokenTypes.METHOD_CALL, TokenTypes.CLASS_DEF, @@ -111,11 +118,6 @@ }; } - @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); - } - /** * Whether to ignore checking {@code String.equalsIgnoreCase(String)}. * @param newValue whether to ignore checking @@ -160,7 +162,7 @@ && astType != TokenTypes.SLIST && astType != TokenTypes.LITERAL_NEW || astType == TokenTypes.LITERAL_NEW - && ast.branchContains(TokenTypes.LCURLY)) { + && ast.findFirstToken(TokenTypes.OBJBLOCK) != null) { currentFrame = currentFrame.getParent(); } else if (astType == TokenTypes.SLIST) { @@ -190,7 +192,7 @@ } /** - * Determine whether SLIST begins static or non-static block and + * Determine whether SLIST begins static or non-static block. * @param ast SLIST ast. */ private void leaveSlist(DetailAST ast) { @@ -241,7 +243,7 @@ * @param ast LITERAL_NEW ast. */ private void processLiteralNew(DetailAST ast) { - if (ast.branchContains(TokenTypes.LCURLY)) { + if (ast.findFirstToken(TokenTypes.OBJBLOCK) != null) { final FieldFrame frame = new FieldFrame(currentFrame); currentFrame.addChild(frame); currentFrame = frame; @@ -258,9 +260,7 @@ traverseFieldFrameTree(child); } currentFrame = child; - for (DetailAST methodCall: child.getMethodCalls()) { - checkMethodCall(methodCall); - } + child.getMethodCalls().forEach(this::checkMethodCall); } } @@ -337,7 +337,7 @@ * @param expr the argument expression * @return - true if any child matches the set of tokens, false if not */ - private boolean containsAllSafeTokens(final DetailAST expr) { + private static boolean containsAllSafeTokens(final DetailAST expr) { DetailAST arg = expr.getFirstChild(); arg = skipVariableAssign(arg); @@ -363,11 +363,12 @@ * @return the next relevant token */ private static DetailAST skipVariableAssign(final DetailAST currentAST) { + DetailAST result = currentAST; if (currentAST.getType() == TokenTypes.ASSIGN && currentAST.getFirstChild().getType() == TokenTypes.IDENT) { - return currentAST.getFirstChild().getNextSibling(); + result = currentAST.getFirstChild().getNextSibling(); } - return currentAST; + return result; } /** @@ -476,9 +477,18 @@ */ private static boolean checkLineNo(DetailAST field, DetailAST objCalledOn) { boolean result = false; + // Required for pitest coverage. We should specify columnNo passing condition + // in such a way, so that the minimal possible distance between field and + // objCalledOn will be the maximal condition to pass this check. + // The minimal distance between objCalledOn and field (of type String) initialization + // is calculated as follows: + // String(6) + space(1) + variableName(1) + assign(1) + + // anotherStringVariableName(1) + semicolon(1) = 11 + // Example: length of "String s=d;" is 11 symbols. + final int minimumSymbolsBetween = 11; if (field.getLineNo() < objCalledOn.getLineNo() || field.getLineNo() == objCalledOn.getLineNo() - && field.getColumnNo() < objCalledOn.getColumnNo()) { + && field.getColumnNo() + minimumSymbolsBetween <= objCalledOn.getColumnNo()) { result = true; } return result; @@ -503,17 +513,18 @@ * Holds the names of fields of a type. */ private static class FieldFrame { + /** Parent frame. */ private final FieldFrame parent; /** Set of frame's children. */ - private final Set children = Sets.newHashSet(); + private final Set children = new HashSet<>(); /** Set of fields. */ - private final Set fields = Sets.newHashSet(); + private final Set fields = new HashSet<>(); /** Set of equals calls. */ - private final Set methodCalls = Sets.newHashSet(); + private final Set methodCalls = new HashSet<>(); /** Name of the class, enum or enum constant declaration. */ private String frameName; @@ -607,12 +618,14 @@ * @return true if this FieldFrame contains instance field field. */ public DetailAST findField(String name) { + DetailAST resultField = null; for (DetailAST field: fields) { if (getFieldName(field).equals(name)) { - return field; + resultField = field; + break; } } - return null; + return resultField; } /** @@ -631,5 +644,7 @@ private static String getFieldName(DetailAST field) { return field.findFirstToken(TokenTypes.IDENT).getText(); } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EqualsHashCodeCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EqualsHashCodeCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EqualsHashCodeCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/EqualsHashCodeCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,20 +19,24 @@ package com.puppycrawl.tools.checkstyle.checks.coding; +import java.util.HashMap; import java.util.Map; -import java.util.Set; import antlr.collections.AST; - -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CheckUtils; /** *

      - * Checks that classes that override equals() also override hashCode(). + * Checks that classes that either override {@code equals()} or {@code hashCode()} also + * overrides the other. + * This checks only verifies that the method declarations match {@link Object#equals(Object)} and + * {@link Object#hashCode()} exactly to be considered an override. This check does not verify + * invalid method names, parameters other than {@code Object}, or anything else. *

      *

      * Rationale: The contract of equals() and hashCode() requires that @@ -48,8 +52,10 @@ * * @author lkuehne */ +@FileStatefulCheck public class EqualsHashCodeCheck - extends Check { + extends AbstractCheck { + // implementation note: we have to use the following members to // keep track of definitions in different inner classes @@ -57,91 +63,113 @@ * A key is pointing to the warning message text in "messages.properties" * file. */ - public static final String MSG_KEY = "equals.noHashCode"; + public static final String MSG_KEY_HASHCODE = "equals.noHashCode"; + + /** + * A key is pointing to the warning message text in "messages.properties" + * file. + */ + public static final String MSG_KEY_EQUALS = "equals.noEquals"; /** Maps OBJ_BLOCK to the method definition of equals(). */ - private final Map objBlockEquals = Maps.newHashMap(); + private final Map objBlockWithEquals = new HashMap<>(); - /** The set of OBJ_BLOCKs that contain a definition of hashCode(). */ - private final Set objBlockWithHashCode = Sets.newHashSet(); + /** Maps OBJ_BLOCKs to the method definition of hashCode(). */ + private final Map objBlockWithHashCode = new HashMap<>(); @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.METHOD_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.METHOD_DEF}; } @Override public void beginTree(DetailAST rootAST) { - objBlockEquals.clear(); + objBlockWithEquals.clear(); objBlockWithHashCode.clear(); } @Override public void visitToken(DetailAST ast) { + if (isEqualsMethod(ast)) { + objBlockWithEquals.put(ast.getParent(), ast); + } + else if (isHashCodeMethod(ast)) { + objBlockWithHashCode.put(ast.getParent(), ast); + } + } + + /** + * Determines if an AST is a valid Equals method implementation. + * + * @param ast the AST to check + * @return true if the {code ast} is a Equals method. + */ + private static boolean isEqualsMethod(DetailAST ast) { + final DetailAST modifiers = ast.getFirstChild(); + final DetailAST parameters = ast.findFirstToken(TokenTypes.PARAMETERS); + + return CheckUtils.isEqualsMethod(ast) + && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null + && isObjectParam(parameters.getFirstChild()) + && (ast.findFirstToken(TokenTypes.SLIST) != null + || modifiers.findFirstToken(TokenTypes.LITERAL_NATIVE) != null); + } + + /** + * Determines if an AST is a valid HashCode method implementation. + * + * @param ast the AST to check + * @return true if the {code ast} is a HashCode method. + */ + private static boolean isHashCodeMethod(DetailAST ast) { final DetailAST modifiers = ast.getFirstChild(); final AST type = ast.findFirstToken(TokenTypes.TYPE); final AST methodName = ast.findFirstToken(TokenTypes.IDENT); final DetailAST parameters = ast.findFirstToken(TokenTypes.PARAMETERS); - if (type.getFirstChild().getType() == TokenTypes.LITERAL_BOOLEAN - && "equals".equals(methodName.getText()) - && modifiers.branchContains(TokenTypes.LITERAL_PUBLIC) - && parameters.getChildCount() == 1 - && isObjectParam(parameters.getFirstChild()) - ) { - objBlockEquals.put(ast.getParent(), ast); - } - else if (type.getFirstChild().getType() == TokenTypes.LITERAL_INT + return type.getFirstChild().getType() == TokenTypes.LITERAL_INT && "hashCode".equals(methodName.getText()) - && modifiers.branchContains(TokenTypes.LITERAL_PUBLIC) - && parameters.getFirstChild() == null) { - objBlockWithHashCode.add(ast.getParent()); - } + && modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null + && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null + && parameters.getFirstChild() == null + && (ast.findFirstToken(TokenTypes.SLIST) != null + || modifiers.findFirstToken(TokenTypes.LITERAL_NATIVE) != null); } /** - * Determines if an AST is a formal param of type Object (or subclass). - * @param firstChild the AST to check - * @return true iff firstChild is a parameter of an Object type. + * Determines if an AST is a formal param of type Object. + * @param paramNode the AST to check + * @return true if firstChild is a parameter of an Object type. */ - private static boolean isObjectParam(AST firstChild) { - final AST modifiers = firstChild.getFirstChild(); - final AST type = modifiers.getNextSibling(); - switch (type.getFirstChild().getType()) { - case TokenTypes.LITERAL_BOOLEAN: - case TokenTypes.LITERAL_BYTE: - case TokenTypes.LITERAL_CHAR: - case TokenTypes.LITERAL_DOUBLE: - case TokenTypes.LITERAL_FLOAT: - case TokenTypes.LITERAL_INT: - case TokenTypes.LITERAL_LONG: - case TokenTypes.LITERAL_SHORT: - return false; - default: - return true; - } + private static boolean isObjectParam(DetailAST paramNode) { + final DetailAST typeNode = paramNode.findFirstToken(TokenTypes.TYPE); + final FullIdent fullIdent = FullIdent.createFullIdentBelow(typeNode); + final String name = fullIdent.getText(); + return "Object".equals(name) || "java.lang.Object".equals(name); } @Override public void finishTree(DetailAST rootAST) { - for (Map.Entry detailASTDetailASTEntry : objBlockEquals.entrySet()) { - if (!objBlockWithHashCode.contains(detailASTDetailASTEntry.getKey())) { + objBlockWithEquals + .entrySet().stream().filter(detailASTDetailASTEntry -> { + return objBlockWithHashCode.remove(detailASTDetailASTEntry.getKey()) == null; + }).forEach(detailASTDetailASTEntry -> { final DetailAST equalsAST = detailASTDetailASTEntry.getValue(); - log(equalsAST.getLineNo(), equalsAST.getColumnNo(), MSG_KEY); - } - } - - objBlockEquals.clear(); - objBlockWithHashCode.clear(); + log(equalsAST.getLineNo(), equalsAST.getColumnNo(), MSG_KEY_HASHCODE); + }); + objBlockWithHashCode.forEach((key, equalsAST) -> { + log(equalsAST.getLineNo(), equalsAST.getColumnNo(), MSG_KEY_EQUALS); + }); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ExplicitInitializationCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ExplicitInitializationCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ExplicitInitializationCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ExplicitInitializationCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CheckUtils; @@ -48,7 +49,8 @@ * * @author o_sukhodolsky */ -public class ExplicitInitializationCheck extends Check { +@StatelessCheck +public class ExplicitInitializationCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -56,47 +58,71 @@ */ public static final String MSG_KEY = "explicit.init"; + /** Whether only explicit initialization made to null should be checked.**/ + private boolean onlyObjectReferences; + @Override public final int[] getDefaultTokens() { - return new int[] {TokenTypes.VARIABLE_DEF}; + return getRequiredTokens(); } @Override public final int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] {TokenTypes.VARIABLE_DEF}; } @Override public final int[] getAcceptableTokens() { - return new int[] {TokenTypes.VARIABLE_DEF}; + return getRequiredTokens(); + } + + /** + * Sets whether only explicit initialization made to null should be checked. + * @param onlyObjectReferences whether only explicit initialization made to null + * should be checked + */ + public void setOnlyObjectReferences(boolean onlyObjectReferences) { + this.onlyObjectReferences = onlyObjectReferences; } @Override public void visitToken(DetailAST ast) { - if (isSkipCase(ast)) { - return; + if (!isSkipCase(ast)) { + final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN); + final DetailAST exprStart = + assign.getFirstChild().getFirstChild(); + final DetailAST type = ast.findFirstToken(TokenTypes.TYPE); + if (isObjectType(type) + && exprStart.getType() == TokenTypes.LITERAL_NULL) { + final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT); + log(ident, MSG_KEY, ident.getText(), "null"); + } + if (!onlyObjectReferences) { + validateNonObjects(ast); + } } + } + /** + * Checks for explicit initializations made to 'false', '0' and '\0'. + * @param ast token being checked for explicit initializations + */ + private void validateNonObjects(DetailAST ast) { final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT); final DetailAST assign = ast.findFirstToken(TokenTypes.ASSIGN); final DetailAST exprStart = - assign.getFirstChild().getFirstChild(); + assign.getFirstChild().getFirstChild(); final DetailAST type = ast.findFirstToken(TokenTypes.TYPE); - if (isObjectType(type) - && exprStart.getType() == TokenTypes.LITERAL_NULL) { - log(ident, MSG_KEY, ident.getText(), "null"); - } - final int primitiveType = type.getFirstChild().getType(); if (primitiveType == TokenTypes.LITERAL_BOOLEAN - && exprStart.getType() == TokenTypes.LITERAL_FALSE) { + && exprStart.getType() == TokenTypes.LITERAL_FALSE) { log(ident, MSG_KEY, ident.getText(), "false"); } if (isNumericType(primitiveType) && isZero(exprStart)) { log(ident, MSG_KEY, ident.getText(), "0"); } if (primitiveType == TokenTypes.LITERAL_CHAR - && isZeroChar(exprStart)) { + && isZeroChar(exprStart)) { log(ident, MSG_KEY, ident.getText(), "\\0"); } } @@ -113,7 +139,7 @@ } /** - * Checks for cases that should be skipped: no assignment, local variable, final variables + * Checks for cases that should be skipped: no assignment, local variable, final variables. * @param ast Variable def AST * @return true is that is a case that need to be skipped. */ @@ -128,7 +154,7 @@ if (assign != null) { final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); - skipCase = modifiers.branchContains(TokenTypes.FINAL); + skipCase = modifiers.findFirstToken(TokenTypes.FINAL) != null; } } return skipCase; @@ -161,21 +187,26 @@ } /** + * Checks if given node contains numeric constant for zero. + * * @param expr node to check. * @return true if given node contains numeric constant for zero. */ private static boolean isZero(DetailAST expr) { final int type = expr.getType(); + final boolean isZero; switch (type) { case TokenTypes.NUM_FLOAT: case TokenTypes.NUM_DOUBLE: case TokenTypes.NUM_INT: case TokenTypes.NUM_LONG: final String text = expr.getText(); - return Double.compare( - CheckUtils.parseDouble(text, type), 0.0) == 0; + isZero = Double.compare(CheckUtils.parseDouble(text, type), 0.0) == 0; + break; default: - return false; + isZero = false; } + return isZero; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/FallThroughCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/FallThroughCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/FallThroughCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/FallThroughCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,9 +22,11 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * Checks for fall through in switch statements @@ -67,7 +69,8 @@ * * @author o_sukhodolsky */ -public class FallThroughCheck extends Check { +@StatelessCheck +public class FallThroughCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -84,25 +87,22 @@ /** Do we need to check last case group. */ private boolean checkLastCaseGroup; - /** Relief pattern to allow fall through to the next case branch. */ - private String reliefPattern = "fallthru|falls? ?through"; - - /** Relief regexp. */ - private Pattern regExp; + /** Relief regexp to allow fall through to the next case branch. */ + private Pattern reliefPattern = Pattern.compile("fallthru|falls? ?through"); @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.CASE_GROUP}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] {TokenTypes.CASE_GROUP}; } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.CASE_GROUP}; + return getRequiredTokens(); } /** @@ -111,7 +111,7 @@ * @param pattern * The regular expression pattern. */ - public void setReliefPattern(String pattern) { + public void setReliefPattern(Pattern pattern) { reliefPattern = pattern; } @@ -124,29 +124,20 @@ } @Override - public void init() { - super.init(); - regExp = Pattern.compile(reliefPattern); - } - - @Override public void visitToken(DetailAST ast) { final DetailAST nextGroup = ast.getNextSibling(); final boolean isLastGroup = nextGroup.getType() != TokenTypes.CASE_GROUP; - if (isLastGroup && !checkLastCaseGroup) { - // we do not need to check last group - return; - } - - final DetailAST slist = ast.findFirstToken(TokenTypes.SLIST); + if (!isLastGroup || checkLastCaseGroup) { + final DetailAST slist = ast.findFirstToken(TokenTypes.SLIST); - if (slist != null && !isTerminated(slist, true, true) - && !hasFallThroughComment(ast, nextGroup)) { - if (isLastGroup) { - log(ast, MSG_FALL_THROUGH_LAST); - } - else { - log(nextGroup, MSG_FALL_THROUGH); + if (slist != null && !isTerminated(slist, true, true) + && !hasFallThroughComment(ast, nextGroup)) { + if (isLastGroup) { + log(ast, MSG_FALL_THROUGH_LAST); + } + else { + log(nextGroup, MSG_FALL_THROUGH); + } } } } @@ -191,6 +182,9 @@ case TokenTypes.LITERAL_SWITCH: terminated = checkSwitch(ast, useContinue); break; + case TokenTypes.LITERAL_SYNCHRONIZED: + terminated = checkSynchronized(ast, useBreak, useContinue); + break; default: terminated = false; } @@ -279,7 +273,13 @@ } if (!isTerminated) { - isTerminated = isTerminated(ast.getFirstChild(), + DetailAST firstChild = ast.getFirstChild(); + + if (firstChild.getType() == TokenTypes.RESOURCE_SPECIFICATION) { + firstChild = firstChild.getNextSibling(); + } + + isTerminated = isTerminated(firstChild, useBreak, useContinue); DetailAST catchStmt = ast.findFirstToken(TokenTypes.LITERAL_CATCH); @@ -315,6 +315,20 @@ } /** + * Checks if a given synchronized block terminated by return, throw or, + * if allowed break, continue. + * @param synchronizedAst synchronized block to check. + * @param useBreak should we consider break as terminator. + * @param useContinue should we consider continue as terminator. + * @return true if synchronized block is terminated. + */ + private boolean checkSynchronized(final DetailAST synchronizedAst, boolean useBreak, + boolean useContinue) { + return isTerminated( + synchronizedAst.findFirstToken(TokenTypes.SLIST), useBreak, useContinue); + } + + /** * Determines if the fall through case between {@code currentCase} and * {@code nextCase} is relieved by a appropriate comment. * @@ -342,7 +356,7 @@ // /+ FALLTHRU +/} // final String linePart = lines[endLineNo - 1].substring(0, endColNo); - if (matchesComment(regExp, linePart, endLineNo)) { + if (matchesComment(reliefPattern, linePart, endLineNo)) { allThroughComment = true; } else { @@ -359,8 +373,8 @@ // } final int startLineNo = currentCase.getLineNo(); for (int i = endLineNo - 2; i > startLineNo - 1; i--) { - if (!lines[i].trim().isEmpty()) { - allThroughComment = matchesComment(regExp, lines[i], i + 1); + if (!CommonUtils.isBlank(lines[i])) { + allThroughComment = matchesComment(reliefPattern, lines[i], i + 1); break; } } @@ -376,19 +390,16 @@ * @param lineNo The line number in the file. * @return True if a match was found inside a comment. */ - private boolean matchesComment(Pattern pattern, String line, int lineNo - ) { + private boolean matchesComment(Pattern pattern, String line, int lineNo) { final Matcher matcher = pattern.matcher(line); + boolean matches = false; - final boolean hit = matcher.find(); - - if (hit) { - final int startMatch = matcher.start(); + if (matcher.find()) { // -1 because it returns the char position beyond the match - final int endMatch = matcher.end() - 1; - return getFileContents().hasIntersectionWithComment(lineNo, - startMatch, lineNo, endMatch); + matches = getFileContents().hasIntersectionWithComment(lineNo, matcher.start(), + lineNo, matcher.end() - 1); } - return false; + return matches; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/FinalLocalVariableCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/FinalLocalVariableCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/FinalLocalVariableCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/FinalLocalVariableCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,8 +25,10 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Optional; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; @@ -46,7 +48,7 @@ * *

      * By default, this Check skip final validation on - * + * * Enhanced For-Loop *

      *

      @@ -73,7 +75,8 @@ * @author k_gibbs, r_auckenthaler * @author Vladislav Lisetskiy */ -public class FinalLocalVariableCheck extends Check { +@FileStatefulCheck +public class FinalLocalVariableCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -119,6 +122,10 @@ private final Deque> prevScopeUninitializedVariables = new ArrayDeque<>(); + /** Assigned variables of current scope. */ + private final Deque> currentScopeAssignedVariables = + new ArrayDeque<>(); + /** Controls whether to check enhanced for-loop variable. */ private boolean validateEnhancedForLoopVariable; @@ -144,6 +151,7 @@ TokenTypes.METHOD_DEF, TokenTypes.SLIST, TokenTypes.OBJBLOCK, + TokenTypes.LITERAL_BREAK, }; } @@ -155,6 +163,7 @@ TokenTypes.METHOD_DEF, TokenTypes.SLIST, TokenTypes.OBJBLOCK, + TokenTypes.LITERAL_BREAK, TokenTypes.VARIABLE_DEF, }; } @@ -167,11 +176,14 @@ TokenTypes.METHOD_DEF, TokenTypes.SLIST, TokenTypes.OBJBLOCK, + TokenTypes.LITERAL_BREAK, TokenTypes.VARIABLE_DEF, TokenTypes.PARAMETER_DEF, }; } + // -@cs[CyclomaticComplexity] The only optimization which can be done here is moving CASE-block + // expressions to separate methods, but that will not increase readability. @Override public void visitToken(DetailAST ast) { switch (ast.getType()) { @@ -181,6 +193,7 @@ scopeStack.push(new ScopeData()); break; case TokenTypes.SLIST: + currentScopeAssignedVariables.push(new ArrayDeque<>()); if (ast.getParent().getType() != TokenTypes.CASE_GROUP || ast.getParent().getParent().findFirstToken(TokenTypes.CASE_GROUP) == ast.getParent()) { @@ -190,29 +203,37 @@ break; case TokenTypes.PARAMETER_DEF: if (!isInLambda(ast) - && !ast.branchContains(TokenTypes.FINAL) + && ast.findFirstToken(TokenTypes.MODIFIERS) + .findFirstToken(TokenTypes.FINAL) == null && !isInAbstractOrNativeMethod(ast) - && !ScopeUtils.isInInterfaceBlock(ast)) { + && !ScopeUtils.isInInterfaceBlock(ast) + && !isMultipleTypeCatch(ast)) { insertParameter(ast); } break; case TokenTypes.VARIABLE_DEF: if (ast.getParent().getType() != TokenTypes.OBJBLOCK - && !ast.branchContains(TokenTypes.FINAL) + && ast.findFirstToken(TokenTypes.MODIFIERS) + .findFirstToken(TokenTypes.FINAL) == null && !isVariableInForInit(ast) && shouldCheckEnhancedForLoopVariable(ast)) { insertVariable(ast); } break; - case TokenTypes.IDENT: final int parentType = ast.getParent().getType(); - if (isAssignOperator(parentType) - && isFirstChild(ast)) { - removeVariable(ast); + if (isAssignOperator(parentType) && isFirstChild(ast)) { + final Optional candidate = getFinalCandidate(ast); + if (candidate.isPresent()) { + determineAssignmentConditions(ast, candidate.get()); + currentScopeAssignedVariables.peek().add(ast); + } + removeFinalVariableCandidateFromStack(ast); } break; - + case TokenTypes.LITERAL_BREAK: + scopeStack.peek().containsBreak = true; + break; default: throw new IllegalStateException("Incorrect token type"); } @@ -220,7 +241,7 @@ @Override public void leaveToken(DetailAST ast) { - Map scope = null; + Map scope = null; switch (ast.getType()) { case TokenTypes.OBJBLOCK: case TokenTypes.CTOR_DEF: @@ -228,27 +249,98 @@ scope = scopeStack.pop().scope; break; case TokenTypes.SLIST: - final Deque prevScopeUnitializedVariableData = + // -@cs[MoveVariableInsideIf] assignment value is modified later so it can't be + // moved + final Deque prevScopeUninitializedVariableData = prevScopeUninitializedVariables.peek(); + boolean containsBreak = false; if (ast.getParent().getType() != TokenTypes.CASE_GROUP || findLastChildWhichContainsSpecifiedToken(ast.getParent().getParent(), TokenTypes.CASE_GROUP, TokenTypes.SLIST) == ast.getParent()) { + containsBreak = scopeStack.peek().containsBreak; scope = scopeStack.pop().scope; prevScopeUninitializedVariables.pop(); } final DetailAST parent = ast.getParent(); - if (shouldUpdateUninitializedVariables(parent)) { - updateUninitializedVariables(prevScopeUnitializedVariableData); + if (containsBreak || shouldUpdateUninitializedVariables(parent)) { + updateAllUninitializedVariables(prevScopeUninitializedVariableData); } + updateCurrentScopeAssignedVariables(); break; default: // do nothing } if (scope != null) { - for (DetailAST node : scope.values()) { - log(node.getLineNo(), node.getColumnNo(), MSG_KEY, node.getText()); + for (FinalVariableCandidate candidate : scope.values()) { + final DetailAST ident = candidate.variableIdent; + log(ident.getLineNo(), ident.getColumnNo(), MSG_KEY, ident.getText()); + } + } + } + + /** + * Update assigned variables in a temporary stack. + */ + private void updateCurrentScopeAssignedVariables() { + // -@cs[MoveVariableInsideIf] assignment value is a modification call so it can't be moved + final Deque poppedScopeAssignedVariableData = + currentScopeAssignedVariables.pop(); + final Deque currentScopeAssignedVariableData = + currentScopeAssignedVariables.peek(); + if (currentScopeAssignedVariableData != null) { + currentScopeAssignedVariableData.addAll(poppedScopeAssignedVariableData); + } + } + + /** + * Determines identifier assignment conditions (assigned or already assigned). + * @param ident identifier. + * @param candidate final local variable candidate. + */ + private static void determineAssignmentConditions(DetailAST ident, + FinalVariableCandidate candidate) { + if (candidate.assigned) { + if (!isInSpecificCodeBlock(ident, TokenTypes.LITERAL_ELSE) + && !isInSpecificCodeBlock(ident, TokenTypes.CASE_GROUP)) { + candidate.alreadyAssigned = true; } } + else { + candidate.assigned = true; + } + } + + /** + * Checks whether the scope of a node is restricted to a specific code block. + * @param node node. + * @param blockType block type. + * @return true if the scope of a node is restricted to a specific code block. + */ + private static boolean isInSpecificCodeBlock(DetailAST node, int blockType) { + boolean returnValue = false; + for (DetailAST token = node.getParent(); token != null; token = token.getParent()) { + final int type = token.getType(); + if (type == blockType) { + returnValue = true; + break; + } + } + return returnValue; + } + + /** + * Gets final variable candidate for ast. + * @param ast ast. + * @return Optional of {@link FinalVariableCandidate} for ast from scopeStack. + */ + private Optional getFinalCandidate(DetailAST ast) { + Optional result = Optional.empty(); + final Iterator iterator = scopeStack.descendingIterator(); + while (iterator.hasNext() && !result.isPresent()) { + final ScopeData scopeData = iterator.next(); + result = scopeData.findFinalVariableCandidateForAst(ast); + } + return result; } /** @@ -256,40 +348,47 @@ */ private void storePrevScopeUninitializedVariableData() { final ScopeData scopeData = scopeStack.peek(); - final Deque prevScopeUnitializedVariableData = + final Deque prevScopeUninitializedVariableData = new ArrayDeque<>(); - for (DetailAST variable : scopeData.uninitializedVariables) { - prevScopeUnitializedVariableData.push(variable); - } - prevScopeUninitializedVariables.push(prevScopeUnitializedVariableData); + scopeData.uninitializedVariables.forEach(prevScopeUninitializedVariableData::push); + prevScopeUninitializedVariables.push(prevScopeUninitializedVariableData); } /** - * Update current scope data uninitialized variable according to the previous scope data. - * @param prevScopeUnitializedVariableData variable for previous stack of uninitialized + * Update current scope data uninitialized variable according to the whole scope data. + * @param prevScopeUninitializedVariableData variable for previous stack of uninitialized * variables + * @noinspection MethodParameterNamingConvention */ - private void updateUninitializedVariables(Deque - prevScopeUnitializedVariableData) { + private void updateAllUninitializedVariables( + Deque prevScopeUninitializedVariableData) { // Check for only previous scope - for (DetailAST variable : prevScopeUnitializedVariableData) { - for (ScopeData scopeData : scopeStack) { - final DetailAST storedVariable = scopeData.scope.get(variable.getText()); - if (storedVariable != null && isSameVariables(storedVariable, variable) - && !scopeData.uninitializedVariables.contains(storedVariable)) { - scopeData.uninitializedVariables.push(variable); - } - } - } + updateUninitializedVariables(prevScopeUninitializedVariableData); // Check for rest of the scope - for (Deque unitializedVariableData : prevScopeUninitializedVariables) { - for (DetailAST variable : unitializedVariableData) { + prevScopeUninitializedVariables.forEach(this::updateUninitializedVariables); + } + + /** + * Update current scope data uninitialized variable according to the specific scope data. + * @param scopeUninitializedVariableData variable for specific stack of uninitialized variables + */ + private void updateUninitializedVariables(Deque scopeUninitializedVariableData) { + final Iterator iterator = currentScopeAssignedVariables.peek().iterator(); + while (iterator.hasNext()) { + final DetailAST assignedVariable = iterator.next(); + for (DetailAST variable : scopeUninitializedVariableData) { for (ScopeData scopeData : scopeStack) { - final DetailAST storedVariable = scopeData.scope.get(variable.getText()); + final FinalVariableCandidate candidate = + scopeData.scope.get(variable.getText()); + DetailAST storedVariable = null; + if (candidate != null) { + storedVariable = candidate.variableIdent; + } if (storedVariable != null && isSameVariables(storedVariable, variable) - && !scopeData.uninitializedVariables.contains(storedVariable)) { + && isSameVariables(assignedVariable, variable)) { scopeData.uninitializedVariables.push(variable); + iterator.remove(); } } } @@ -297,16 +396,34 @@ } /** - * If token is LITERAL_TRY, LITERAL_CATCH, LITERAL_FINALLY, or LITERAL_ELSE, then do not - * update the uninitialized variables. + * If token is LITERAL_IF and there is an {@code else} following or token is CASE_GROUP and + * there is another {@code case} following, then update the uninitialized variables. * @param ast token to be checked * @return true if should be updated, else false */ - private boolean shouldUpdateUninitializedVariables(DetailAST ast) { - return ast.getType() != TokenTypes.LITERAL_TRY - && ast.getType() != TokenTypes.LITERAL_CATCH - && ast.getType() != TokenTypes.LITERAL_FINALLY - && ast.getType() != TokenTypes.LITERAL_ELSE; + private static boolean shouldUpdateUninitializedVariables(DetailAST ast) { + return isIfTokenWithAnElseFollowing(ast) || isCaseTokenWithAnotherCaseFollowing(ast); + } + + /** + * If token is LITERAL_IF and there is an {@code else} following. + * @param ast token to be checked + * @return true if token is LITERAL_IF and there is an {@code else} following, else false + */ + private static boolean isIfTokenWithAnElseFollowing(DetailAST ast) { + return ast.getType() == TokenTypes.LITERAL_IF + && ast.getLastChild().getType() == TokenTypes.LITERAL_ELSE; + } + + /** + * If token is CASE_GROUP and there is another {@code case} following. + * @param ast token to be checked + * @return true if token is CASE_GROUP and there is another {@code case} following, else false + */ + private static boolean isCaseTokenWithAnotherCaseFollowing(DetailAST ast) { + return ast.getType() == TokenTypes.CASE_GROUP + && findLastChildWhichContainsSpecifiedToken( + ast.getParent(), TokenTypes.CASE_GROUP, TokenTypes.SLIST) != ast; } /** @@ -317,12 +434,13 @@ * @param containType the token type which has to be present in the branch * @return the matching token, or null if no match */ - public DetailAST findLastChildWhichContainsSpecifiedToken(DetailAST ast, int childType, - int containType) { + private static DetailAST findLastChildWhichContainsSpecifiedToken(DetailAST ast, int childType, + int containType) { DetailAST returnValue = null; for (DetailAST astIterator = ast.getFirstChild(); astIterator != null; astIterator = astIterator.getNextSibling()) { - if (astIterator.getType() == childType && astIterator.branchContains(containType)) { + if (astIterator.getType() == childType + && astIterator.findFirstToken(containType) != null) { returnValue = astIterator; } } @@ -344,9 +462,9 @@ * @param ast the variable to insert. */ private void insertParameter(DetailAST ast) { - final Map scope = scopeStack.peek().scope; + final Map scope = scopeStack.peek().scope; final DetailAST astNode = ast.findFirstToken(TokenTypes.IDENT); - scope.put(astNode.getText(), astNode); + scope.put(astNode.getText(), new FinalVariableCandidate(astNode)); } /** @@ -354,9 +472,9 @@ * @param ast the variable to insert. */ private void insertVariable(DetailAST ast) { - final Map scope = scopeStack.peek().scope; + final Map scope = scopeStack.peek().scope; final DetailAST astNode = ast.findFirstToken(TokenTypes.IDENT); - scope.put(astNode.getText(), astNode); + scope.put(astNode.getText(), new FinalVariableCandidate(astNode)); if (!isInitialized(astNode)) { scopeStack.peek().uninitializedVariables.add(astNode); } @@ -381,17 +499,21 @@ } /** - * Remove the variable from the Stack. - * @param ast Variable to remove + * Removes the final variable candidate from the Stack. + * @param ast variable to remove. */ - private void removeVariable(DetailAST ast) { + private void removeFinalVariableCandidateFromStack(DetailAST ast) { final Iterator iterator = scopeStack.descendingIterator(); while (iterator.hasNext()) { final ScopeData scopeData = iterator.next(); - final Map scope = scopeData.scope; - final DetailAST storedVariable = scope.get(ast.getText()); + final Map scope = scopeData.scope; + final FinalVariableCandidate candidate = scope.get(ast.getText()); + DetailAST storedVariable = null; + if (candidate != null) { + storedVariable = candidate.variableIdent; + } if (storedVariable != null && isSameVariables(storedVariable, ast)) { - if (shouldRemoveVariable(scopeData, ast)) { + if (shouldRemoveFinalVariableCandidate(scopeData, ast)) { scope.remove(ast.getText()); } break; @@ -400,22 +522,32 @@ } /** - * Whether the variable should be removed from the list of final local variable + * Check if given parameter definition is a multiple type catch. + * @param parameterDefAst parameter definition + * @return true if it is a multiple type catch, false otherwise + */ + private static boolean isMultipleTypeCatch(DetailAST parameterDefAst) { + final DetailAST typeAst = parameterDefAst.findFirstToken(TokenTypes.TYPE); + return typeAst.getFirstChild().getType() == TokenTypes.BOR; + } + + /** + * Whether the final variable candidate should be removed from the list of final local variable * candidates. * @param scopeData the scope data of the variable. * @param ast the variable ast. * @return true, if the variable should be removed. */ - private static boolean shouldRemoveVariable(ScopeData scopeData, DetailAST ast) { + private static boolean shouldRemoveFinalVariableCandidate(ScopeData scopeData, DetailAST ast) { boolean shouldRemove = true; for (DetailAST variable : scopeData.uninitializedVariables) { if (variable.getText().equals(ast.getText())) { - // if the variable is declared outside the loop and initialized inside // the loop, then it cannot be declared final, as it can be initialized // more than once in this case - if (isInTheSameLoop(variable, ast)) { - shouldRemove = false; + if (isInTheSameLoop(variable, ast) || !isUseOfExternalVariableInsideLoop(ast)) { + final FinalVariableCandidate candidate = scopeData.scope.get(ast.getText()); + shouldRemove = candidate.alreadyAssigned; } scopeData.uninitializedVariables.remove(variable); break; @@ -425,6 +557,29 @@ } /** + * Checks whether a variable which is declared outside loop is used inside loop. + * For example: + *

      + * {@code + * int x; + * for (int i = 0, j = 0; i < j; i++) { + * x = 5; + * } + * } + *

      + * @param variable variable. + * @return true if a variable which is declared outside loop is used inside loop. + */ + private static boolean isUseOfExternalVariableInsideLoop(DetailAST variable) { + DetailAST loop2 = variable.getParent(); + while (loop2 != null + && !isLoopAst(loop2.getType())) { + loop2 = loop2.getParent(); + } + return loop2 != null; + } + + /** * Is Arithmetic operator. * @param parentType token AST * @return true is token type is in arithmetic operator @@ -461,8 +616,8 @@ if (parent.getType() == TokenTypes.METHOD_DEF) { final DetailAST modifiers = parent.findFirstToken(TokenTypes.MODIFIERS); - abstractOrNative = modifiers.branchContains(TokenTypes.ABSTRACT) - || modifiers.branchContains(TokenTypes.LITERAL_NATIVE); + abstractOrNative = modifiers.findFirstToken(TokenTypes.ABSTRACT) != null + || modifiers.findFirstToken(TokenTypes.LITERAL_NATIVE) != null; } parent = parent.getParent(); } @@ -479,7 +634,7 @@ } /** - * Find the Class, Constructor, Enum or Method in which it is defined. + * Find the Class, Constructor, Enum, Method, or Field in which it is defined. * @param ast Variable for which we want to find the scope in which it is defined * @return ast The Class or Constructor or Method in which it is defined. */ @@ -488,7 +643,8 @@ while (astTraverse.getType() != TokenTypes.METHOD_DEF && astTraverse.getType() != TokenTypes.CLASS_DEF && astTraverse.getType() != TokenTypes.ENUM_DEF - && astTraverse.getType() != TokenTypes.CTOR_DEF) { + && astTraverse.getType() != TokenTypes.CTOR_DEF + && !ScopeUtils.isClassFieldDef(astTraverse)) { astTraverse = astTraverse.getParent(); } return astTraverse; @@ -505,7 +661,7 @@ findFirstUpperNamedBlock(ast1); final DetailAST classOrMethodOfAst2 = findFirstUpperNamedBlock(ast2); - return classOrMethodOfAst1 == classOrMethodOfAst2; + return classOrMethodOfAst1 == classOrMethodOfAst2 && ast1.getText().equals(ast2.getText()); } /** @@ -523,8 +679,7 @@ while (loop2 != null && !isLoopAst(loop2.getType())) { loop2 = loop2.getParent(); } - return loop1 == null && loop2 == null - || loop1 != null && loop1 == loop2; + return loop1 != null && loop1 == loop2; } /** @@ -540,10 +695,55 @@ * Holder for the scope data. */ private static class ScopeData { + /** Contains variable definitions. */ - private final Map scope = new HashMap<>(); + private final Map scope = new HashMap<>(); /** Contains definitions of uninitialized variables. */ private final Deque uninitializedVariables = new ArrayDeque<>(); + + /** Whether there is a {@code break} in the scope. */ + private boolean containsBreak; + + /** + * Searches for final local variable candidate for ast in the scope. + * @param ast ast. + * @return Optional of {@link FinalVariableCandidate}. + */ + public Optional findFinalVariableCandidateForAst(DetailAST ast) { + Optional result = Optional.empty(); + DetailAST storedVariable = null; + final Optional candidate = + Optional.ofNullable(scope.get(ast.getText())); + if (candidate.isPresent()) { + storedVariable = candidate.get().variableIdent; + } + if (storedVariable != null && isSameVariables(storedVariable, ast)) { + result = candidate; + } + return result; + } + + } + + /**Represents information about final local variable candidate. */ + private static class FinalVariableCandidate { + + /** Identifier token. */ + private final DetailAST variableIdent; + /** Whether the variable is assigned. */ + private boolean assigned; + /** Whether the variable is already assigned. */ + private boolean alreadyAssigned; + + /** + * Creates new instance. + * @param variableIdent variable identifier. + */ + FinalVariableCandidate(DetailAST variableIdent) { + this.variableIdent = variableIdent; + } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/HiddenFieldCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,17 +19,18 @@ package com.puppycrawl.tools.checkstyle.checks.coding; +import java.util.HashSet; import java.util.Locale; import java.util.Objects; import java.util.Set; import java.util.regex.Pattern; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.Scope; import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; +import com.puppycrawl.tools.checkstyle.utils.CheckUtils; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; /** @@ -128,8 +129,10 @@ * * @author Dmitri Priimak */ +@FileStatefulCheck public class HiddenFieldCheck - extends Check { + extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -142,7 +145,7 @@ private FieldFrame frame; /** Pattern for names of variables and parameters to ignore. */ - private Pattern regexp; + private Pattern ignoreFormat; /** Controls whether to check the parameter of a property setter method. */ private boolean ignoreSetter; @@ -219,7 +222,8 @@ final DetailAST firstChild = ast.getFirstChild(); if (firstChild.getType() == TokenTypes.IDENT) { final String untypedLambdaParameterName = firstChild.getText(); - if (isStaticOrInstanceField(firstChild, untypedLambdaParameterName)) { + if (frame.containsStaticField(untypedLambdaParameterName) + || isInstanceField(firstChild, untypedLambdaParameterName)) { log(firstChild, MSG_KEY, untypedLambdaParameterName); } } @@ -245,7 +249,7 @@ final DetailAST typeMods = ast.findFirstToken(TokenTypes.MODIFIERS); final boolean isStaticInnerType = typeMods != null - && typeMods.branchContains(TokenTypes.LITERAL_STATIC); + && typeMods.findFirstToken(TokenTypes.LITERAL_STATIC) != null; final String frameName; if (type == TokenTypes.CLASS_DEF || type == TokenTypes.ENUM_DEF) { @@ -267,11 +271,11 @@ child.findFirstToken(TokenTypes.IDENT).getText(); final DetailAST mods = child.findFirstToken(TokenTypes.MODIFIERS); - if (mods.branchContains(TokenTypes.LITERAL_STATIC)) { - newFrame.addStaticField(name); + if (mods.findFirstToken(TokenTypes.LITERAL_STATIC) == null) { + newFrame.addInstanceField(name); } else { - newFrame.addInstanceField(name); + newFrame.addStaticField(name); } } child = child.getNextSibling(); @@ -299,14 +303,14 @@ */ private void processVariable(DetailAST ast) { if (!ScopeUtils.isInInterfaceOrAnnotationBlock(ast) + && !CheckUtils.isReceiverParameter(ast) && (ScopeUtils.isLocalVariableDef(ast) || ast.getType() == TokenTypes.PARAMETER_DEF)) { // local variable or parameter. Does it shadow a field? final DetailAST nameAST = ast.findFirstToken(TokenTypes.IDENT); final String name = nameAST.getText(); - if ((isStaticFieldHiddenFromAnonymousClass(ast, name) - || isStaticOrInstanceField(ast, name)) + if ((frame.containsStaticField(name) || isInstanceField(ast, name)) && !isMatchingRegexp(name) && !isIgnoredParam(ast, name)) { log(nameAST, MSG_KEY, name); @@ -315,17 +319,6 @@ } /** - * Checks whether a static field is hidden from closure. - * @param nameAST local variable or parameter. - * @param name field name. - * @return true if static field is hidden from closure. - */ - private boolean isStaticFieldHiddenFromAnonymousClass(DetailAST nameAST, String name) { - return isInStatic(nameAST) - && frame.containsStaticField(name); - } - - /** * Checks whether method or constructor parameter is ignored. * @param ast the parameter token. * @param name the parameter name. @@ -338,14 +331,13 @@ } /** - * Check for static or instance field. + * Check for instance field. * @param ast token * @param name identifier of token - * @return true if static or instance field + * @return true if instance field */ - private boolean isStaticOrInstanceField(DetailAST ast, String name) { - return frame.containsStaticField(name) - || !isInStatic(ast) && frame.containsInstanceField(name); + private boolean isInstanceField(DetailAST ast, String name) { + return !isInStatic(ast) && frame.containsInstanceField(name); } /** @@ -354,7 +346,7 @@ * @return true is regexp is matching */ private boolean isMatchingRegexp(String name) { - return regexp != null && regexp.matcher(name).find(); + return ignoreFormat != null && ignoreFormat.matcher(name).find(); } /** @@ -376,7 +368,7 @@ || parent.getType() == TokenTypes.VARIABLE_DEF) { final DetailAST mods = parent.findFirstToken(TokenTypes.MODIFIERS); - inStatic = mods.branchContains(TokenTypes.LITERAL_STATIC); + inStatic = mods.findFirstToken(TokenTypes.LITERAL_STATIC) != null; break; } else { @@ -393,7 +385,7 @@ * (default behavior) or return type is name of the class in which * such method is declared (allowed only if * {@link #setSetterCanReturnItsClass(boolean)} is called with - * value true) + * value true). * * @param ast the AST to check. * @param name the name of ast. @@ -401,16 +393,17 @@ * ignoreSetter is true and ast is the parameter of a setter method. */ private boolean isIgnoredSetterParam(DetailAST ast, String name) { + boolean isIgnoredSetterParam = false; if (ignoreSetter && ast.getType() == TokenTypes.PARAMETER_DEF) { final DetailAST parametersAST = ast.getParent(); final DetailAST methodAST = parametersAST.getParent(); if (parametersAST.getChildCount() == 1 && methodAST.getType() == TokenTypes.METHOD_DEF && isSetterMethod(methodAST, name)) { - return true; + isIgnoredSetterParam = true; } } - return false; + return isIgnoredSetterParam; } /** @@ -433,7 +426,7 @@ // therefore this method is potentially a setter final DetailAST typeAST = aMethodAST.findFirstToken(TokenTypes.TYPE); final String returnType = typeAST.getFirstChild().getText(); - if (typeAST.branchContains(TokenTypes.LITERAL_VOID) + if (typeAST.findFirstToken(TokenTypes.LITERAL_VOID) != null || setterCanReturnItsClass && frame.isEmbeddedIn(returnType)) { // this method has signature // @@ -502,18 +495,18 @@ final DetailAST method = ast.getParent().getParent(); if (method.getType() == TokenTypes.METHOD_DEF) { final DetailAST mods = method.findFirstToken(TokenTypes.MODIFIERS); - result = mods.branchContains(TokenTypes.ABSTRACT); + result = mods.findFirstToken(TokenTypes.ABSTRACT) != null; } } return result; } /** - * Set the ignore format to the specified regular expression. - * @param format a {@code String} value + * Set the ignore format for the specified regular expression. + * @param pattern a pattern. */ - public void setIgnoreFormat(String format) { - regexp = CommonUtils.createPattern(format); + public void setIgnoreFormat(Pattern pattern) { + ignoreFormat = pattern; } /** @@ -565,6 +558,7 @@ * @author Rick Giles */ private static class FieldFrame { + /** Name of the frame, such name of the class or enum declaration. */ private final String frameName; @@ -575,10 +569,10 @@ private final FieldFrame parent; /** Set of instance field names. */ - private final Set instanceFields = Sets.newHashSet(); + private final Set instanceFields = new HashSet<>(); /** Set of static field names. */ - private final Set staticFields = Sets.newHashSet(); + private final Set staticFields = new HashSet<>(); /** * Creates new frame. @@ -618,7 +612,6 @@ || parent != null && !staticType && parent.containsInstanceField(field); - } /** @@ -652,13 +645,17 @@ */ private boolean isEmbeddedIn(String classOrEnumName) { FieldFrame currentFrame = this; + boolean isEmbeddedIn = false; while (currentFrame != null) { if (Objects.equals(currentFrame.frameName, classOrEnumName)) { - return true; + isEmbeddedIn = true; + break; } currentFrame = currentFrame.parent; } - return false; + return isEmbeddedIn; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalCatchCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalCatchCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalCatchCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalCatchCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,15 +19,18 @@ package com.puppycrawl.tools.checkstyle.checks.coding; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CheckUtils; /** * Catching java.lang.Exception, java.lang.Error or java.lang.RuntimeException @@ -35,7 +38,8 @@ * @author Simon Harris * @author Ilja Dubinin */ -public final class IllegalCatchCheck extends Check { +@StatelessCheck +public final class IllegalCatchCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -44,9 +48,9 @@ public static final String MSG_KEY = "illegal.catch"; /** Illegal class names. */ - private final Set illegalClassNames = Sets.newHashSet("Exception", "Error", - "RuntimeException", "Throwable", "java.lang.Error", "java.lang.Exception", - "java.lang.RuntimeException", "java.lang.Throwable"); + private final Set illegalClassNames = Arrays.stream(new String[] {"Exception", "Error", + "RuntimeException", "Throwable", "java.lang.Error", "java.lang.Exception", + "java.lang.RuntimeException", "java.lang.Throwable", }).collect(Collectors.toSet()); /** * Set the list of illegal classes. @@ -56,30 +60,23 @@ */ public void setIllegalClassNames(final String... classNames) { illegalClassNames.clear(); - for (final String name : classNames) { - illegalClassNames.add(name); - final int lastDot = name.lastIndexOf('.'); - if (lastDot > 0 && lastDot < name.length() - 1) { - final String shortName = name - .substring(name.lastIndexOf('.') + 1); - illegalClassNames.add(shortName); - } - } + illegalClassNames.addAll( + CheckUtils.parseClassNames(classNames)); } @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.LITERAL_CATCH}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] {TokenTypes.LITERAL_CATCH}; } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.LITERAL_CATCH}; + return getRequiredTokens(); } @Override @@ -125,4 +122,5 @@ } return exceptionTypes; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalInstantiationCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalInstantiationCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalInstantiationCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalInstantiationCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,13 +19,14 @@ package com.puppycrawl.tools.checkstyle.checks.coding; +import java.util.Arrays; +import java.util.HashSet; import java.util.Set; -import java.util.StringTokenizer; +import java.util.stream.Collectors; import antlr.collections.AST; - -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -61,8 +62,9 @@ * * @author lkuehne */ +@FileStatefulCheck public class IllegalInstantiationCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -70,20 +72,20 @@ */ public static final String MSG_KEY = "instantiation.avoid"; - /** {@link java.lang} package as string */ + /** {@link java.lang} package as string. */ private static final String JAVA_LANG = "java.lang."; - /** Set of fully qualified class names. E.g. "java.lang.Boolean" */ - private final Set illegalClasses = Sets.newHashSet(); - /** The imports for the file. */ - private final Set imports = Sets.newHashSet(); + private final Set imports = new HashSet<>(); /** The class names defined in the file. */ - private final Set classNames = Sets.newHashSet(); + private final Set classNames = new HashSet<>(); /** The instantiations in the file. */ - private final Set instantiations = Sets.newHashSet(); + private final Set instantiations = new HashSet<>(); + + /** Set of fully qualified class names. E.g. "java.lang.Boolean" */ + private Set classes = new HashSet<>(); /** Name of the package. */ private String pkgName; @@ -114,7 +116,6 @@ @Override public void beginTree(DetailAST rootAST) { - super.beginTree(rootAST); pkgName = null; imports.clear(); instantiations.clear(); @@ -143,9 +144,7 @@ @Override public void finishTree(DetailAST rootAST) { - for (DetailAST literalNewAST : instantiations) { - postProcessLiteralNew(literalNewAST); - } + instantiations.forEach(this::postProcessLiteralNew); } /** @@ -201,18 +200,16 @@ private void postProcessLiteralNew(DetailAST newTokenAst) { final DetailAST typeNameAst = newTokenAst.getFirstChild(); final AST nameSibling = typeNameAst.getNextSibling(); - if (nameSibling.getType() == TokenTypes.ARRAY_DECLARATOR) { - // ast == "new Boolean[]" - return; - } - - final FullIdent typeIdent = FullIdent.createFullIdent(typeNameAst); - final String typeName = typeIdent.getText(); - final int lineNo = newTokenAst.getLineNo(); - final int colNo = newTokenAst.getColumnNo(); - final String fqClassName = getIllegalInstantiation(typeName); - if (fqClassName != null) { - log(lineNo, colNo, MSG_KEY, fqClassName); + if (nameSibling.getType() != TokenTypes.ARRAY_DECLARATOR) { + // ast != "new Boolean[]" + final FullIdent typeIdent = FullIdent.createFullIdent(typeNameAst); + final String typeName = typeIdent.getText(); + final String fqClassName = getIllegalInstantiation(typeName); + if (fqClassName != null) { + final int lineNo = newTokenAst.getLineNo(); + final int colNo = newTokenAst.getColumnNo(); + log(lineNo, colNo, MSG_KEY, fqClassName); + } } } @@ -225,7 +222,7 @@ private String getIllegalInstantiation(String className) { String fullClassName = null; - if (illegalClasses.contains(className)) { + if (classes.contains(className)) { fullClassName = className; } else { @@ -238,7 +235,7 @@ pkgNameLen = pkgName.length(); } - for (String illegal : illegalClasses) { + for (String illegal : classes) { if (isStandardClass(className, illegal) || isSamePackage(className, pkgNameLen, illegal)) { fullClassName = illegal; @@ -259,7 +256,6 @@ * Check import statements. * @param className name of the class * @return value of illegal instantiated type - * @noinspection StringContatenationInLoop */ private String checkImportStatements(String className) { String illegalType = null; @@ -271,7 +267,7 @@ + className; } if (CommonUtils.baseClassName(importArg).equals(className) - && illegalClasses.contains(importArg)) { + && classes.contains(importArg)) { illegalType = importArg; break; } @@ -331,6 +327,7 @@ * @return true if type is standard */ private boolean isStandardClass(String className, String illegal) { + boolean isStandardClass = false; // class from java.lang if (illegal.length() - JAVA_LANG.length() == className.length() && illegal.endsWith(className) @@ -345,21 +342,18 @@ final boolean isSamePackage = isSamePackage(className); if (!isSameFile && !isSamePackage) { - return true; + isStandardClass = true; } } - return false; + return isStandardClass; } /** * Sets the classes that are illegal to instantiate. * @param names a comma separate list of class names */ - public void setClasses(String names) { - illegalClasses.clear(); - final StringTokenizer tok = new StringTokenizer(names, ","); - while (tok.hasMoreTokens()) { - illegalClasses.add(tok.nextToken()); - } + public void setClasses(String... names) { + classes = Arrays.stream(names).collect(Collectors.toSet()); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalThrowsCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalThrowsCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalThrowsCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalThrowsCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,15 +19,18 @@ package com.puppycrawl.tools.checkstyle.checks.coding; +import java.util.Arrays; import java.util.Collections; import java.util.Set; +import java.util.stream.Collectors; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.AnnotationUtility; +import com.puppycrawl.tools.checkstyle.utils.CheckUtils; /** *

      @@ -50,7 +53,8 @@ * @author John Sirois * @author Aleksey Nesterenko */ -public final class IllegalThrowsCheck extends Check { +@StatelessCheck +public final class IllegalThrowsCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -59,11 +63,14 @@ public static final String MSG_KEY = "illegal.throw"; /** Methods which should be ignored. */ - private final Set ignoredMethodNames = Sets.newHashSet("finalize"); + private final Set ignoredMethodNames = + Arrays.stream(new String[] {"finalize", }).collect(Collectors.toSet()); /** Illegal class names. */ - private final Set illegalClassNames = Sets.newHashSet("Error", "RuntimeException", - "Throwable", "java.lang.Error", "java.lang.RuntimeException", "java.lang.Throwable"); + private final Set illegalClassNames = Arrays.stream( + new String[] {"Error", "RuntimeException", "Throwable", "java.lang.Error", + "java.lang.RuntimeException", "java.lang.Throwable", }) + .collect(Collectors.toSet()); /** Property for ignoring overridden methods. */ private boolean ignoreOverriddenMethods = true; @@ -76,38 +83,31 @@ */ public void setIllegalClassNames(final String... classNames) { illegalClassNames.clear(); - for (final String name : classNames) { - illegalClassNames.add(name); - final int lastDot = name.lastIndexOf('.'); - if (lastDot > 0 && lastDot < name.length() - 1) { - final String shortName = name - .substring(name.lastIndexOf('.') + 1); - illegalClassNames.add(shortName); - } - } + illegalClassNames.addAll( + CheckUtils.parseClassNames(classNames)); } @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.LITERAL_THROWS}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] {TokenTypes.LITERAL_THROWS}; } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.LITERAL_THROWS}; + return getRequiredTokens(); } @Override public void visitToken(DetailAST detailAST) { final DetailAST methodDef = detailAST.getParent(); - DetailAST token = detailAST.getFirstChild(); // Check if the method with the given name should be ignored. if (!isIgnorableMethod(methodDef)) { + DetailAST token = detailAST.getFirstChild(); while (token != null) { if (token.getType() != TokenTypes.COMMA) { final FullIdent ident = FullIdent.createFullIdent(token); @@ -157,4 +157,5 @@ public void setIgnoreOverriddenMethods(boolean ignoreOverriddenMethods) { this.ignoreOverriddenMethods = ignoreOverriddenMethods; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTokenCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTokenCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTokenCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTokenCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,11 +19,12 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; +import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; import com.puppycrawl.tools.checkstyle.utils.TokenUtils; /** @@ -53,8 +54,9 @@ * @author Simon Harris * @author Rick Giles */ +@StatelessCheck public class IllegalTokenCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -76,7 +78,12 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; + } + + @Override + public boolean isCommentNodesRequired() { + return true; } @Override @@ -96,11 +103,17 @@ */ private static String convertToString(DetailAST ast) { final String tokenText; - if (ast.getType() == TokenTypes.LABELED_STAT) { - tokenText = ast.getFirstChild().getText() + ast.getText(); - } - else { - tokenText = ast.getText(); + switch (ast.getType()) { + case TokenTypes.LABELED_STAT: + tokenText = ast.getFirstChild().getText() + ast.getText(); + break; + // multiline tokens need to become singlelined + case TokenTypes.COMMENT_CONTENT: + tokenText = JavadocUtils.escapeAllControlChars(ast.getText()); + break; + default: + tokenText = ast.getText(); + break; } return tokenText; } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTokenTextCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTokenTextCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTokenTextCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTokenTextCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,12 +21,11 @@ import java.util.regex.Pattern; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; -import com.puppycrawl.tools.checkstyle.utils.TokenUtils; /** *

      @@ -53,8 +52,9 @@ * * @author Rick Giles */ +@StatelessCheck public class IllegalTokenTextCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -69,33 +69,47 @@ private String message = ""; /** The format string of the regexp. */ - private String format = "$^"; + private String formatString = "$^"; /** The regexp to match against. */ - private Pattern regexp = Pattern.compile(format); + private Pattern format = Pattern.compile(formatString); - /** The flags to use with the regexp. */ - private int compileFlags; + /** {@code true} if the casing should be ignored. */ + private boolean ignoreCase; @Override public int[] getDefaultTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override public int[] getAcceptableTokens() { - return TokenUtils.getAllTokenIds(); + return new int[] { + TokenTypes.NUM_DOUBLE, + TokenTypes.NUM_FLOAT, + TokenTypes.NUM_INT, + TokenTypes.NUM_LONG, + TokenTypes.IDENT, + TokenTypes.COMMENT_CONTENT, + TokenTypes.STRING_LITERAL, + TokenTypes.CHAR_LITERAL, + }; } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; + } + + @Override + public boolean isCommentNodesRequired() { + return true; } @Override public void visitToken(DetailAST ast) { final String text = ast.getText(); - if (regexp.matcher(text).find()) { + if (format.matcher(text).find()) { String customMessage = message; if (customMessage.isEmpty()) { customMessage = MSG_KEY; @@ -104,7 +118,7 @@ ast.getLineNo(), ast.getColumnNo(), customMessage, - format); + formatString); } } @@ -128,30 +142,33 @@ * @throws org.apache.commons.beanutils.ConversionException unable to parse format */ public void setFormat(String format) { - this.format = format; + formatString = format; updateRegexp(); } /** * Set whether or not the match is case sensitive. * @param caseInsensitive true if the match is case insensitive. + * @noinspection BooleanParameter */ public void setIgnoreCase(boolean caseInsensitive) { - if (caseInsensitive) { - compileFlags = Pattern.CASE_INSENSITIVE; - } - else { - compileFlags = 0; - } - + ignoreCase = caseInsensitive; updateRegexp(); } /** - * Updates the {@link #regexp} based on the values from {@link #format} and - * {@link #compileFlags}. + * Updates the {@link #format} based on the values from {@link #formatString} and + * {@link #ignoreCase}. */ private void updateRegexp() { - regexp = CommonUtils.createPattern(format, compileFlags); + final int compileFlags; + if (ignoreCase) { + compileFlags = Pattern.CASE_INSENSITIVE; + } + else { + compileFlags = 0; + } + format = CommonUtils.createPattern(formatString, compileFlags); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTypeCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTypeCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTypeCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/IllegalTypeCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,17 +21,16 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Pattern; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CheckUtils; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.TokenUtils; /** @@ -50,7 +49,7 @@ *

      illegalClassNames - Classes that should not be used as types in variable declarations, return values or parameters. * It is possible to set illegal class names via short or - * + * * canonical name. * Specifying illegal type invokes analyzing imports and Check puts violations at * corresponding declarations @@ -91,7 +90,7 @@ * @author Aleksey Nesterenko * @author Andrei Selkin */ -public final class IllegalTypeCheck extends Check { +public final class IllegalTypeCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -99,8 +98,6 @@ */ public static final String MSG_KEY = "illegal.type"; - /** Abstract classes legal by default. */ - private static final String[] DEFAULT_LEGAL_ABSTRACT_NAMES = {}; /** Types illegal by default. */ private static final String[] DEFAULT_ILLEGAL_TYPES = { "HashSet", @@ -124,19 +121,18 @@ }; /** Illegal classes. */ - private final Set illegalClassNames = Sets.newHashSet(); + private final Set illegalClassNames = new HashSet<>(); + /** Illegal short classes. */ + private final Set illegalShortClassNames = new HashSet<>(); /** Legal abstract classes. */ - private final Set legalAbstractClassNames = Sets.newHashSet(); + private final Set legalAbstractClassNames = new HashSet<>(); /** Methods which should be ignored. */ - private final Set ignoredMethodNames = Sets.newHashSet(); + private final Set ignoredMethodNames = new HashSet<>(); /** Check methods and fields with only corresponding modifiers. */ private List memberModifiers; - /** The format string of the regexp. */ - private String format = "^(.*[\\.])?Abstract.*$"; - /** The regexp to match against. */ - private Pattern regexp = Pattern.compile(format); + private Pattern format = Pattern.compile("^(.*[.])?Abstract.*$"); /** * Controls whether to validate abstract class names. @@ -146,18 +142,15 @@ /** Creates new instance of the check. */ public IllegalTypeCheck() { setIllegalClassNames(DEFAULT_ILLEGAL_TYPES); - setLegalAbstractClassNames(DEFAULT_LEGAL_ABSTRACT_NAMES); setIgnoredMethodNames(DEFAULT_IGNORED_METHOD_NAMES); } /** - * Set the format to the specified regular expression. - * @param format a {@code String} value - * @throws org.apache.commons.beanutils.ConversionException unable to parse format - */ - public void setFormat(String format) { - this.format = format; - regexp = CommonUtils.createPattern(format); + * Set the format for the specified regular expression. + * @param pattern a pattern. + */ + public void setFormat(Pattern pattern) { + format = pattern; } /** @@ -184,6 +177,17 @@ } @Override + public void beginTree(DetailAST rootAST) { + illegalShortClassNames.clear(); + + for (String s : illegalClassNames) { + if (s.indexOf('.') == -1) { + illegalShortClassNames.add(s); + } + } + } + + @Override public int[] getRequiredTokens() { return new int[] {TokenTypes.IMPORT}; } @@ -242,6 +246,7 @@ modifier = modifier.getNextSibling()) { if (memberModifiers.contains(modifier.getType())) { result = true; + break; } } } @@ -330,6 +335,7 @@ } /** + * Returns true if given class name is one of illegal classes or else false. * @param className class name to check. * @return true if given class name is one of illegal classes * or if it matches to abstract class names pattern. @@ -337,35 +343,35 @@ private boolean isMatchingClassName(String className) { final String shortName = className.substring(className.lastIndexOf('.') + 1); return illegalClassNames.contains(className) - || illegalClassNames.contains(shortName) + || illegalShortClassNames.contains(shortName) || validateAbstractClassNames && !legalAbstractClassNames.contains(className) - && regexp.matcher(className).find(); + && format.matcher(className).find(); } /** * Extends illegal class names set via imported short type name. * @param canonicalName - * + * * Canonical name of imported type. */ private void extendIllegalClassNamesWithShortName(String canonicalName) { if (illegalClassNames.contains(canonicalName)) { final String shortName = canonicalName .substring(canonicalName.lastIndexOf('.') + 1); - illegalClassNames.add(shortName); + illegalShortClassNames.add(shortName); } } /** * Gets imported type's - * + * * canonical name. * @param importAst {@link TokenTypes#IMPORT Import} * @return Imported canonical type's name. */ private static String getImportedTypeCanonicalName(DetailAST importAst) { - final StringBuilder canonicalNameBuilder = new StringBuilder(); + final StringBuilder canonicalNameBuilder = new StringBuilder(256); DetailAST toVisit = importAst; while (toVisit != null) { toVisit = getNextSubTreeNode(toVisit, importAst); @@ -405,6 +411,7 @@ } /** + * Returns true if method has to be checked or false. * @param ast method def to check. * @return true if we should check this method. */ @@ -417,6 +424,7 @@ /** * Set the list of illegal variable types. * @param classNames array of illegal variable types + * @noinspection WeakerAccess */ public void setIllegalClassNames(String... classNames) { illegalClassNames.clear(); @@ -426,6 +434,7 @@ /** * Set the list of ignore method names. * @param methodNames array of ignored method names + * @noinspection WeakerAccess */ public void setIgnoredMethodNames(String... methodNames) { ignoredMethodNames.clear(); @@ -435,9 +444,9 @@ /** * Set the list of legal abstract class names. * @param classNames array of legal abstract class names + * @noinspection WeakerAccess */ public void setLegalAbstractClassNames(String... classNames) { - legalAbstractClassNames.clear(); Collections.addAll(legalAbstractClassNames, classNames); } @@ -452,4 +461,5 @@ } memberModifiers = modifiersList; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/InnerAssignmentCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/InnerAssignmentCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/InnerAssignmentCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/InnerAssignmentCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,8 +22,8 @@ import java.util.Arrays; import antlr.collections.AST; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -41,8 +41,9 @@ * * @author lkuehne */ +@StatelessCheck public class InnerAssignmentCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -105,11 +106,16 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { return new int[] { TokenTypes.ASSIGN, // '=' TokenTypes.DIV_ASSIGN, // "/=" @@ -127,11 +133,6 @@ } @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); - } - - @Override public void visitToken(DetailAST ast) { if (!isInContext(ast, ALLOWED_ASSIGNMENT_CONTEXT) && !isInNoBraceControlStatement(ast) @@ -170,12 +171,13 @@ * @return whether ast is in the body of a flow control statement */ private static boolean isInNoBraceControlStatement(DetailAST ast) { - if (!isInContext(ast, CONTROL_CONTEXT)) { - return false; + boolean result = false; + if (isInContext(ast, CONTROL_CONTEXT)) { + final DetailAST expr = ast.getParent(); + final AST exprNext = expr.getNextSibling(); + result = exprNext.getType() == TokenTypes.SEMI; } - final DetailAST expr = ast.getParent(); - final AST exprNext = expr.getNextSibling(); - return exprNext.getType() == TokenTypes.SEMI; + return result; } /** @@ -194,11 +196,12 @@ * @return whether the context of the assignment AST indicates the idiom */ private static boolean isInWhileIdiom(DetailAST ast) { - if (!isComparison(ast.getParent())) { - return false; + boolean result = false; + if (isComparison(ast.getParent())) { + result = isInContext( + ast.getParent(), ALLOWED_ASSIGNMENT_IN_COMPARISON_CONTEXT); } - return isInContext( - ast.getParent(), ALLOWED_ASSIGNMENT_IN_COMPARISON_CONTEXT); + return result; } /** @@ -241,4 +244,5 @@ } return found; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MagicNumberCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MagicNumberCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MagicNumberCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MagicNumberCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,12 +21,12 @@ import java.util.Arrays; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CheckUtils; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; import com.puppycrawl.tools.checkstyle.utils.TokenUtils; @@ -138,7 +138,8 @@ * @author Lars Kühne * @author Daniel Solano Gómez */ -public class MagicNumberCheck extends Check { +@StatelessCheck +public class MagicNumberCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -203,31 +204,26 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override public void visitToken(DetailAST ast) { - if (ignoreAnnotation && isChildOf(ast, TokenTypes.ANNOTATION)) { - return; - } - - if (isInIgnoreList(ast) - || ignoreHashCodeMethod && isInHashCodeMethod(ast)) { - return; - } - - final DetailAST constantDefAST = findContainingConstantDef(ast); - - if (constantDefAST == null) { - if (!ignoreFieldDeclaration || !isFieldDeclaration(ast)) { - reportMagicNumber(ast); + if ((!ignoreAnnotation || !isChildOf(ast, TokenTypes.ANNOTATION)) + && !isInIgnoreList(ast) + && (!ignoreHashCodeMethod || !isInHashCodeMethod(ast))) { + final DetailAST constantDefAST = findContainingConstantDef(ast); + + if (constantDefAST == null) { + if (!ignoreFieldDeclaration || !isFieldDeclaration(ast)) { + reportMagicNumber(ast); + } } - } - else { - final boolean found = isMagicNumberExists(ast, constantDefAST); - if (found) { - reportMagicNumber(ast); + else { + final boolean found = isMagicNumberExists(ast, constantDefAST); + if (found) { + reportMagicNumber(ast); + } } } } @@ -277,7 +273,7 @@ // explicit constant final DetailAST modifiersAST = varDefAST.findFirstToken(TokenTypes.MODIFIERS); - if (modifiersAST.branchContains(TokenTypes.FINAL)) { + if (modifiersAST.findFirstToken(TokenTypes.FINAL) != null) { constantDef = varDefAST; } } @@ -399,7 +395,7 @@ */ public void setIgnoreNumbers(double... list) { if (list.length == 0) { - ignoreNumbers = ArrayUtils.EMPTY_DOUBLE_ARRAY; + ignoreNumbers = CommonUtils.EMPTY_DOUBLE_ARRAY; } else { ignoreNumbers = new double[list.length]; @@ -448,10 +444,12 @@ do { if (node.getType() == type) { result = true; + break; } node = node.getParent(); - } while (node != null && !result); + } while (node != null); return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MissingCtorCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MissingCtorCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MissingCtorCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MissingCtorCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -37,7 +38,8 @@ * * @author o_sukhodolsky */ -public class MissingCtorCheck extends Check { +@StatelessCheck +public class MissingCtorCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -47,26 +49,27 @@ @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.CLASS_DEF}; + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return getDefaultTokens(); + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] {TokenTypes.CLASS_DEF}; } @Override public void visitToken(DetailAST ast) { final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); - if (!modifiers.branchContains(TokenTypes.ABSTRACT) + if (modifiers.findFirstToken(TokenTypes.ABSTRACT) == null && ast.findFirstToken(TokenTypes.OBJBLOCK) .findFirstToken(TokenTypes.CTOR_DEF) == null) { log(ast.getLineNo(), MSG_KEY); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MissingSwitchDefaultCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MissingSwitchDefaultCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MissingSwitchDefaultCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MissingSwitchDefaultCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -44,7 +45,8 @@ * * @author o_sukhodolsky */ -public class MissingSwitchDefaultCheck extends Check { +@StatelessCheck +public class MissingSwitchDefaultCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -54,17 +56,17 @@ @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.LITERAL_SWITCH}; + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return getDefaultTokens(); + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] {TokenTypes.LITERAL_SWITCH}; } @Override @@ -96,4 +98,5 @@ return found; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ModifiedControlVariableCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ModifiedControlVariableCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ModifiedControlVariableCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ModifiedControlVariableCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,14 +20,16 @@ package com.puppycrawl.tools.checkstyle.checks.coding; import java.util.ArrayDeque; +import java.util.Arrays; import java.util.Deque; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -44,7 +46,7 @@ * * Rationale: If the control variable is modified inside the loop * body, the program flow becomes more difficult to follow.
      - * See + * See * FOR statement specification for more details. *

      Examples:

      * @@ -65,7 +67,7 @@ * *

      * By default, This Check validates - * + * * Enhanced For-Loop. *

      *

      @@ -94,7 +96,8 @@ * @author Daniel Grenner * @author liscju */ -public final class ModifiedControlVariableCheck extends Check { +@FileStatefulCheck +public final class ModifiedControlVariableCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -109,8 +112,13 @@ /** Operations which can change control variable in update part of the loop. */ private static final Set MUTATION_OPERATIONS = - Sets.newHashSet(TokenTypes.POST_INC, TokenTypes.POST_DEC, TokenTypes.DEC, - TokenTypes.INC, TokenTypes.ASSIGN); + Arrays.stream(new Integer[] { + TokenTypes.POST_INC, + TokenTypes.POST_DEC, + TokenTypes.DEC, + TokenTypes.INC, + TokenTypes.ASSIGN, + }).collect(Collectors.toSet()); /** Stack of block parameters. */ private final Deque> variableStack = new ArrayDeque<>(); @@ -128,16 +136,11 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); - } - - @Override - public int[] getAcceptableTokens() { return new int[] { TokenTypes.OBJBLOCK, TokenTypes.LITERAL_FOR, @@ -163,10 +166,14 @@ } @Override + public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override public void beginTree(DetailAST rootAST) { // clear data variableStack.clear(); - variableStack.push(new ArrayDeque()); } @Override @@ -250,7 +257,7 @@ * Enters an inner class, which requires a new variable set. */ private void enterBlock() { - variableStack.push(new ArrayDeque()); + variableStack.push(new ArrayDeque<>()); } /** @@ -273,7 +280,8 @@ * @param ast ident to check. */ private void checkIdent(DetailAST ast) { - if (!getCurrentVariables().isEmpty()) { + final Deque currentVariables = getCurrentVariables(); + if (currentVariables != null && !currentVariables.isEmpty()) { final DetailAST identAST = ast.getFirstChild(); if (identAST != null && identAST.getType() == TokenTypes.IDENT @@ -304,8 +312,8 @@ private static Set getVariablesManagedByForLoop(DetailAST ast) { final Set initializedVariables = getForInitVariables(ast); final Set iteratingVariables = getForIteratorVariables(ast); - - return Sets.intersection(initializedVariables, iteratingVariables); + return initializedVariables.stream().filter(iteratingVariables::contains) + .collect(Collectors.toSet()); } /** @@ -324,8 +332,10 @@ private void leaveForDef(DetailAST ast) { final DetailAST forInitAST = ast.findFirstToken(TokenTypes.FOR_INIT); if (forInitAST == null) { - // this is for-each loop, just pop variables - getCurrentVariables().pop(); + if (!skipEnhancedForLoopVariable) { + // this is for-each loop, just pop variables + getCurrentVariables().pop(); + } } else { final Set variablesManagedByForLoop = getVariablesManagedByForLoop(ast); @@ -375,15 +385,15 @@ final DetailAST forIteratorAST = ast.findFirstToken(TokenTypes.FOR_ITERATOR); final DetailAST forUpdateListAST = forIteratorAST.findFirstToken(TokenTypes.ELIST); - for (DetailAST iteratingExpressionAST : findChildrenOfExpressionType(forUpdateListAST)) { - - if (MUTATION_OPERATIONS.contains(iteratingExpressionAST.getType())) { + findChildrenOfExpressionType(forUpdateListAST).stream() + .filter(iteratingExpressionAST -> { + return MUTATION_OPERATIONS.contains(iteratingExpressionAST.getType()); + }).forEach(iteratingExpressionAST -> { final DetailAST oneVariableOperatorChild = iteratingExpressionAST.getFirstChild(); if (oneVariableOperatorChild.getType() == TokenTypes.IDENT) { iteratorVariables.add(oneVariableOperatorChild.getText()); } - } - } + }); return iteratorVariables; } @@ -406,4 +416,5 @@ } return foundExpressions; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MultipleStringLiteralsCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,17 +19,17 @@ package com.puppycrawl.tools.checkstyle.checks.coding; +import java.util.ArrayList; import java.util.BitSet; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.TokenUtils; /** @@ -38,7 +38,8 @@ * * @author Daniel Grenner */ -public class MultipleStringLiteralsCheck extends Check { +@FileStatefulCheck +public class MultipleStringLiteralsCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -51,7 +52,7 @@ * {@code }, with the ArrayList containing StringInfo * objects. */ - private final Map> stringMap = Maps.newHashMap(); + private final Map> stringMap = new HashMap<>(); /** * Marks the TokenTypes where duplicate strings should be ignored. @@ -67,13 +68,13 @@ /** * Pattern for matching ignored strings. */ - private Pattern pattern; + private Pattern ignoreStringsRegexp; /** * Construct an instance with default values. */ public MultipleStringLiteralsCheck() { - setIgnoreStringsRegexp("^\"\"$"); + setIgnoreStringsRegexp(Pattern.compile("^\"\"$")); ignoreOccurrenceContext.set(TokenTypes.ANNOTATION); } @@ -89,15 +90,14 @@ * Sets regular expression pattern for ignored strings. * @param ignoreStringsRegexp * regular expression pattern for ignored strings - * @throws org.apache.commons.beanutils.ConversionException - * if unable to create Pattern object + * @noinspection WeakerAccess */ - public final void setIgnoreStringsRegexp(String ignoreStringsRegexp) { - if (ignoreStringsRegexp == null || ignoreStringsRegexp.isEmpty()) { - pattern = null; + public final void setIgnoreStringsRegexp(Pattern ignoreStringsRegexp) { + if (ignoreStringsRegexp == null || ignoreStringsRegexp.pattern().isEmpty()) { + this.ignoreStringsRegexp = null; } else { - pattern = CommonUtils.createPattern(ignoreStringsRegexp); + this.ignoreStringsRegexp = ignoreStringsRegexp; } } @@ -115,34 +115,33 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.STRING_LITERAL}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.STRING_LITERAL}; } @Override public void visitToken(DetailAST ast) { - if (isInIgnoreOccurrenceContext(ast)) { - return; - } - final String currentString = ast.getText(); - if (pattern == null || !pattern.matcher(currentString).find()) { - List hitList = stringMap.get(currentString); - if (hitList == null) { - hitList = Lists.newArrayList(); - stringMap.put(currentString, hitList); + if (!isInIgnoreOccurrenceContext(ast)) { + final String currentString = ast.getText(); + if (ignoreStringsRegexp == null || !ignoreStringsRegexp.matcher(currentString).find()) { + List hitList = stringMap.get(currentString); + if (hitList == null) { + hitList = new ArrayList<>(); + stringMap.put(currentString, hitList); + } + final int line = ast.getLineNo(); + final int col = ast.getColumnNo(); + hitList.add(new StringInfo(line, col)); } - final int line = ast.getLineNo(); - final int col = ast.getColumnNo(); - hitList.add(new StringInfo(line, col)); } } @@ -155,20 +154,21 @@ * token type in {@link #ignoreOccurrenceContext}. */ private boolean isInIgnoreOccurrenceContext(DetailAST ast) { + boolean isInIgnoreOccurrenceContext = false; for (DetailAST token = ast; token.getParent() != null; token = token.getParent()) { final int type = token.getType(); if (ignoreOccurrenceContext.get(type)) { - return true; + isInIgnoreOccurrenceContext = true; + break; } } - return false; + return isInIgnoreOccurrenceContext; } @Override public void beginTree(DetailAST rootAST) { - super.beginTree(rootAST); stringMap.clear(); } @@ -189,6 +189,7 @@ * This class contains information about where a string was found. */ private static final class StringInfo { + /** * Line of finding. */ @@ -223,6 +224,7 @@ private int getCol() { return col; } + } } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MultipleVariableDeclarationsCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MultipleVariableDeclarationsCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MultipleVariableDeclarationsCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/MultipleVariableDeclarationsCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CheckUtils; @@ -43,7 +44,8 @@ * * @author o_sukhodolsky */ -public class MultipleVariableDeclarationsCheck extends Check { +@StatelessCheck +public class MultipleVariableDeclarationsCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -59,59 +61,55 @@ @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.VARIABLE_DEF}; + return getRequiredTokens(); } @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.VARIABLE_DEF}; } @Override public void visitToken(DetailAST ast) { DetailAST nextNode = ast.getNextSibling(); - if (nextNode == null) { - // no next statement - no check - return; - } - - final boolean isCommaSeparated = nextNode.getType() == TokenTypes.COMMA; - - if (isCommaSeparated - || nextNode.getType() == TokenTypes.SEMI) { - nextNode = nextNode.getNextSibling(); - } + if (nextNode != null) { + final boolean isCommaSeparated = nextNode.getType() == TokenTypes.COMMA; - if (nextNode != null - && nextNode.getType() == TokenTypes.VARIABLE_DEF) { - final DetailAST firstNode = CheckUtils.getFirstNode(ast); - if (isCommaSeparated) { - // Check if the multiple variable declarations are in a - // for loop initializer. If they are, then no warning - // should be displayed. Declaring multiple variables in - // a for loop initializer is a good way to minimize - // variable scope. Refer Feature Request Id - 2895985 - // for more details - if (ast.getParent().getType() != TokenTypes.FOR_INIT) { - log(firstNode, MSG_MULTIPLE_COMMA); - } - return; + if (isCommaSeparated + || nextNode.getType() == TokenTypes.SEMI) { + nextNode = nextNode.getNextSibling(); } - final DetailAST lastNode = getLastNode(ast); - final DetailAST firstNextNode = CheckUtils.getFirstNode(nextNode); - - if (firstNextNode.getLineNo() == lastNode.getLineNo()) { - log(firstNode, MSG_MULTIPLE); + if (nextNode != null + && nextNode.getType() == TokenTypes.VARIABLE_DEF) { + final DetailAST firstNode = CheckUtils.getFirstNode(ast); + if (isCommaSeparated) { + // Check if the multiple variable declarations are in a + // for loop initializer. If they are, then no warning + // should be displayed. Declaring multiple variables in + // a for loop initializer is a good way to minimize + // variable scope. Refer Feature Request Id - 2895985 + // for more details + if (ast.getParent().getType() != TokenTypes.FOR_INIT) { + log(firstNode, MSG_MULTIPLE_COMMA); + } + } + else { + final DetailAST lastNode = getLastNode(ast); + final DetailAST firstNextNode = CheckUtils.getFirstNode(nextNode); + + if (firstNextNode.getLineNo() == lastNode.getLineNo()) { + log(firstNode, MSG_MULTIPLE); + } + } } } - } /** @@ -134,4 +132,5 @@ return currentNode; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedForDepthCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedForDepthCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedForDepthCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedForDepthCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -41,7 +42,8 @@ * @author Alexander Jesse * @see NestedIfDepthCheck */ -public final class NestedForDepthCheck extends Check { +@FileStatefulCheck +public final class NestedForDepthCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -64,17 +66,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.LITERAL_FOR}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.LITERAL_FOR}; } @Override @@ -94,4 +96,5 @@ public void leaveToken(DetailAST ast) { --depth; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedIfDepthCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedIfDepthCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedIfDepthCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedIfDepthCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CheckUtils; @@ -29,7 +30,8 @@ * * @author Simon Harris */ -public final class NestedIfDepthCheck extends Check { +@FileStatefulCheck +public final class NestedIfDepthCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -52,17 +54,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.LITERAL_IF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.LITERAL_IF}; } @Override diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedTryDepthCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedTryDepthCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedTryDepthCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NestedTryDepthCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -27,7 +28,8 @@ * Restricts nested try-catch-finally blocks to a specified depth (default = 1). * @author Simon Harris */ -public final class NestedTryDepthCheck extends Check { +@FileStatefulCheck +public final class NestedTryDepthCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -50,17 +52,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.LITERAL_TRY}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.LITERAL_TRY}; } @Override diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NoCloneCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NoCloneCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NoCloneCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NoCloneCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -116,7 +117,8 @@ * @author Travis Schneeberger * @see Object#clone() */ -public class NoCloneCheck extends Check { +@StatelessCheck +public class NoCloneCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -126,17 +128,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.METHOD_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.METHOD_DEF}; } @Override @@ -145,14 +147,14 @@ final String name = mid.getText(); if ("clone".equals(name)) { - final DetailAST params = aAST.findFirstToken(TokenTypes.PARAMETERS); final boolean hasEmptyParamList = - !params.branchContains(TokenTypes.PARAMETER_DEF); + params.findFirstToken(TokenTypes.PARAMETER_DEF) == null; if (hasEmptyParamList) { log(aAST.getLineNo(), MSG_KEY); } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NoFinalizerCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NoFinalizerCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NoFinalizerCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/NoFinalizerCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -31,7 +32,8 @@ * @author smckay@google.com (Steve McKay) * @author lkuehne */ -public class NoFinalizerCheck extends Check { +@StatelessCheck +public class NoFinalizerCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -41,17 +43,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.METHOD_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.METHOD_DEF}; } @Override @@ -60,14 +62,14 @@ final String name = mid.getText(); if ("finalize".equals(name)) { - final DetailAST params = aAST.findFirstToken(TokenTypes.PARAMETERS); final boolean hasEmptyParamList = - !params.branchContains(TokenTypes.PARAMETER_DEF); + params.findFirstToken(TokenTypes.PARAMETER_DEF) == null; if (hasEmptyParamList) { log(aAST.getLineNo(), MSG_KEY); } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/OneStatementPerLineCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/OneStatementPerLineCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/OneStatementPerLineCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/OneStatementPerLineCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,8 @@ import java.util.ArrayDeque; import java.util.Deque; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -67,7 +68,8 @@ * @author Oliver Burn * @author Andrei Selkin */ -public final class OneStatementPerLineCheck extends Check { +@FileStatefulCheck +public final class OneStatementPerLineCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -107,11 +109,16 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { return new int[] { TokenTypes.SEMI, TokenTypes.FOR_INIT, @@ -121,11 +128,6 @@ } @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); - } - - @Override public void beginTree(DetailAST rootAST) { inForHeader = false; lastStatementEnd = -1; @@ -237,4 +239,5 @@ } return multiline; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/OverloadMethodsDeclarationOrderCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/OverloadMethodsDeclarationOrderCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/OverloadMethodsDeclarationOrderCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/OverloadMethodsDeclarationOrderCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,8 @@ import java.util.HashMap; import java.util.Map; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -47,7 +48,8 @@ * * @author maxvetrenko */ -public class OverloadMethodsDeclarationOrderCheck extends Check { +@StatelessCheck +public class OverloadMethodsDeclarationOrderCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -57,19 +59,19 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.OBJBLOCK, - }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] { + TokenTypes.OBJBLOCK, + }; } @Override @@ -115,4 +117,5 @@ currentToken = currentToken.getNextSibling(); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/PackageDeclarationCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/PackageDeclarationCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/PackageDeclarationCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/PackageDeclarationCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,25 +19,42 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import java.io.File; + +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; /** * Ensures there is a package declaration. + * Optionally checks if directory structure matches package name. * Rationale: Classes that live in the null package cannot be * imported. Many novice developers are not aware of this. + * Packages provide logical namespace to classes and should be stored in + * the form of directory levels to provide physical grouping to your classes. + * These directories are added to the classpath so that your classes + * are visible to JVM when it runs the code. * * @author Simon Harris * @author Oliver Burn + * @author Vikramaditya Kukreja */ -public final class PackageDeclarationCheck extends Check { +@FileStatefulCheck +public final class PackageDeclarationCheck extends AbstractCheck { + + /** + * A key is pointing to the warning message text in "messages.properties" + * file. + */ + public static final String MSG_KEY_MISSING = "missing.package.declaration"; /** * A key is pointing to the warning message text in "messages.properties" * file. */ - public static final String MSG_KEY = "missing.package.declaration"; + public static final String MSG_KEY_MISMATCH = "mismatch.package.directory"; /** Line number used to log violation when no AST nodes are present in file. */ private static final int DEFAULT_LINE_NUMBER = 1; @@ -45,19 +62,30 @@ /** Is package defined. */ private boolean defined; + /** Whether to check for directory and package name match. */ + private boolean matchDirectoryStructure = true; + + /** + * Set whether to check for directory and package name match. + * @param matchDirectoryStructure the new value. + */ + public void setMatchDirectoryStructure(boolean matchDirectoryStructure) { + this.matchDirectoryStructure = matchDirectoryStructure; + } + @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.PACKAGE_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] {TokenTypes.PACKAGE_DEF}; } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.PACKAGE_DEF}; + return getRequiredTokens(); } @Override @@ -72,12 +100,35 @@ if (ast != null) { lineNumber = ast.getLineNo(); } - log(lineNumber, MSG_KEY); + log(lineNumber, MSG_KEY_MISSING); } } @Override public void visitToken(DetailAST ast) { defined = true; + + if (matchDirectoryStructure) { + final DetailAST packageNameAst = ast.getLastChild().getPreviousSibling(); + final FullIdent fullIdent = FullIdent.createFullIdent(packageNameAst); + final String packageName = fullIdent.getText().replace('.', File.separatorChar); + + final String directoryName = getDirectoryName(); + + if (!directoryName.endsWith(packageName)) { + log(fullIdent.getLineNo(), MSG_KEY_MISMATCH, packageName); + } + } + } + + /** + * Returns the directory name this file is in. + * @return Directory name. + */ + private String getDirectoryName() { + final String fileName = getFileContents().getFileName(); + final int lastSeparatorPos = fileName.lastIndexOf(File.separatorChar); + return fileName.substring(0, lastSeparatorPos); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ParameterAssignmentCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ParameterAssignmentCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ParameterAssignmentCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ParameterAssignmentCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,12 +22,14 @@ import java.util.ArrayDeque; import java.util.Collections; import java.util.Deque; +import java.util.HashSet; import java.util.Set; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CheckUtils; /** *

      @@ -43,7 +45,8 @@ *

      * @author Simon Harris */ -public final class ParameterAssignmentCheck extends Check { +@FileStatefulCheck +public final class ParameterAssignmentCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -58,35 +61,11 @@ @Override public int[] getDefaultTokens() { - return new int[] { - TokenTypes.CTOR_DEF, - TokenTypes.METHOD_DEF, - TokenTypes.ASSIGN, - TokenTypes.PLUS_ASSIGN, - TokenTypes.MINUS_ASSIGN, - TokenTypes.STAR_ASSIGN, - TokenTypes.DIV_ASSIGN, - TokenTypes.MOD_ASSIGN, - TokenTypes.SR_ASSIGN, - TokenTypes.BSR_ASSIGN, - TokenTypes.SL_ASSIGN, - TokenTypes.BAND_ASSIGN, - TokenTypes.BXOR_ASSIGN, - TokenTypes.BOR_ASSIGN, - TokenTypes.INC, - TokenTypes.POST_INC, - TokenTypes.DEC, - TokenTypes.POST_DEC, - }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); - } - - @Override - public int[] getAcceptableTokens() { return new int[] { TokenTypes.CTOR_DEF, TokenTypes.METHOD_DEF, @@ -110,6 +89,11 @@ } @Override + public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override public void beginTree(DetailAST rootAST) { // clear data parameterNamesStack.clear(); @@ -217,7 +201,7 @@ */ private void visitMethodDef(DetailAST ast) { parameterNamesStack.push(parameterNames); - parameterNames = Sets.newHashSet(); + parameterNames = new HashSet<>(); visitMethodParameters(ast.findFirstToken(TokenTypes.PARAMETERS)); } @@ -236,7 +220,8 @@ ast.findFirstToken(TokenTypes.PARAMETER_DEF); while (parameterDefAST != null) { - if (parameterDefAST.getType() == TokenTypes.PARAMETER_DEF) { + if (parameterDefAST.getType() == TokenTypes.PARAMETER_DEF + && !CheckUtils.isReceiverParameter(parameterDefAST)) { final DetailAST param = parameterDefAST.findFirstToken(TokenTypes.IDENT); parameterNames.add(param.getText()); @@ -244,4 +229,5 @@ parameterDefAST = parameterDefAST.getNextSibling(); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/RequireThisCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/RequireThisCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/RequireThisCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/RequireThisCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,19 +19,25 @@ package com.puppycrawl.tools.checkstyle.checks.coding; +import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Collections; import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.Set; +import java.util.stream.Collectors; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CheckUtils; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; +import com.puppycrawl.tools.checkstyle.utils.TokenUtils; /** *

      Checks that code doesn't rely on the "this" default. @@ -39,8 +45,15 @@ * object are explicitly of the form "this.varName" or * "this.methodName(args)". *

      + * Check has the following options: + *

      checkFields - whether to check references to fields. Default value is true.

      + *

      checkMethods - whether to check references to methods. + * Default value is true.

      + *

      validateOnlyOverlapping - whether to check only overlapping by variables or + * arguments. Default value is true.

      * - *

      Warning: the Check is very controversial and not that actual nowadays.

      + *

      Warning: the Check is very controversial if 'validateOnlyOverlapping' option is set to 'false' + * and not that actual nowadays.

      * *

      Examples of use: *

      @@ -76,48 +89,76 @@
        *
        * @author Stephen Bloch
        * @author o_sukhodolsky
      + * @author Andrei Selkin
        */
      -public class RequireThisCheck extends Check {
      +// -@cs[ClassDataAbstractionCoupling] This check requires to work with and identify many frames.
      +@FileStatefulCheck
      +public class RequireThisCheck extends AbstractCheck {
       
           /**
            * A key is pointing to the warning message text in "messages.properties"
            * file.
            */
           public static final String MSG_METHOD = "require.this.method";
      -
           /**
            * A key is pointing to the warning message text in "messages.properties"
            * file.
            */
           public static final String MSG_VARIABLE = "require.this.variable";
      -    /**
      -     * Set of all declaration tokens.
      -     */
      -    private static final ImmutableSet DECLARATION_TOKENS = ImmutableSet.of(
      +
      +    /** Set of all declaration tokens. */
      +    private static final Set DECLARATION_TOKENS = Collections.unmodifiableSet(
      +        Arrays.stream(new Integer[] {
                   TokenTypes.VARIABLE_DEF,
                   TokenTypes.CTOR_DEF,
                   TokenTypes.METHOD_DEF,
                   TokenTypes.CLASS_DEF,
                   TokenTypes.ENUM_DEF,
      +            TokenTypes.ANNOTATION_DEF,
                   TokenTypes.INTERFACE_DEF,
                   TokenTypes.PARAMETER_DEF,
      -            TokenTypes.TYPE_ARGUMENT
      -    );
      +            TokenTypes.TYPE_ARGUMENT,
      +        }).collect(Collectors.toSet()));
      +    /** Set of all assign tokens. */
      +    private static final Set ASSIGN_TOKENS = Collections.unmodifiableSet(
      +        Arrays.stream(new Integer[] {
      +            TokenTypes.ASSIGN,
      +            TokenTypes.PLUS_ASSIGN,
      +            TokenTypes.STAR_ASSIGN,
      +            TokenTypes.DIV_ASSIGN,
      +            TokenTypes.MOD_ASSIGN,
      +            TokenTypes.SR_ASSIGN,
      +            TokenTypes.BSR_ASSIGN,
      +            TokenTypes.SL_ASSIGN,
      +            TokenTypes.BAND_ASSIGN,
      +            TokenTypes.BXOR_ASSIGN,
      +        }).collect(Collectors.toSet()));
      +    /** Set of all compound assign tokens. */
      +    private static final Set COMPOUND_ASSIGN_TOKENS = Collections.unmodifiableSet(
      +        Arrays.stream(new Integer[] {
      +            TokenTypes.PLUS_ASSIGN,
      +            TokenTypes.STAR_ASSIGN,
      +            TokenTypes.DIV_ASSIGN,
      +            TokenTypes.MOD_ASSIGN,
      +            TokenTypes.SR_ASSIGN,
      +            TokenTypes.BSR_ASSIGN,
      +            TokenTypes.SL_ASSIGN,
      +            TokenTypes.BAND_ASSIGN,
      +            TokenTypes.BXOR_ASSIGN,
      +        }).collect(Collectors.toSet()));
       
      -    /**
      -     * Tree of all the parsed frames.
      -     */
      -    private Map frames;
      +    /** Frame for the currently processed AST. */
      +    private final Deque current = new ArrayDeque<>();
       
      -    /**
      -     * Frame for the currently processed AST.
      -     */
      -    private AbstractFrame current;
      +    /** Tree of all the parsed frames. */
      +    private Map frames;
       
           /** Whether we should check fields usage. */
           private boolean checkFields = true;
           /** Whether we should check methods usage. */
           private boolean checkMethods = true;
      +    /** Whether we should check only overlapping by variables or arguments. */
      +    private boolean validateOnlyOverlapping = true;
       
           /**
            * Setter for checkFields property.
      @@ -135,35 +176,45 @@
               this.checkMethods = checkMethods;
           }
       
      -    @Override
      -    public int[] getDefaultTokens() {
      -        return getAcceptableTokens();
      +    /**
      +     * Setter for validateOnlyOverlapping property.
      +     * @param validateOnlyOverlapping should we check only overlapping by variables or arguments.
      +     */
      +    public void setValidateOnlyOverlapping(boolean validateOnlyOverlapping) {
      +        this.validateOnlyOverlapping = validateOnlyOverlapping;
           }
       
           @Override
      -    public int[] getRequiredTokens() {
      -        return getAcceptableTokens();
      +    public int[] getDefaultTokens() {
      +        return getRequiredTokens();
           }
       
           @Override
      -    public int[] getAcceptableTokens() {
      +    public int[] getRequiredTokens() {
               return new int[] {
                   TokenTypes.CLASS_DEF,
                   TokenTypes.INTERFACE_DEF,
                   TokenTypes.ENUM_DEF,
      +            TokenTypes.ANNOTATION_DEF,
                   TokenTypes.CTOR_DEF,
                   TokenTypes.METHOD_DEF,
      +            TokenTypes.LITERAL_FOR,
                   TokenTypes.SLIST,
                   TokenTypes.IDENT,
               };
           }
       
           @Override
      -    public void beginTree(DetailAST rootAST) {
      -        final Deque frameStack = Lists.newLinkedList();
      +    public int[] getAcceptableTokens() {
      +        return getRequiredTokens();
      +    }
       
      -        frames = Maps.newHashMap();
      +    @Override
      +    public void beginTree(DetailAST rootAST) {
      +        frames = new HashMap<>();
      +        current.clear();
       
      +        final Deque frameStack = new LinkedList<>();
               DetailAST curNode = rootAST;
               while (curNode != null) {
                   collectDeclarations(frameStack, curNode);
      @@ -192,7 +243,26 @@
                   case TokenTypes.SLIST :
                   case TokenTypes.METHOD_DEF :
                   case TokenTypes.CTOR_DEF :
      -                current = frames.get(ast);
      +            case TokenTypes.LITERAL_FOR :
      +                current.push(frames.get(ast));
      +                break;
      +            default :
      +                // do nothing
      +        }
      +    }
      +
      +    @Override
      +    public void leaveToken(DetailAST ast) {
      +        switch (ast.getType()) {
      +            case TokenTypes.CLASS_DEF :
      +            case TokenTypes.INTERFACE_DEF :
      +            case TokenTypes.ENUM_DEF :
      +            case TokenTypes.ANNOTATION_DEF :
      +            case TokenTypes.SLIST :
      +            case TokenTypes.METHOD_DEF :
      +            case TokenTypes.CTOR_DEF :
      +            case TokenTypes.LITERAL_FOR:
      +                current.pop();
                       break;
                   default :
                       // do nothing
      @@ -201,12 +271,16 @@
       
           /**
            * Checks if a given IDENT is method call or field name which
      -     * require explicit {@code this} qualifier.
      -     *
      +     * requires explicit {@code this} qualifier.
            * @param ast IDENT to check.
            */
           private void processIdent(DetailAST ast) {
      -        final int parentType = ast.getParent().getType();
      +        int parentType = ast.getParent().getType();
      +        if (parentType == TokenTypes.EXPR
      +                && ast.getParent().getParent().getParent().getType()
      +                    == TokenTypes.ANNOTATION_FIELD_DEF) {
      +            parentType = TokenTypes.ANNOTATION_FIELD_DEF;
      +        }
               switch (parentType) {
                   case TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR:
                   case TokenTypes.ANNOTATION:
      @@ -214,9 +288,8 @@
                       // no need to check annotations content
                       break;
                   case TokenTypes.METHOD_CALL:
      -                // let's check method calls
                       if (checkMethods) {
      -                    final AbstractFrame frame = checkMethod(ast);
      +                    final AbstractFrame frame = getMethodWithoutThis(ast);
                           if (frame != null) {
                               logViolation(MSG_METHOD, ast, frame);
                           }
      @@ -224,7 +297,7 @@
                       break;
                   default:
                       if (checkFields) {
      -                    final AbstractFrame frame = processField(ast, parentType);
      +                    final AbstractFrame frame = getFieldWithoutThis(ast, parentType);
                           if (frame != null) {
                               logViolation(MSG_VARIABLE, ast, frame);
                           }
      @@ -237,24 +310,26 @@
            * Helper method to log a LocalizedMessage.
            * @param ast a node to get line id column numbers associated with the message.
            * @param msgKey key to locale message format.
      -     * @param frame the frame, where the violation is found.
      +     * @param frame the class frame where the violation is found.
            */
           private void logViolation(String msgKey, DetailAST ast, AbstractFrame frame) {
               if (frame.getFrameName().equals(getNearestClassFrameName())) {
                   log(ast, msgKey, ast.getText(), "");
               }
      -        else {
      +        else if (!(frame instanceof AnonymousClassFrame)) {
                   log(ast, msgKey, ast.getText(), frame.getFrameName() + '.');
               }
           }
       
           /**
      -     * Process validation of Field.
      -     * @param ast field definition ast token
      -     * @param parentType type of the parent
      -     * @return frame, where the field is declared, if the violation is found and null otherwise
      +     * Returns the frame where the field is declared, if the given field is used without
      +     * 'this', and null otherwise.
      +     * @param ast field definition ast token.
      +     * @param parentType type of the parent.
      +     * @return the frame where the field is declared, if the given field is used without
      +     *         'this' and null otherwise.
            */
      -    private AbstractFrame processField(DetailAST ast, int parentType) {
      +    private AbstractFrame getFieldWithoutThis(DetailAST ast, int parentType) {
               final boolean importOrPackage = ScopeUtils.getSurroundingScope(ast) == null;
               final boolean methodNameInMethodCall = parentType == TokenTypes.DOT
                       && ast.getPreviousSibling() != null;
      @@ -265,55 +340,81 @@
               if (!importOrPackage
                       && !methodNameInMethodCall
                       && !typeName
      -                && !isDeclarationToken(parentType)) {
      -            frame = checkField(ast);
      +                && !isDeclarationToken(parentType)
      +                && !isLambdaParameter(ast)) {
      +            final AbstractFrame fieldFrame = findClassFrame(ast, false);
      +
      +            if (fieldFrame != null && ((ClassFrame) fieldFrame).hasInstanceMember(ast)) {
      +                frame = getClassFrameWhereViolationIsFound(ast);
      +            }
               }
               return frame;
           }
       
           /**
      -     * Parse the next AST for declarations.
      -     *
      -     * @param frameStack Stack containing the FrameTree being built
      -     * @param ast AST to parse
      +     * Parses the next AST for declarations.
      +     * @param frameStack stack containing the FrameTree being built.
      +     * @param ast AST to parse.
            */
      -    private static void collectDeclarations(Deque frameStack,
      -        DetailAST ast) {
      +    // -@cs[JavaNCSS] This method is a big switch and is too hard to remove.
      +    private static void collectDeclarations(Deque frameStack, DetailAST ast) {
               final AbstractFrame frame = frameStack.peek();
               switch (ast.getType()) {
                   case TokenTypes.VARIABLE_DEF :
                       collectVariableDeclarations(ast, frame);
                       break;
                   case TokenTypes.PARAMETER_DEF :
      -                final DetailAST parameterIdent = ast.findFirstToken(TokenTypes.IDENT);
      -                frame.addIdent(parameterIdent);
      +                if (!CheckUtils.isReceiverParameter(ast)
      +                        && !isLambdaParameter(ast)
      +                        && ast.getParent().getType() != TokenTypes.LITERAL_CATCH) {
      +                    final DetailAST parameterIdent = ast.findFirstToken(TokenTypes.IDENT);
      +                    frame.addIdent(parameterIdent);
      +                }
                       break;
                   case TokenTypes.CLASS_DEF :
                   case TokenTypes.INTERFACE_DEF :
                   case TokenTypes.ENUM_DEF :
                   case TokenTypes.ANNOTATION_DEF :
      -                final DetailAST classIdent = ast.findFirstToken(TokenTypes.IDENT);
      -                frameStack.addFirst(new ClassFrame(frame, classIdent.getText()));
      +                final DetailAST classFrameNameIdent = ast.findFirstToken(TokenTypes.IDENT);
      +                frameStack.addFirst(new ClassFrame(frame, classFrameNameIdent));
                       break;
                   case TokenTypes.SLIST :
      -                frameStack.addFirst(new BlockFrame(frame));
      +                frameStack.addFirst(new BlockFrame(frame, ast));
                       break;
                   case TokenTypes.METHOD_DEF :
      -                final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
      -                if (frame.getType() == FrameType.CLASS_FRAME) {
      -                    final DetailAST mods =
      -                            ast.findFirstToken(TokenTypes.MODIFIERS);
      -                    if (mods.branchContains(TokenTypes.LITERAL_STATIC)) {
      -                        ((ClassFrame) frame).addStaticMethod(ident);
      -                    }
      -                    else {
      -                        ((ClassFrame) frame).addInstanceMethod(ident);
      -                    }
      +                final DetailAST methodFrameNameIdent = ast.findFirstToken(TokenTypes.IDENT);
      +                final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS);
      +                if (mods.findFirstToken(TokenTypes.LITERAL_STATIC) == null) {
      +                    ((ClassFrame) frame).addInstanceMethod(methodFrameNameIdent);
      +                }
      +                else {
      +                    ((ClassFrame) frame).addStaticMethod(methodFrameNameIdent);
                       }
      -                frameStack.addFirst(new MethodFrame(frame));
      +                frameStack.addFirst(new MethodFrame(frame, methodFrameNameIdent));
                       break;
                   case TokenTypes.CTOR_DEF :
      -                frameStack.addFirst(new MethodFrame(frame));
      +                final DetailAST ctorFrameNameIdent = ast.findFirstToken(TokenTypes.IDENT);
      +                frameStack.addFirst(new ConstructorFrame(frame, ctorFrameNameIdent));
      +                break;
      +            case TokenTypes.ENUM_CONSTANT_DEF :
      +                final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
      +                ((ClassFrame) frame).addStaticMember(ident);
      +                break;
      +            case TokenTypes.LITERAL_CATCH:
      +                final AbstractFrame catchFrame = new CatchFrame(frame, ast);
      +                catchFrame.addIdent(ast.findFirstToken(TokenTypes.PARAMETER_DEF).findFirstToken(
      +                        TokenTypes.IDENT));
      +                frameStack.addFirst(catchFrame);
      +                break;
      +            case TokenTypes.LITERAL_FOR:
      +                final AbstractFrame forFrame = new ForFrame(frame, ast);
      +                frameStack.addFirst(forFrame);
      +                break;
      +            case TokenTypes.LITERAL_NEW:
      +                if (isAnonymousClassDef(ast)) {
      +                    frameStack.addFirst(new AnonymousClassFrame(frame,
      +                            ast.getFirstChild().toString()));
      +                }
                       break;
                   default:
                       // do nothing
      @@ -321,9 +422,9 @@
           }
       
           /**
      -     * Collect Variable Declarations.
      -     * @param ast variable token
      -     * @param frame current frame
      +     * Collects variable declarations.
      +     * @param ast variable token.
      +     * @param frame current frame.
            */
           private static void collectVariableDeclarations(DetailAST ast, AbstractFrame frame) {
               final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT);
      @@ -331,7 +432,7 @@
                   final DetailAST mods =
                           ast.findFirstToken(TokenTypes.MODIFIERS);
                   if (ScopeUtils.isInInterfaceBlock(ast)
      -                    || mods.branchContains(TokenTypes.LITERAL_STATIC)) {
      +                    || mods.findFirstToken(TokenTypes.LITERAL_STATIC) != null) {
                       ((ClassFrame) frame).addStaticMember(ident);
                   }
                   else {
      @@ -344,13 +445,11 @@
           }
       
           /**
      -     * End parsing of the AST for declarations.
      -     *
      -     * @param frameStack Stack containing the FrameTree being built
      -     * @param ast AST that was parsed
      +     * Ends parsing of the AST for declarations.
      +     * @param frameStack Stack containing the FrameTree being built.
      +     * @param ast AST that was parsed.
            */
      -    private void endCollectingDeclarations(Queue frameStack,
      -        DetailAST ast) {
      +    private void endCollectingDeclarations(Queue frameStack, DetailAST ast) {
               switch (ast.getType()) {
                   case TokenTypes.CLASS_DEF :
                   case TokenTypes.INTERFACE_DEF :
      @@ -359,41 +458,431 @@
                   case TokenTypes.SLIST :
                   case TokenTypes.METHOD_DEF :
                   case TokenTypes.CTOR_DEF :
      +            case TokenTypes.LITERAL_CATCH :
      +            case TokenTypes.LITERAL_FOR :
                       frames.put(ast, frameStack.poll());
                       break;
      +            case TokenTypes.LITERAL_NEW :
      +                if (isAnonymousClassDef(ast)) {
      +                    frames.put(ast, frameStack.poll());
      +                }
      +                break;
                   default :
                       // do nothing
               }
           }
       
           /**
      -     * Check if given name is a name for class field in current environment.
      -     * @param ast an IDENT ast to check
      -     * @return frame, where the field is declared, if the violation is found and null otherwise
      -     */
      -    private AbstractFrame checkField(DetailAST ast) {
      -        final AbstractFrame frame = findFrame(ast, false);
      -        if (frame != null
      -                && frame.getType() == FrameType.CLASS_FRAME
      -                && ((ClassFrame) frame).hasInstanceMember(ast)) {
      -            return frame;
      +     * Whether the AST is a definition of an anonymous class.
      +     * @param ast the AST to process.
      +     * @return true if the AST is a definition of an anonymous class.
      +     */
      +    private static boolean isAnonymousClassDef(DetailAST ast) {
      +        final DetailAST lastChild = ast.getLastChild();
      +        return lastChild != null
      +            && lastChild.getType() == TokenTypes.OBJBLOCK;
      +    }
      +
      +    /**
      +     * Returns the class frame where violation is found (where the field is used without 'this')
      +     * or null otherwise.
      +     * @param ast IDENT ast to check.
      +     * @return the class frame where violation is found or null otherwise.
      +     * @noinspection IfStatementWithIdenticalBranches
      +     */
      +    // -@cs[CyclomaticComplexity] Method already invokes too many methods that fully explain
      +    // a logic, additional abstraction will not make logic/algorithm more readable.
      +    private AbstractFrame getClassFrameWhereViolationIsFound(DetailAST ast) {
      +        AbstractFrame frameWhereViolationIsFound = null;
      +        final AbstractFrame variableDeclarationFrame = findFrame(ast, false);
      +        final FrameType variableDeclarationFrameType = variableDeclarationFrame.getType();
      +        final DetailAST prevSibling = ast.getPreviousSibling();
      +        if (variableDeclarationFrameType == FrameType.CLASS_FRAME
      +                && !validateOnlyOverlapping
      +                && prevSibling == null
      +                && canBeReferencedFromStaticContext(ast)) {
      +            frameWhereViolationIsFound = variableDeclarationFrame;
      +        }
      +        else if (variableDeclarationFrameType == FrameType.METHOD_FRAME) {
      +            if (isOverlappingByArgument(ast)) {
      +                if (!isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)
      +                        && !isReturnedVariable(variableDeclarationFrame, ast)
      +                        && canBeReferencedFromStaticContext(ast)
      +                        && canAssignValueToClassField(ast)) {
      +                    frameWhereViolationIsFound = findFrame(ast, true);
      +                }
      +            }
      +            else if (!validateOnlyOverlapping
      +                     && prevSibling == null
      +                     && isAssignToken(ast.getParent().getType())
      +                     && !isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)
      +                     && canBeReferencedFromStaticContext(ast)
      +                     && canAssignValueToClassField(ast)) {
      +                frameWhereViolationIsFound = findFrame(ast, true);
      +            }
      +        }
      +        else if (variableDeclarationFrameType == FrameType.CTOR_FRAME
      +                 && isOverlappingByArgument(ast)
      +                 && !isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)) {
      +            frameWhereViolationIsFound = findFrame(ast, true);
      +        }
      +        else if (variableDeclarationFrameType == FrameType.BLOCK_FRAME
      +                    && isOverlappingByLocalVariable(ast)
      +                    && canAssignValueToClassField(ast)
      +                    && !isUserDefinedArrangementOfThis(variableDeclarationFrame, ast)
      +                    && !isReturnedVariable(variableDeclarationFrame, ast)
      +                    && canBeReferencedFromStaticContext(ast)) {
      +            frameWhereViolationIsFound = findFrame(ast, true);
      +        }
      +        return frameWhereViolationIsFound;
      +    }
      +
      +    /**
      +     * Checks whether user arranges 'this' for variable in method, constructor, or block on his own.
      +     * @param currentFrame current frame.
      +     * @param ident ident token.
      +     * @return true if user arranges 'this' for variable in method, constructor,
      +     *         or block on his own.
      +     */
      +    private static boolean isUserDefinedArrangementOfThis(AbstractFrame currentFrame,
      +                                                          DetailAST ident) {
      +        final DetailAST blockFrameNameIdent = currentFrame.getFrameNameIdent();
      +        final DetailAST definitionToken = blockFrameNameIdent.getParent();
      +        final DetailAST blockStartToken = definitionToken.findFirstToken(TokenTypes.SLIST);
      +        final DetailAST blockEndToken = getBlockEndToken(blockFrameNameIdent, blockStartToken);
      +
      +        boolean userDefinedArrangementOfThis = false;
      +
      +        final Set variableUsagesInsideBlock =
      +            getAllTokensWhichAreEqualToCurrent(definitionToken, ident,
      +                blockEndToken.getLineNo());
      +
      +        for (DetailAST variableUsage : variableUsagesInsideBlock) {
      +            final DetailAST prevSibling = variableUsage.getPreviousSibling();
      +            if (prevSibling != null
      +                    && prevSibling.getType() == TokenTypes.LITERAL_THIS) {
      +                userDefinedArrangementOfThis = true;
      +                break;
      +            }
               }
      -        return null;
      +        return userDefinedArrangementOfThis;
           }
       
           /**
      -     * Check if given name is a name for class method in current environment.
      -     * @param ast the IDENT ast of the name to check
      -     * @return frame, where the method is declared, if the violation is found and null otherwise
      +     * Returns the token which ends the code block.
      +     * @param blockNameIdent block name identifier.
      +     * @param blockStartToken token which starts the block.
      +     * @return the token which ends the code block.
            */
      -    private AbstractFrame checkMethod(DetailAST ast) {
      -        final AbstractFrame frame = findFrame(ast, true);
      -        if (frame != null
      -            && ((ClassFrame) frame).hasInstanceMethod(ast)
      -            && !((ClassFrame) frame).hasStaticMethod(ast)) {
      -            return frame;
      +    private static DetailAST getBlockEndToken(DetailAST blockNameIdent, DetailAST blockStartToken) {
      +        DetailAST blockEndToken = null;
      +        final DetailAST blockNameIdentParent = blockNameIdent.getParent();
      +        if (blockNameIdentParent.getType() == TokenTypes.CASE_GROUP) {
      +            blockEndToken = blockNameIdentParent.getNextSibling();
      +        }
      +        else {
      +            final Set rcurlyTokens = getAllTokensOfType(blockNameIdent,
      +                    TokenTypes.RCURLY);
      +            for (DetailAST currentRcurly : rcurlyTokens) {
      +                final DetailAST parent = currentRcurly.getParent();
      +                if (blockStartToken.getLineNo() == parent.getLineNo()) {
      +                    blockEndToken = currentRcurly;
      +                }
      +            }
               }
      -        return null;
      +        return blockEndToken;
      +    }
      +
      +    /**
      +     * Checks whether the current variable is returned from the method.
      +     * @param currentFrame current frame.
      +     * @param ident variable ident token.
      +     * @return true if the current variable is returned from the method.
      +     */
      +    private static boolean isReturnedVariable(AbstractFrame currentFrame, DetailAST ident) {
      +        final DetailAST blockFrameNameIdent = currentFrame.getFrameNameIdent();
      +        final DetailAST definitionToken = blockFrameNameIdent.getParent();
      +        final DetailAST blockStartToken = definitionToken.findFirstToken(TokenTypes.SLIST);
      +        final DetailAST blockEndToken = getBlockEndToken(blockFrameNameIdent, blockStartToken);
      +
      +        final Set returnsInsideBlock = getAllTokensOfType(definitionToken,
      +            TokenTypes.LITERAL_RETURN, blockEndToken.getLineNo());
      +
      +        boolean returnedVariable = false;
      +        for (DetailAST returnToken : returnsInsideBlock) {
      +            returnedVariable = returnToken.findAll(ident).hasMoreNodes();
      +            if (returnedVariable) {
      +                break;
      +            }
      +        }
      +        return returnedVariable;
      +    }
      +
      +    /**
      +     * Checks whether a field can be referenced from a static context.
      +     * @param ident ident token.
      +     * @return true if field can be referenced from a static context.
      +     */
      +    private boolean canBeReferencedFromStaticContext(DetailAST ident) {
      +        AbstractFrame variableDeclarationFrame = findFrame(ident, false);
      +        boolean staticInitializationBlock = false;
      +        while (variableDeclarationFrame.getType() == FrameType.BLOCK_FRAME
      +                || variableDeclarationFrame.getType() == FrameType.FOR_FRAME) {
      +            final DetailAST blockFrameNameIdent = variableDeclarationFrame.getFrameNameIdent();
      +            final DetailAST definitionToken = blockFrameNameIdent.getParent();
      +            if (definitionToken.getType() == TokenTypes.STATIC_INIT) {
      +                staticInitializationBlock = true;
      +                break;
      +            }
      +            variableDeclarationFrame = variableDeclarationFrame.getParent();
      +        }
      +
      +        boolean staticContext = false;
      +        if (staticInitializationBlock) {
      +            staticContext = true;
      +        }
      +        else {
      +            if (variableDeclarationFrame.getType() == FrameType.CLASS_FRAME) {
      +                final DetailAST codeBlockDefinition = getCodeBlockDefinitionToken(ident);
      +                if (codeBlockDefinition != null) {
      +                    final DetailAST modifiers = codeBlockDefinition.getFirstChild();
      +                    staticContext = codeBlockDefinition.getType() == TokenTypes.STATIC_INIT
      +                        || modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null;
      +                }
      +            }
      +            else {
      +                final DetailAST frameNameIdent = variableDeclarationFrame.getFrameNameIdent();
      +                final DetailAST definitionToken = frameNameIdent.getParent();
      +                staticContext = definitionToken.findFirstToken(TokenTypes.MODIFIERS)
      +                        .findFirstToken(TokenTypes.LITERAL_STATIC) != null;
      +            }
      +        }
      +        return !staticContext;
      +    }
      +
      +    /**
      +     * Returns code block definition token for current identifier.
      +     * @param ident ident token.
      +     * @return code block definition token for current identifier or null if code block
      +     *         definition was not found.
      +     */
      +    private static DetailAST getCodeBlockDefinitionToken(DetailAST ident) {
      +        DetailAST parent = ident.getParent();
      +        while (parent != null
      +               && parent.getType() != TokenTypes.METHOD_DEF
      +               && parent.getType() != TokenTypes.CTOR_DEF
      +               && parent.getType() != TokenTypes.STATIC_INIT) {
      +            parent = parent.getParent();
      +        }
      +        return parent;
      +    }
      +
      +    /**
      +     * Checks whether a value can be assigned to a field.
      +     * A value can be assigned to a final field only in constructor block. If there is a method
      +     * block, value assignment can be performed only to non final field.
      +     * @param ast an identifier token.
      +     * @return true if a value can be assigned to a field.
      +     */
      +    private boolean canAssignValueToClassField(DetailAST ast) {
      +        final AbstractFrame fieldUsageFrame = findFrame(ast, false);
      +        final boolean fieldUsageInConstructor = isInsideConstructorFrame(fieldUsageFrame);
      +
      +        final AbstractFrame declarationFrame = findFrame(ast, true);
      +        final boolean finalField = ((ClassFrame) declarationFrame).hasFinalField(ast);
      +
      +        return fieldUsageInConstructor || !finalField;
      +    }
      +
      +    /**
      +     * Checks whether a field usage frame is inside constructor frame.
      +     * @param frame frame, where field is used.
      +     * @return true if the field usage frame is inside constructor frame.
      +     */
      +    private static boolean isInsideConstructorFrame(AbstractFrame frame) {
      +        boolean assignmentInConstructor = false;
      +        AbstractFrame fieldUsageFrame = frame;
      +        if (fieldUsageFrame.getType() == FrameType.BLOCK_FRAME) {
      +            while (fieldUsageFrame.getType() == FrameType.BLOCK_FRAME) {
      +                fieldUsageFrame = fieldUsageFrame.getParent();
      +            }
      +            if (fieldUsageFrame.getType() == FrameType.CTOR_FRAME) {
      +                assignmentInConstructor = true;
      +            }
      +        }
      +        return assignmentInConstructor;
      +    }
      +
      +    /**
      +     * Checks whether an overlapping by method or constructor argument takes place.
      +     * @param ast an identifier.
      +     * @return true if an overlapping by method or constructor argument takes place.
      +     */
      +    private boolean isOverlappingByArgument(DetailAST ast) {
      +        boolean overlapping = false;
      +        final DetailAST parent = ast.getParent();
      +        final DetailAST sibling = ast.getNextSibling();
      +        if (sibling != null && isAssignToken(parent.getType())) {
      +            if (isCompoundAssignToken(parent.getType())) {
      +                overlapping = true;
      +            }
      +            else {
      +                final ClassFrame classFrame = (ClassFrame) findFrame(ast, true);
      +                final Set exprIdents = getAllTokensOfType(sibling, TokenTypes.IDENT);
      +                overlapping = classFrame.containsFieldOrVariableDef(exprIdents, ast);
      +            }
      +        }
      +        return overlapping;
      +    }
      +
      +    /**
      +     * Checks whether an overlapping by local variable takes place.
      +     * @param ast an identifier.
      +     * @return true if an overlapping by local variable takes place.
      +     */
      +    private boolean isOverlappingByLocalVariable(DetailAST ast) {
      +        boolean overlapping = false;
      +        final DetailAST parent = ast.getParent();
      +        final DetailAST sibling = ast.getNextSibling();
      +        if (sibling != null && isAssignToken(parent.getType())) {
      +            final ClassFrame classFrame = (ClassFrame) findFrame(ast, true);
      +            final Set exprIdents = getAllTokensOfType(sibling, TokenTypes.IDENT);
      +            overlapping = classFrame.containsFieldOrVariableDef(exprIdents, ast);
      +        }
      +        return overlapping;
      +    }
      +
      +    /**
      +     * Collects all tokens of specific type starting with the current ast node.
      +     * @param ast ast node.
      +     * @param tokenType token type.
      +     * @return a set of all tokens of specific type starting with the current ast node.
      +     */
      +    private static Set getAllTokensOfType(DetailAST ast, int tokenType) {
      +        DetailAST vertex = ast;
      +        final Set result = new HashSet<>();
      +        final Deque stack = new ArrayDeque<>();
      +        while (vertex != null || !stack.isEmpty()) {
      +            if (!stack.isEmpty()) {
      +                vertex = stack.pop();
      +            }
      +            while (vertex != null) {
      +                if (vertex.getType() == tokenType) {
      +                    result.add(vertex);
      +                }
      +                if (vertex.getNextSibling() != null) {
      +                    stack.push(vertex.getNextSibling());
      +                }
      +                vertex = vertex.getFirstChild();
      +            }
      +        }
      +        return result;
      +    }
      +
      +    /**
      +     * Collects all tokens of specific type starting with the current ast node and which line
      +     * number is lower or equal to the end line number.
      +     * @param ast ast node.
      +     * @param tokenType token type.
      +     * @param endLineNumber end line number.
      +     * @return a set of all tokens of specific type starting with the current ast node and which
      +     *         line number is lower or equal to the end line number.
      +     */
      +    private static Set getAllTokensOfType(DetailAST ast, int tokenType,
      +                                                     int endLineNumber) {
      +        DetailAST vertex = ast;
      +        final Set result = new HashSet<>();
      +        final Deque stack = new ArrayDeque<>();
      +        while (vertex != null || !stack.isEmpty()) {
      +            if (!stack.isEmpty()) {
      +                vertex = stack.pop();
      +            }
      +            while (vertex != null) {
      +                if (tokenType == vertex.getType()
      +                    && vertex.getLineNo() <= endLineNumber) {
      +                    result.add(vertex);
      +                }
      +                if (vertex.getNextSibling() != null) {
      +                    stack.push(vertex.getNextSibling());
      +                }
      +                vertex = vertex.getFirstChild();
      +            }
      +        }
      +        return result;
      +    }
      +
      +    /**
      +     * Collects all tokens which are equal to current token starting with the current ast node and
      +     * which line number is lower or equal to the end line number.
      +     * @param ast ast node.
      +     * @param token token.
      +     * @param endLineNumber end line number.
      +     * @return a set of tokens which are equal to current token starting with the current ast node
      +     *         and which line number is lower or equal to the end line number.
      +     */
      +    private static Set getAllTokensWhichAreEqualToCurrent(DetailAST ast, DetailAST token,
      +                                                                     int endLineNumber) {
      +        DetailAST vertex = ast;
      +        final Set result = new HashSet<>();
      +        final Deque stack = new ArrayDeque<>();
      +        while (vertex != null || !stack.isEmpty()) {
      +            if (!stack.isEmpty()) {
      +                vertex = stack.pop();
      +            }
      +            while (vertex != null) {
      +                if (token.equals(vertex)
      +                        && vertex.getLineNo() <= endLineNumber) {
      +                    result.add(vertex);
      +                }
      +                if (vertex.getNextSibling() != null) {
      +                    stack.push(vertex.getNextSibling());
      +                }
      +                vertex = vertex.getFirstChild();
      +            }
      +        }
      +        return result;
      +    }
      +
      +    /**
      +     * Returns the frame where the method is declared, if the given method is used without
      +     * 'this' and null otherwise.
      +     * @param ast the IDENT ast of the name to check.
      +     * @return the frame where the method is declared, if the given method is used without
      +     *         'this' and null otherwise.
      +     */
      +    private AbstractFrame getMethodWithoutThis(DetailAST ast) {
      +        AbstractFrame result = null;
      +        if (!validateOnlyOverlapping) {
      +            final AbstractFrame frame = findFrame(ast, true);
      +            if (frame != null
      +                    && ((ClassFrame) frame).hasInstanceMethod(ast)
      +                    && !((ClassFrame) frame).hasStaticMethod(ast)) {
      +                result = frame;
      +            }
      +        }
      +        return result;
      +    }
      +
      +    /**
      +     * Find the class frame containing declaration.
      +     * @param name IDENT ast of the declaration to find.
      +     * @param lookForMethod whether we are looking for a method name.
      +     * @return AbstractFrame containing declaration or null.
      +     */
      +    private AbstractFrame findClassFrame(DetailAST name, boolean lookForMethod) {
      +        AbstractFrame frame = current.peek();
      +
      +        while (true) {
      +            frame = findFrame(frame, name, lookForMethod);
      +
      +            if (frame == null || frame instanceof ClassFrame) {
      +                break;
      +            }
      +
      +            frame = frame.getParent();
      +        }
      +
      +        return frame;
           }
       
           /**
      @@ -403,73 +892,138 @@
            * @return AbstractFrame containing declaration or null.
            */
           private AbstractFrame findFrame(DetailAST name, boolean lookForMethod) {
      -        if (current == null) {
      -            return null;
      -        }
      -        else {
      -            return current.getIfContains(name, lookForMethod);
      -        }
      +        return findFrame(current.peek(), name, lookForMethod);
      +    }
      +
      +    /**
      +     * Find frame containing declaration.
      +     * @param frame The parent frame to searching in.
      +     * @param name IDENT ast of the declaration to find.
      +     * @param lookForMethod whether we are looking for a method name.
      +     * @return AbstractFrame containing declaration or null.
      +     */
      +    private static AbstractFrame findFrame(AbstractFrame frame, DetailAST name,
      +            boolean lookForMethod) {
      +        return frame.getIfContains(name, lookForMethod);
           }
       
           /**
            * Check that token is related to Definition tokens.
      -     * @param parentType token Type
      -     * @return true if token is related to Definition Tokens
      +     * @param parentType token Type.
      +     * @return true if token is related to Definition Tokens.
            */
           private static boolean isDeclarationToken(int parentType) {
               return DECLARATION_TOKENS.contains(parentType);
           }
       
           /**
      -     * Get the name of the nearest parent ClassFrame.
      +     * Check that token is related to assign tokens.
      +     * @param tokenType token type.
      +     * @return true if token is related to assign tokens.
      +     */
      +    private static boolean isAssignToken(int tokenType) {
      +        return ASSIGN_TOKENS.contains(tokenType);
      +    }
      +
      +    /**
      +     * Check that token is related to compound assign tokens.
      +     * @param tokenType token type.
      +     * @return true if token is related to compound assign tokens.
      +     */
      +    private static boolean isCompoundAssignToken(int tokenType) {
      +        return COMPOUND_ASSIGN_TOKENS.contains(tokenType);
      +    }
      +
      +    /**
      +     * Gets the name of the nearest parent ClassFrame.
            * @return the name of the nearest parent ClassFrame.
            */
           private String getNearestClassFrameName() {
      -        AbstractFrame frame = current;
      +        AbstractFrame frame = current.peek();
               while (frame.getType() != FrameType.CLASS_FRAME) {
                   frame = frame.getParent();
               }
               return frame.getFrameName();
           }
       
      +    /**
      +     * Checks if the token is a Lambda parameter.
      +     * @param ast the {@code DetailAST} value of the token to be checked
      +     * @return true if the token is a Lambda parameter
      +     */
      +    private static boolean isLambdaParameter(DetailAST ast) {
      +        DetailAST parent;
      +        for (parent = ast.getParent(); parent != null; parent = parent.getParent()) {
      +            if (parent.getType() == TokenTypes.LAMBDA) {
      +                break;
      +            }
      +        }
      +        final boolean isLambdaParameter;
      +        if (parent == null) {
      +            isLambdaParameter = false;
      +        }
      +        else if (ast.getType() == TokenTypes.PARAMETER_DEF) {
      +            isLambdaParameter = true;
      +        }
      +        else {
      +            final DetailAST lambdaParameters = parent.findFirstToken(TokenTypes.PARAMETERS);
      +            if (lambdaParameters == null) {
      +                isLambdaParameter = parent.getFirstChild().getText().equals(ast.getText());
      +            }
      +            else {
      +                isLambdaParameter = TokenUtils.findFirstTokenByPredicate(lambdaParameters,
      +                    paramDef -> {
      +                        final DetailAST param = paramDef.findFirstToken(TokenTypes.IDENT);
      +                        return param != null && param.getText().equals(ast.getText());
      +                    }).isPresent();
      +            }
      +        }
      +        return isLambdaParameter;
      +    }
      +
           /** An AbstractFrame type. */
           private enum FrameType {
      +
               /** Class frame type. */
               CLASS_FRAME,
      +        /** Constructor frame type. */
      +        CTOR_FRAME,
               /** Method frame type. */
               METHOD_FRAME,
               /** Block frame type. */
               BLOCK_FRAME,
      +        /** Catch frame type. */
      +        CATCH_FRAME,
      +        /** Lambda frame type. */
      +        FOR_FRAME,
      +
           }
       
           /**
            * A declaration frame.
            * @author Stephen Bloch
      +     * @author Andrei Selkin
            */
           private abstract static class AbstractFrame {
      +
               /** Set of name of variables declared in this frame. */
               private final Set varIdents;
       
      -        /**
      -         * Parent frame.
      -         */
      +        /** Parent frame. */
               private final AbstractFrame parent;
       
      -        /**
      -         * Frame name.
      -         */
      -        private final String frameName;
      +        /** Name identifier token. */
      +        private final DetailAST frameNameIdent;
       
               /**
                * Constructor -- invokable only via super() from subclasses.
      -         *
      -         * @param parent parent frame
      -         * @param frameName frame name
      +         * @param parent parent frame.
      +         * @param ident frame name ident.
                */
      -        protected AbstractFrame(AbstractFrame parent, String frameName) {
      +        protected AbstractFrame(AbstractFrame parent, DetailAST ident) {
                   this.parent = parent;
      -            this.frameName = frameName;
      -            varIdents = Sets.newHashSet();
      +            frameNameIdent = ident;
      +            varIdents = new HashSet<>();
               }
       
               /**
      @@ -480,7 +1034,7 @@
       
               /**
                * Add a name to the frame.
      -         * @param identToAdd the name we're adding
      +         * @param identToAdd the name we're adding.
                */
               private void addIdent(DetailAST identToAdd) {
                   varIdents.add(identToAdd);
      @@ -491,18 +1045,24 @@
               }
       
               protected String getFrameName() {
      -            return frameName;
      +            return frameNameIdent.getText();
      +        }
      +
      +        public DetailAST getFrameNameIdent() {
      +            return frameNameIdent;
               }
       
      -        /** Check whether the frame contains a field or a variable with the given name.
      -         * @param nameToFind the IDENT ast of the name we're looking for
      -         * @return whether it was found
      +        /**
      +         * Check whether the frame contains a field or a variable with the given name.
      +         * @param nameToFind the IDENT ast of the name we're looking for.
      +         * @return whether it was found.
                */
      -        boolean containsFieldOrVariable(DetailAST nameToFind) {
      +        protected boolean containsFieldOrVariable(DetailAST nameToFind) {
                   return containsFieldOrVariableDef(varIdents, nameToFind);
               }
       
      -        /** Check whether the frame contains a given name.
      +        /**
      +         * Check whether the frame contains a given name.
                * @param nameToFind IDENT ast of the name we're looking for.
                * @param lookForMethod whether we are looking for a method name.
                * @return whether it was found.
      @@ -524,7 +1084,7 @@
                * Whether the set contains a declaration with the text of the specified
                * IDENT ast and it is declared in a proper position.
                * @param set the set of declarations.
      -         * @param ident the specified IDENT ast
      +         * @param ident the specified IDENT ast.
                * @return true if the set contains a declaration with the text of the specified
                *         IDENT ast and it is declared in a proper position.
                */
      @@ -560,38 +1120,67 @@
               private static boolean checkPosition(DetailAST ast1, DetailAST ast2) {
                   boolean result = false;
                   if (ast1.getLineNo() < ast2.getLineNo()
      -                || ast1.getLineNo() == ast2.getLineNo()
      -                && ast1.getColumnNo() < ast2.getColumnNo()) {
      +                    || ast1.getLineNo() == ast2.getLineNo()
      +                    && ast1.getColumnNo() < ast2.getColumnNo()) {
                       result = true;
                   }
                   return result;
               }
      +
           }
       
           /**
      -     * A frame initiated at method definition; holds parameter names.
      +     * A frame initiated at method definition; holds a method definition token.
            * @author Stephen Bloch
      +     * @author Andrei Selkin
            */
           private static class MethodFrame extends AbstractFrame {
      +
               /**
                * Creates method frame.
      -         * @param parent parent frame
      +         * @param parent parent frame.
      +         * @param ident method name identifier token.
                */
      -        protected MethodFrame(AbstractFrame parent) {
      -            super(parent, null);
      +        protected MethodFrame(AbstractFrame parent, DetailAST ident) {
      +            super(parent, ident);
               }
       
               @Override
               protected FrameType getType() {
                   return FrameType.METHOD_FRAME;
               }
      +
           }
       
           /**
      -     * A frame initiated at class< enum or interface definition; holds instance variable names.
      +     * A frame initiated at constructor definition.
      +     * @author Andrei Selkin
      +     */
      +    private static class ConstructorFrame extends AbstractFrame {
      +
      +        /**
      +         * Creates a constructor frame.
      +         * @param parent parent frame.
      +         * @param ident frame name ident.
      +         */
      +        protected ConstructorFrame(AbstractFrame parent, DetailAST ident) {
      +            super(parent, ident);
      +        }
      +
      +        @Override
      +        protected FrameType getType() {
      +            return FrameType.CTOR_FRAME;
      +        }
      +
      +    }
      +
      +    /**
      +     * A frame initiated at class, enum or interface definition; holds instance variable names.
            * @author Stephen Bloch
      +     * @author Andrei Selkin
            */
           private static class ClassFrame extends AbstractFrame {
      +
               /** Set of idents of instance members declared in this frame. */
               private final Set instanceMembers;
               /** Set of idents of instance methods declared in this frame. */
      @@ -603,15 +1192,15 @@
       
               /**
                * Creates new instance of ClassFrame.
      -         * @param parent parent frame
      -         * @param frameName frame name
      +         * @param parent parent frame.
      +         * @param ident frame name ident.
                */
      -        ClassFrame(AbstractFrame parent, String frameName) {
      -            super(parent, frameName);
      -            instanceMembers = Sets.newHashSet();
      -            instanceMethods = Sets.newHashSet();
      -            staticMembers = Sets.newHashSet();
      -            staticMethods = Sets.newHashSet();
      +        ClassFrame(AbstractFrame parent, DetailAST ident) {
      +            super(parent, ident);
      +            instanceMembers = new HashSet<>();
      +            instanceMethods = new HashSet<>();
      +            staticMembers = new HashSet<>();
      +            staticMethods = new HashSet<>();
               }
       
               @Override
      @@ -621,7 +1210,7 @@
       
               /**
                * Adds static member's ident.
      -         * @param ident an ident of static member of the class
      +         * @param ident an ident of static member of the class.
                */
               public void addStaticMember(final DetailAST ident) {
                   staticMembers.add(ident);
      @@ -629,7 +1218,7 @@
       
               /**
                * Adds static method's name.
      -         * @param ident an ident of static method of the class
      +         * @param ident an ident of static method of the class.
                */
               public void addStaticMethod(final DetailAST ident) {
                   staticMethods.add(ident);
      @@ -637,7 +1226,7 @@
       
               /**
                * Adds instance member's ident.
      -         * @param ident an ident of instance member of the class
      +         * @param ident an ident of instance member of the class.
                */
               public void addInstanceMember(final DetailAST ident) {
                   instanceMembers.add(ident);
      @@ -645,7 +1234,7 @@
       
               /**
                * Adds instance method's name.
      -         * @param ident an ident of instance method of the class
      +         * @param ident an ident of instance method of the class.
                */
               public void addInstanceMethod(final DetailAST ident) {
                   instanceMethods.add(ident);
      @@ -653,9 +1242,9 @@
       
               /**
                * Checks if a given name is a known instance member of the class.
      -         * @param ident the IDENT ast of the name to check
      +         * @param ident the IDENT ast of the name to check.
                * @return true is the given name is a name of a known
      -         *         instance member of the class
      +         *         instance member of the class.
                */
               public boolean hasInstanceMember(final DetailAST ident) {
                   return containsFieldOrVariableDef(instanceMembers, ident);
      @@ -663,9 +1252,9 @@
       
               /**
                * Checks if a given name is a known instance method of the class.
      -         * @param ident the IDENT ast of the method call to check
      +         * @param ident the IDENT ast of the method call to check.
                * @return true if the given ast is correspondent to a known
      -         *         instance method of the class
      +         *         instance method of the class.
                */
               public boolean hasInstanceMethod(final DetailAST ident) {
                   return containsMethodDef(instanceMethods, ident);
      @@ -673,16 +1262,34 @@
       
               /**
                * Checks if a given name is a known static method of the class.
      -         * @param ident the IDENT ast of the method call to check
      +         * @param ident the IDENT ast of the method call to check.
                * @return true is the given ast is correspondent to a known
      -         *         instance method of the class
      +         *         instance method of the class.
                */
               public boolean hasStaticMethod(final DetailAST ident) {
                   return containsMethodDef(staticMethods, ident);
               }
       
      +        /**
      +         * Checks whether given instance member has final modifier.
      +         * @param instanceMember an instance member of a class.
      +         * @return true if given instance member has final modifier.
      +         */
      +        public boolean hasFinalField(final DetailAST instanceMember) {
      +            boolean result = false;
      +            for (DetailAST member : instanceMembers) {
      +                final DetailAST mods = member.getParent().findFirstToken(TokenTypes.MODIFIERS);
      +                final boolean finalMod = mods.findFirstToken(TokenTypes.FINAL) != null;
      +                if (finalMod && member.equals(instanceMember)) {
      +                    result = true;
      +                    break;
      +                }
      +            }
      +            return result;
      +        }
      +
               @Override
      -        boolean containsFieldOrVariable(DetailAST nameToFind) {
      +        protected boolean containsFieldOrVariable(DetailAST nameToFind) {
                   return containsFieldOrVariableDef(instanceMembers, nameToFind)
                           || containsFieldOrVariableDef(staticMembers, nameToFind);
               }
      @@ -725,7 +1332,7 @@
                * @return true if the set contains a definition with the
                *     same name and number of parameters.
                */
      -        private boolean containsMethodDef(Set set, DetailAST ident) {
      +        private static boolean containsMethodDef(Set set, DetailAST ident) {
                   boolean result = false;
                   for (DetailAST ast: set) {
                       if (isSimilarSignature(ident, ast)) {
      @@ -743,17 +1350,43 @@
                * @return true if a method definition has the same name and number of parameters
                *     as the method call.
                */
      -        private boolean isSimilarSignature(DetailAST ident, DetailAST ast) {
      +        private static boolean isSimilarSignature(DetailAST ident, DetailAST ast) {
                   boolean result = false;
      -            if (ident.getText().equals(ast.getText())) {
      -                final int paramsNumber = ast.getParent().findFirstToken(TokenTypes.PARAMETERS)
      -                    .getChildCount();
      -                final int argsNumber = ident.getParent().findFirstToken(TokenTypes.ELIST)
      -                    .getChildCount();
      +            final DetailAST elistToken = ident.getParent().findFirstToken(TokenTypes.ELIST);
      +            if (elistToken != null && ident.getText().equals(ast.getText())) {
      +                final int paramsNumber =
      +                    ast.getParent().findFirstToken(TokenTypes.PARAMETERS).getChildCount();
      +                final int argsNumber = elistToken.getChildCount();
                       result = paramsNumber == argsNumber;
                   }
                   return result;
               }
      +
      +    }
      +
      +    /**
      +     * An anonymous class frame; holds instance variable names.
      +     */
      +    private static class AnonymousClassFrame extends ClassFrame {
      +
      +        /** The name of the frame. */
      +        private final String frameName;
      +
      +        /**
      +         * Creates anonymous class frame.
      +         * @param parent parent frame.
      +         * @param frameName name of the frame.
      +         */
      +        protected AnonymousClassFrame(AbstractFrame parent, String frameName) {
      +            super(parent, null);
      +            this.frameName = frameName;
      +        }
      +
      +        @Override
      +        protected String getFrameName() {
      +            return frameName;
      +        }
      +
           }
       
           /**
      @@ -764,15 +1397,62 @@
       
               /**
                * Creates block frame.
      -         * @param parent parent frame
      +         * @param parent parent frame.
      +         * @param ident ident frame name ident.
                */
      -        protected BlockFrame(AbstractFrame parent) {
      -            super(parent, null);
      +        protected BlockFrame(AbstractFrame parent, DetailAST ident) {
      +            super(parent, ident);
               }
       
               @Override
               protected FrameType getType() {
                   return FrameType.BLOCK_FRAME;
               }
      +
      +    }
      +
      +    /**
      +     * A frame initiated on entering a catch block; holds local catch variable names.
      +     * @author Richard Veach
      +     */
      +    public static class CatchFrame extends AbstractFrame {
      +
      +        /**
      +         * Creates catch frame.
      +         * @param parent parent frame.
      +         * @param ident ident frame name ident.
      +         */
      +        protected CatchFrame(AbstractFrame parent, DetailAST ident) {
      +            super(parent, ident);
      +        }
      +
      +        @Override
      +        public FrameType getType() {
      +            return FrameType.CATCH_FRAME;
      +        }
      +
      +    }
      +
      +    /**
      +     * A frame initiated on entering a for block; holds local for variable names.
      +     * @author Richard Veach
      +     */
      +    public static class ForFrame extends AbstractFrame {
      +
      +        /**
      +         * Creates for frame.
      +         * @param parent parent frame.
      +         * @param ident ident frame name ident.
      +         */
      +        protected ForFrame(AbstractFrame parent, DetailAST ident) {
      +            super(parent, ident);
      +        }
      +
      +        @Override
      +        public FrameType getType() {
      +            return FrameType.FOR_FRAME;
      +        }
      +
           }
      +
       }
      diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ReturnCountCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ReturnCountCheck.java
      --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ReturnCountCheck.java	2016-01-30 23:19:28.000000000 +0000
      +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/ReturnCountCheck.java	2018-01-14 13:38:20.000000000 +0000
      @@ -1,6 +1,6 @@
       ////////////////////////////////////////////////////////////////////////////////
       // checkstyle: Checks Java source code for adherence to a set of rules.
      -// Copyright (C) 2001-2016 the original author or authors.
      +// Copyright (C) 2001-2018 the original author or authors.
       //
       // This library is free software; you can redistribute it and/or
       // modify it under the terms of the GNU Lesser General Public
      @@ -23,10 +23,10 @@
       import java.util.Deque;
       import java.util.regex.Pattern;
       
      -import com.puppycrawl.tools.checkstyle.api.Check;
      +import com.puppycrawl.tools.checkstyle.FileStatefulCheck;
      +import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
       import com.puppycrawl.tools.checkstyle.api.DetailAST;
       import com.puppycrawl.tools.checkstyle.api.TokenTypes;
      -import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
       
       /**
        * 

      @@ -34,30 +34,48 @@ * (2 by default). Ignores specified methods ({@code equals()} by default). *

      *

      + * max property will only check returns in methods and lambdas that + * return a specific value (Ex: 'return 1;'). + *

      + *

      + * maxForVoid property will only check returns in methods, constructors, + * and lambdas that have no return type (IE 'return;'). It will only count + * visible return statements. Return statements not normally written, but + * implied, at the end of the method/constructor definition will not be taken + * into account. To disallow "return;" in void return type methods, use a value + * of 0. + *

      + *

      * Rationale: Too many return points can be indication that code is * attempting to do too much or may be difficult to understand. *

      * * @author Simon Harris */ -public final class ReturnCountCheck extends Check { +@FileStatefulCheck +public final class ReturnCountCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" * file. */ public static final String MSG_KEY = "return.count"; + /** + * A key pointing to the warning message text in "messages.properties" + * file. + */ + public static final String MSG_KEY_VOID = "return.countVoid"; /** Stack of method contexts. */ private final Deque contextStack = new ArrayDeque<>(); - /** The format string of the regexp. */ - private String format = "^equals$"; /** The regexp to match against. */ - private Pattern regexp = Pattern.compile(format); + private Pattern format = Pattern.compile("^equals$"); /** Maximum allowed number of return statements. */ private int max = 2; + /** Maximum allowed number of return statements for void methods. */ + private int maxForVoid = 1; /** Current method context. */ private Context context; @@ -87,21 +105,11 @@ } /** - * Set the format to the specified regular expression. - * @param format a {@code String} value - * @throws org.apache.commons.beanutils.ConversionException unable to parse format + * Set the format for the specified regular expression. + * @param pattern a pattern. */ - public void setFormat(String format) { - this.format = format; - regexp = CommonUtils.createPattern(format); - } - - /** - * Getter for max property. - * @return maximum allowed number of return statements. - */ - public int getMax() { - return max; + public void setFormat(Pattern pattern) { + format = pattern; } /** @@ -112,6 +120,14 @@ this.max = max; } + /** + * Setter for maxForVoid property. + * @param maxForVoid maximum allowed number of return statements for void methods. + */ + public void setMaxForVoid(int maxForVoid) { + this.maxForVoid = maxForVoid; + } + @Override public void beginTree(DetailAST rootAST) { context = new Context(false); @@ -129,7 +145,7 @@ visitLambda(); break; case TokenTypes.LITERAL_RETURN: - context.visitLiteralReturn(); + visitReturn(ast); break; default: throw new IllegalStateException(ast.toString()); @@ -159,7 +175,7 @@ private void visitMethodDef(DetailAST ast) { contextStack.push(context); final DetailAST methodNameAST = ast.findFirstToken(TokenTypes.IDENT); - final boolean check = !regexp.matcher(methodNameAST.getText()).find(); + final boolean check = !format.matcher(methodNameAST.getText()).find(); context = new Context(check); } @@ -181,14 +197,34 @@ } /** + * Examines the return statement and tells context about it. + * @param ast return statement to check. + */ + private void visitReturn(DetailAST ast) { + // we can't identify which max to use for lambdas, so we can only assign + // after the first return statement is seen + if (ast.getFirstChild().getType() == TokenTypes.SEMI) { + context.visitLiteralReturn(maxForVoid, true); + } + else { + context.visitLiteralReturn(max, false); + } + } + + /** * Class to encapsulate information about one method. * @author Simon Harris */ private class Context { + /** Whether we should check this method or not. */ private final boolean checking; /** Counter for return statements. */ private int count; + /** Maximum allowed number of return statements. */ + private Integer maxAllowed; + /** Identifies if context is void. */ + private boolean isVoidContext; /** * Creates new method context. @@ -196,24 +232,38 @@ */ Context(boolean checking) { this.checking = checking; - count = 0; } - /** Increase number of return statements. */ - public void visitLiteralReturn() { + /** + * Increase the number of return statements and set context return type. + * @param maxAssigned Maximum allowed number of return statements. + * @param voidReturn Identifies if context is void. + */ + public void visitLiteralReturn(int maxAssigned, Boolean voidReturn) { + isVoidContext = voidReturn; + if (maxAllowed == null) { + maxAllowed = maxAssigned; + } + ++count; } /** - * Checks if number of return statements in method more + * Checks if number of return statements in the method are more * than allowed. * @param ast method def associated with this context. */ public void checkCount(DetailAST ast) { - if (checking && count > getMax()) { - log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY, - count, getMax()); + if (checking && maxAllowed != null && count > maxAllowed) { + if (isVoidContext) { + log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY_VOID, count, maxAllowed); + } + else { + log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY, count, maxAllowed); + } } } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SimplifyBooleanExpressionCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SimplifyBooleanExpressionCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SimplifyBooleanExpressionCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SimplifyBooleanExpressionCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -40,8 +41,9 @@ *
      * @author lkuehne */ +@StatelessCheck public class SimplifyBooleanExpressionCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -51,17 +53,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.LITERAL_TRUE, TokenTypes.LITERAL_FALSE}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.LITERAL_TRUE, TokenTypes.LITERAL_FALSE}; } @Override @@ -80,4 +82,5 @@ break; } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SimplifyBooleanReturnCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SimplifyBooleanReturnCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SimplifyBooleanReturnCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SimplifyBooleanReturnCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,8 +20,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; import antlr.collections.AST; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -38,8 +38,9 @@ * * @author Lars Kühne */ +@StatelessCheck public class SimplifyBooleanReturnCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -49,17 +50,17 @@ @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.LITERAL_IF}; + return getRequiredTokens(); } @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.LITERAL_IF}; } @Override @@ -74,18 +75,17 @@ // don't bother if this is not if then else final AST elseLiteral = ast.findFirstToken(TokenTypes.LITERAL_ELSE); - if (elseLiteral == null) { - return; - } - final AST elseStatement = elseLiteral.getFirstChild(); + if (elseLiteral != null) { + final AST elseStatement = elseLiteral.getFirstChild(); - // skip '(' and ')' - final AST condition = ast.getFirstChild().getNextSibling(); - final AST thenStatement = condition.getNextSibling().getNextSibling(); - - if (canReturnOnlyBooleanLiteral(thenStatement) - && canReturnOnlyBooleanLiteral(elseStatement)) { - log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY); + // skip '(' and ')' + final AST condition = ast.getFirstChild().getNextSibling(); + final AST thenStatement = condition.getNextSibling().getNextSibling(); + + if (canReturnOnlyBooleanLiteral(thenStatement) + && canReturnOnlyBooleanLiteral(elseStatement)) { + log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY); + } } } @@ -110,12 +110,12 @@ * @return if ast is a return statement with a boolean literal. */ private static boolean canReturnOnlyBooleanLiteral(AST ast) { - if (isBooleanLiteralReturnStatement(ast)) { - return true; + boolean result = true; + if (!isBooleanLiteralReturnStatement(ast)) { + final AST firstStatement = ast.getFirstChild(); + result = isBooleanLiteralReturnStatement(firstStatement); } - - final AST firstStatement = ast.getFirstChild(); - return isBooleanLiteralReturnStatement(firstStatement); + return result; } /** @@ -154,4 +154,5 @@ final boolean isFalse = tokenType == TokenTypes.LITERAL_FALSE; return isTrue || isFalse; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/StringLiteralEqualityCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/StringLiteralEqualityCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/StringLiteralEqualityCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/StringLiteralEqualityCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,24 +20,26 @@ package com.puppycrawl.tools.checkstyle.checks.coding; import antlr.collections.AST; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; /** *

      Checks that string literals are not used with - * {@code ==} or {@code !=}. + * {@code ==} or !=. *

      *

      * Rationale: Novice Java programmers often use code like - * {@code if (x == "something")} when they mean - * {@code if ("something".equals(x))}. + * {@code if (x == "something")} when they mean + * {@code if ("something".equals(x))}. *

      * * @author Lars Kühne + * @noinspection HtmlTagCanBeJavadocTag */ -public class StringLiteralEqualityCheck extends Check { +@StatelessCheck +public class StringLiteralEqualityCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -47,17 +49,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.EQUAL, TokenTypes.NOT_EQUAL}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.EQUAL, TokenTypes.NOT_EQUAL}; } @Override @@ -72,4 +74,5 @@ MSG_KEY, ast.getText()); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SuperCloneCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SuperCloneCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SuperCloneCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SuperCloneCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,6 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; +import com.puppycrawl.tools.checkstyle.StatelessCheck; + /** *

      * Checks that an overriding clone() method invokes super.clone(). @@ -26,7 +28,7 @@ *

      *

      * Reference: + * href="https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#clone--"> * Object.clone. *

      *

      @@ -37,9 +39,12 @@ * * @author Rick Giles */ +@StatelessCheck public class SuperCloneCheck extends AbstractSuperCheck { + @Override protected String getMethodName() { return "clone"; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/SuperFinalizeCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,6 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.coding; +import com.puppycrawl.tools.checkstyle.StatelessCheck; + /** *

      * Checks that an overriding finalize() method invokes super.finalize(). @@ -26,8 +28,8 @@ *

      *

      * Reference: - * Cleaning up unused objects. + * href="http://javarevisited.blogspot.com/2012/03/finalize-method-in-java-tutorial.html"> + * 10 points on finalize method in Java. *

      *

      * An example of how to configure the check is: @@ -37,9 +39,12 @@ * * @author Rick Giles */ +@StatelessCheck public class SuperFinalizeCheck extends AbstractSuperCheck { + @Override protected String getMethodName() { return "finalize"; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessaryParenthesesCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessaryParenthesesCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessaryParenthesesCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/UnnecessaryParenthesesCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,11 +19,11 @@ package com.puppycrawl.tools.checkstyle.checks.coding; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

      @@ -52,7 +52,8 @@ * * @author Eric Roe */ -public class UnnecessaryParenthesesCheck extends Check { +@FileStatefulCheck +public class UnnecessaryParenthesesCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -90,6 +91,12 @@ */ public static final String MSG_RETURN = "unnecessary.paren.return"; + /** + * A key is pointing to the warning message text in "messages.properties" + * file. + */ + public static final String MSG_LAMBDA = "unnecessary.paren.lambda"; + /** The maximum string length before we chop the string. */ private static final int MAX_QUOTED_LENGTH = 25; @@ -154,6 +161,7 @@ TokenTypes.SL_ASSIGN, TokenTypes.SR_ASSIGN, TokenTypes.STAR_ASSIGN, + TokenTypes.LAMBDA, }; } @@ -182,23 +190,27 @@ TokenTypes.SL_ASSIGN, TokenTypes.SR_ASSIGN, TokenTypes.STAR_ASSIGN, + TokenTypes.LAMBDA, }; } @Override public int[] getRequiredTokens() { // Check can work with any of acceptable tokens - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } + // -@cs[CyclomaticComplexity] All logs should be in visit token. @Override public void visitToken(DetailAST ast) { final int type = ast.getType(); final DetailAST parent = ast.getParent(); - if (type != TokenTypes.ASSIGN + if (type == TokenTypes.LAMBDA && isLambdaSingleParameterSurrounded(ast)) { + log(ast, MSG_LAMBDA, ast.getText()); + } + else if (type != TokenTypes.ASSIGN || parent.getType() != TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) { - final boolean surrounded = isSurrounded(ast); // An identifier surrounded by parentheses. if (surrounded && type == TokenTypes.IDENT) { @@ -232,38 +244,33 @@ final int type = ast.getType(); final DetailAST parent = ast.getParent(); - if (type == TokenTypes.ASSIGN - && parent.getType() == TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) { - // shouldn't process assign in annotation pairs - return; - } - - // An expression is surrounded by parentheses. - if (type == TokenTypes.EXPR) { - - // If 'parentToSkip' == 'ast', then we've already logged a - // warning about an immediate child node in visitToken, so we don't - // need to log another one here. - - if (parentToSkip != ast && isExprSurrounded(ast)) { - if (assignDepth >= 1) { - log(ast, MSG_ASSIGN); - } - else if (ast.getParent().getType() == TokenTypes.LITERAL_RETURN) { - log(ast, MSG_RETURN); - } - else { - log(ast, MSG_EXPR); + // shouldn't process assign in annotation pairs + if (type != TokenTypes.ASSIGN + || parent.getType() != TokenTypes.ANNOTATION_MEMBER_VALUE_PAIR) { + // An expression is surrounded by parentheses. + if (type == TokenTypes.EXPR) { + // If 'parentToSkip' == 'ast', then we've already logged a + // warning about an immediate child node in visitToken, so we don't + // need to log another one here. + + if (parentToSkip != ast && isExprSurrounded(ast)) { + if (assignDepth >= 1) { + log(ast, MSG_ASSIGN); + } + else if (ast.getParent().getType() == TokenTypes.LITERAL_RETURN) { + log(ast, MSG_RETURN); + } + else { + log(ast, MSG_EXPR); + } } - } - parentToSkip = null; - } - else if (isInTokenList(type, ASSIGNMENTS)) { - assignDepth--; + parentToSkip = null; + } + else if (isInTokenList(type, ASSIGNMENTS)) { + assignDepth--; + } } - - super.leaveToken(ast); } /** @@ -295,6 +302,22 @@ } /** + * Tests if the given lambda node has a single parameter, no defined type, and is surrounded + * by parentheses. + * @param ast a {@code DetailAST} whose type is + * {@code TokenTypes.LAMBDA}. + * @return {@code true} if the lambda has a single parameter, no defined type, and is + * surrounded by parentheses. + */ + private static boolean isLambdaSingleParameterSurrounded(DetailAST ast) { + final DetailAST firstChild = ast.getFirstChild(); + return firstChild.getType() == TokenTypes.LPAREN + && firstChild.getNextSibling().getChildCount(TokenTypes.PARAMETER_DEF) == 1 + && firstChild.getNextSibling().getFirstChild().findFirstToken(TokenTypes.TYPE) + .getChildCount() == 0; + } + + /** * Check if the given token type can be found in an array of token types. * @param type the token type. * @param tokens an array of token types to search. @@ -322,9 +345,11 @@ * {@code MAX_QUOTED_LENGTH}; otherwise {@code string}. */ private static String chopString(String value) { + String result = value; if (value.length() > MAX_QUOTED_LENGTH) { - return value.substring(0, MAX_QUOTED_LENGTH) + "...\""; + result = value.substring(0, MAX_QUOTED_LENGTH) + "...\""; } - return value; + return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/VariableDeclarationUsageDistanceCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/VariableDeclarationUsageDistanceCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/VariableDeclarationUsageDistanceCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/coding/VariableDeclarationUsageDistanceCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -27,12 +27,11 @@ import java.util.regex.Pattern; import antlr.collections.ASTEnumeration; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

      @@ -165,7 +164,9 @@ * @author Ruslan Diachenko * @author Baratali Izmailov */ -public class VariableDeclarationUsageDistanceCheck extends Check { +@StatelessCheck +public class VariableDeclarationUsageDistanceCheck extends AbstractCheck { + /** * Warning message key. */ @@ -213,13 +214,10 @@ /** * Sets RegExp pattern to ignore distance calculation for variables listed in this pattern. - * @param ignorePattern - * Pattern contains ignored variables. - * @throws org.apache.commons.beanutils.ConversionException - * if unable to create Pattern object. + * @param pattern a pattern. */ - public void setIgnoreVariablePattern(String ignorePattern) { - ignoreVariablePattern = CommonUtils.createPattern(ignorePattern); + public void setIgnoreVariablePattern(Pattern pattern) { + ignoreVariablePattern = pattern; } /** @@ -244,17 +242,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.VARIABLE_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.VARIABLE_DEF}; } @Override @@ -263,7 +261,7 @@ final DetailAST modifiers = ast.getFirstChild(); if (parentType != TokenTypes.OBJBLOCK - && (!ignoreFinal || !modifiers.branchContains(TokenTypes.FINAL))) { + && (!ignoreFinal || modifiers.findFirstToken(TokenTypes.FINAL) == null)) { final DetailAST variable = ast.findFirstToken(TokenTypes.IDENT); if (!isVariableMatchesIgnorePattern(variable.getText())) { @@ -329,9 +327,7 @@ while (result && !isUsedVariableDeclarationFound && currentSiblingAst != null) { - switch (currentSiblingAst.getType()) { - case TokenTypes.EXPR: final DetailAST methodCallAst = currentSiblingAst.getFirstChild(); @@ -397,38 +393,8 @@ while (!firstUsageFound && currentAst != null && currentAst.getType() != TokenTypes.RCURLY) { if (currentAst.getFirstChild() != null) { - if (isChild(currentAst, variableIdentAst)) { - - switch (currentAst.getType()) { - case TokenTypes.VARIABLE_DEF: - dist++; - break; - case TokenTypes.SLIST: - dist = 0; - break; - case TokenTypes.LITERAL_FOR: - case TokenTypes.LITERAL_WHILE: - case TokenTypes.LITERAL_DO: - case TokenTypes.LITERAL_IF: - case TokenTypes.LITERAL_SWITCH: - if (isVariableInOperatorExpr(currentAst, variableIdentAst)) { - dist++; - } - else { - // variable usage is in inner scope - // reset counters, because we can't determine distance - dist = 0; - } - break; - default: - if (currentAst.branchContains(TokenTypes.SLIST)) { - dist = 0; - } - else { - dist++; - } - } + dist = getDistToVariableUsageInChildNode(currentAst, variableIdentAst, dist); variableUsageAst = currentAst; firstUsageFound = true; } @@ -448,6 +414,53 @@ } /** + * Returns the distance to variable usage for in the child node. + * @param childNode child node. + * @param varIdent variable variable identifier. + * @param currentDistToVarUsage current distance to the variable usage. + * @return the distance to variable usage for in the child node. + */ + private static int getDistToVariableUsageInChildNode(DetailAST childNode, DetailAST varIdent, + int currentDistToVarUsage) { + DetailAST examineNode = childNode; + if (examineNode.getType() == TokenTypes.LABELED_STAT) { + examineNode = examineNode.getFirstChild().getNextSibling(); + } + + int resultDist = currentDistToVarUsage; + switch (examineNode.getType()) { + case TokenTypes.VARIABLE_DEF: + resultDist++; + break; + case TokenTypes.SLIST: + resultDist = 0; + break; + case TokenTypes.LITERAL_FOR: + case TokenTypes.LITERAL_WHILE: + case TokenTypes.LITERAL_DO: + case TokenTypes.LITERAL_IF: + case TokenTypes.LITERAL_SWITCH: + if (isVariableInOperatorExpr(examineNode, varIdent)) { + resultDist++; + } + else { + // variable usage is in inner scope + // reset counters, because we can't determine distance + resultDist = 0; + } + break; + default: + if (examineNode.findFirstToken(TokenTypes.SLIST) == null) { + resultDist++; + } + else { + resultDist = 0; + } + } + return resultDist; + } + + /** * Calculates distance between declaration of variable and its first usage * in multiple scopes. * @param ast @@ -512,16 +525,17 @@ variableUsageAst = exprWithVariableUsage; } } + + // If there's no any variable usage, then distance = 0. + else if (variableUsageExpressions.isEmpty()) { + variableUsageAst = null; + } // If variable usage exists in different scopes, then distance = // distance until variable first usage. - else if (variableUsageExpressions.size() > 1) { + else { dist++; variableUsageAst = variableUsageExpressions.get(0); } - // If there's no any variable usage, then distance = 0. - else { - variableUsageAst = null; - } } return new SimpleEntry<>(variableUsageAst, dist); } @@ -672,7 +686,6 @@ */ private static DetailAST getFirstNodeInsideSwitchBlock( DetailAST block, DetailAST variable) { - DetailAST currentNode = block .findFirstToken(TokenTypes.CASE_GROUP); final List variableUsageExpressions = @@ -784,7 +797,6 @@ // Look if variable is in operator expression while (exprBetweenBrackets.getType() != TokenTypes.RPAREN) { - if (isChild(exprBetweenBrackets, variable)) { isVarInOperatorDeclaration = true; break; @@ -828,7 +840,6 @@ DetailAST astParent = astNode.getParent(); while (astParent != null) { - if (astParent.equals(parent) && astParent.getLineNo() == parent.getLineNo()) { isChild = true; @@ -851,4 +862,5 @@ final Matcher matcher = ignoreVariablePattern.matcher(variable); return matcher.matches(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/DescendantTokenCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/DescendantTokenCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/DescendantTokenCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/DescendantTokenCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,12 +22,11 @@ import java.util.Arrays; import java.util.Set; -import org.apache.commons.lang3.ArrayUtils; - import antlr.collections.AST; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.TokenUtils; /** @@ -167,7 +166,8 @@ * @author Tim Tyler <tim@tt1.org> * @author Rick Giles */ -public class DescendantTokenCheck extends Check { +@FileStatefulCheck +public class DescendantTokenCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -204,7 +204,7 @@ /** Whether to sum the number of tokens found. */ private boolean sumTokenCounts; /** Limited tokens. */ - private int[] limitedTokens = ArrayUtils.EMPTY_INT_ARRAY; + private int[] limitedTokens = CommonUtils.EMPTY_INT_ARRAY; /** Error message when minimum count not reached. */ private String minimumMessage; /** Error message when maximum count exceeded. */ @@ -214,16 +214,16 @@ * Counts of descendant tokens. * Indexed by (token ID - 1) for performance. */ - private int[] counts = ArrayUtils.EMPTY_INT_ARRAY; + private int[] counts = CommonUtils.EMPTY_INT_ARRAY; @Override public int[] getDefaultTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -357,7 +357,7 @@ int maxToken = 0; for (int i = 0; i < limitedTokensParam.length; i++) { limitedTokens[i] = TokenUtils.getTokenId(limitedTokensParam[i]); - if (limitedTokens[i] > maxToken) { + if (limitedTokens[i] >= maxToken + 1) { maxToken = limitedTokens[i]; } } @@ -435,4 +435,5 @@ public void setSumTokenCounts(boolean sum) { sumTokenCounts = sum; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/DesignForExtensionCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/DesignForExtensionCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/DesignForExtensionCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/DesignForExtensionCheck.java 2018-01-22 14:58:53.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,43 +19,80 @@ package com.puppycrawl.tools.checkstyle.checks.design; -import com.puppycrawl.tools.checkstyle.api.Check; +import java.util.Arrays; +import java.util.Optional; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.Scope; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; +import com.puppycrawl.tools.checkstyle.utils.TokenUtils; /** - * Checks that classes are designed for inheritance. + * The check finds classes that are designed for extension (subclass creation). * *

      - * More specifically, it enforces a programming style - * where superclasses provide empty "hooks" that can be - * implemented by subclasses. + * Nothing wrong could be with founded classes. + * This check makes sense only for library projects (not application projects) + * which care of ideal OOP-design to make sure that class works in all cases even misusage. + * Even in library projects this check most likely will find classes that are designed for extension + * by somebody. User needs to use suppressions extensively to got a benefit from this check, + * and keep in suppressions all confirmed/known classes that are deigned for inheritance + * intentionally to let the check catch only new classes, and bring this to team/user attention. *

      * - *

      The exact rule is that non-private, non-static methods in - * non-final classes (or classes that do not - * only have private constructors) must either be - *

        - *
      • abstract or
      • - *
      • final or
      • - *
      • have an empty implementation
      • - *
      + *

      + * ATTENTION: Only user can decide whether a class is designed for extension or not. + * The check just shows all classes which are possibly designed for extension. + * If smth inappropriate is found please use suppression. + *

      * + *

      + * ATTENTION: If the method which can be overridden in a subclass has a javadoc comment + * (a good practice is to explain its self-use of overridable methods) the check will not + * rise a violation. The violation can also be skipped if the method which can be overridden + * in a subclass has one or more annotations that are specified in ignoredAnnotations + * option. Note, that by default @Override annotation is not included in the + * ignoredAnnotations set as in a subclass the method which has the annotation can also be + * overridden in its subclass. + *

      * *

      - * This protects superclasses against being broken by - * subclasses. The downside is that subclasses are limited - * in their flexibility, in particular they cannot prevent - * execution of code in the superclass, but that also - * means that subclasses can't forget to call their super - * method. + * More specifically, the check enforces a programming style where superclasses provide empty + * "hooks" that can be implemented by subclasses. *

      * + *

      + * The check finds classes that have overridable methods (public or protected methods + * that are non-static, not-final, non-abstract) and have non-empty implementation. + *

      + * + *

      + * This protects superclasses against being broken by subclasses. The downside is that subclasses + * are limited in their flexibility, in particular, they cannot prevent execution of code in the + * superclass, but that also means that subclasses cannot forget to call their super method. + *

      + * + *

      + * The check has the following options: + *

      + *
        + *
      • + * ignoredAnnotations - annotations which allow the check to skip the method from validation. + * Default value is Test, Before, After, BeforeClass, AfterClass. + *
      • + *
      + * * @author lkuehne + * @author Andrei Selkin */ -public class DesignForExtensionCheck extends Check { +@StatelessCheck +public class DesignForExtensionCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -63,68 +100,200 @@ */ public static final String MSG_KEY = "design.forExtension"; + /** + * A set of annotations which allow the check to skip the method from validation. + */ + private Set ignoredAnnotations = Arrays.stream(new String[] {"Test", "Before", "After", + "BeforeClass", "AfterClass", }).collect(Collectors.toSet()); + + /** + * Sets annotations which allow the check to skip the method from validation. + * @param ignoredAnnotations method annotations. + */ + public void setIgnoredAnnotations(String... ignoredAnnotations) { + this.ignoredAnnotations = Arrays.stream(ignoredAnnotations).collect(Collectors.toSet()); + } + @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.METHOD_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + // The check does not subscribe to CLASS_DEF token as now it is stateless. If the check + // subscribes to CLASS_DEF token it will become stateful, since we need to have additional + // stack to hold CLASS_DEF tokens. + return new int[] {TokenTypes.METHOD_DEF}; + } + + @Override + public boolean isCommentNodesRequired() { + return true; } @Override public void visitToken(DetailAST ast) { - // nothing to do for Interfaces - if (!ScopeUtils.isInInterfaceOrAnnotationBlock(ast) - && !isPrivateOrFinalOrAbstract(ast) - && ScopeUtils.getSurroundingScope(ast).isIn(Scope.PROTECTED)) { - - // method is ok if it is implementation can verified to be empty - // Note: native methods don't have impl in java code, so - // implementation can be null even if method not abstract - final DetailAST implementation = ast.findFirstToken(TokenTypes.SLIST); - final boolean nonEmptyImplementation = implementation == null - || implementation.getFirstChild().getType() != TokenTypes.RCURLY; - - final DetailAST classDef = findContainingClass(ast); - final DetailAST classMods = classDef.findFirstToken(TokenTypes.MODIFIERS); - // check if the containing class can be subclassed - final boolean classCanBeSubclassed = classDef.getType() != TokenTypes.ENUM_DEF - && !classMods.branchContains(TokenTypes.FINAL); + if (!hasJavadocComment(ast) + && canBeOverridden(ast) + && (isNativeMethod(ast) + || !hasEmptyImplementation(ast)) + && !hasIgnoredAnnotation(ast, ignoredAnnotations)) { + final DetailAST classDef = getNearestClassOrEnumDefinition(ast); + if (canBeSubclassed(classDef)) { + final String className = classDef.findFirstToken(TokenTypes.IDENT).getText(); + final String methodName = ast.findFirstToken(TokenTypes.IDENT).getText(); + log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY, className, methodName); + } + } + } + + /** + * Checks whether a method has a javadoc comment. + * @param methodDef method definition token. + * @return true if a method has a javadoc comment. + */ + private static boolean hasJavadocComment(DetailAST methodDef) { + return hasJavadocCommentOnToken(methodDef, TokenTypes.MODIFIERS) + || hasJavadocCommentOnToken(methodDef, TokenTypes.TYPE); + } - if (nonEmptyImplementation && classCanBeSubclassed - && hasDefaultOrExplicitNonPrivateCtor(classDef)) { + /** + * Checks whether a token has a javadoc comment. + * + * @param methodDef method definition token. + * @param tokenType token type. + * @return true if a token has a javadoc comment. + */ + private static boolean hasJavadocCommentOnToken(DetailAST methodDef, int tokenType) { + final DetailAST token = methodDef.findFirstToken(tokenType); + return token.branchContains(TokenTypes.BLOCK_COMMENT_BEGIN); + } - final String name = ast.findFirstToken(TokenTypes.IDENT).getText(); - log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY, name); + /** + * Checks whether a methods is native. + * @param ast method definition token. + * @return true if a methods is native. + */ + private static boolean isNativeMethod(DetailAST ast) { + final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS); + return mods.findFirstToken(TokenTypes.LITERAL_NATIVE) != null; + } + + /** + * Checks whether a method has only comments in the body (has an empty implementation). + * Method is OK if its implementation is empty. + * @param ast method definition token. + * @return true if a method has only comments in the body. + */ + private static boolean hasEmptyImplementation(DetailAST ast) { + boolean hasEmptyBody = true; + final DetailAST methodImplOpenBrace = ast.findFirstToken(TokenTypes.SLIST); + final DetailAST methodImplCloseBrace = methodImplOpenBrace.getLastChild(); + final Predicate predicate = currentNode -> { + return currentNode != methodImplCloseBrace + && !TokenUtils.isCommentType(currentNode.getType()); + }; + final Optional methodBody = + TokenUtils.findFirstTokenByPredicate(methodImplOpenBrace, predicate); + if (methodBody.isPresent()) { + hasEmptyBody = false; + } + return hasEmptyBody; + } + + /** + * Checks whether a method can be overridden. + * Method can be overridden if it is not private, abstract, final or static. + * Note that the check has nothing to do for interfaces. + * @param methodDef method definition token. + * @return true if a method can be overridden in a subclass. + */ + private static boolean canBeOverridden(DetailAST methodDef) { + final DetailAST modifiers = methodDef.findFirstToken(TokenTypes.MODIFIERS); + return ScopeUtils.getSurroundingScope(methodDef).isIn(Scope.PROTECTED) + && !ScopeUtils.isInInterfaceOrAnnotationBlock(methodDef) + && modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null + && modifiers.findFirstToken(TokenTypes.ABSTRACT) == null + && modifiers.findFirstToken(TokenTypes.FINAL) == null + && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) == null; + } + + /** + * Checks whether a method has any of ignored annotations. + * @param methodDef method definition token. + * @param annotations a set of ignored annotations. + * @return true if a method has any of ignored annotations. + */ + private static boolean hasIgnoredAnnotation(DetailAST methodDef, Set annotations) { + final DetailAST modifiers = methodDef.findFirstToken(TokenTypes.MODIFIERS); + boolean hasIgnoredAnnotation = false; + if (modifiers.findFirstToken(TokenTypes.ANNOTATION) != null) { + final Optional annotation = TokenUtils.findFirstTokenByPredicate(modifiers, + currentToken -> { + return currentToken.getType() == TokenTypes.ANNOTATION + && annotations.contains(getAnnotationName(currentToken)); + }); + if (annotation.isPresent()) { + hasIgnoredAnnotation = true; } } + return hasIgnoredAnnotation; + } + + /** + * Gets the name of the annotation. + * @param annotation to get name of. + * @return the name of the annotation. + */ + private static String getAnnotationName(DetailAST annotation) { + final DetailAST dotAst = annotation.findFirstToken(TokenTypes.DOT); + final String name; + if (dotAst == null) { + name = annotation.findFirstToken(TokenTypes.IDENT).getText(); + } + else { + name = dotAst.findFirstToken(TokenTypes.IDENT).getText(); + } + return name; } /** - * Check for modifiers. - * @param ast modifier ast - * @return tru in modifier is in checked ones - */ - private static boolean isPrivateOrFinalOrAbstract(DetailAST ast) { - // method is ok if it is private or abstract or final - final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); - return modifiers.branchContains(TokenTypes.LITERAL_PRIVATE) - || modifiers.branchContains(TokenTypes.ABSTRACT) - || modifiers.branchContains(TokenTypes.FINAL) - || modifiers.branchContains(TokenTypes.LITERAL_STATIC); + * Returns CLASS_DEF or ENUM_DEF token which is the nearest to the given ast node. + * Searches the tree towards the root until it finds a CLASS_DEF or ENUM_DEF node. + * @param ast the start node for searching. + * @return the CLASS_DEF or ENUM_DEF token. + */ + private static DetailAST getNearestClassOrEnumDefinition(DetailAST ast) { + DetailAST searchAST = ast; + while (searchAST.getType() != TokenTypes.CLASS_DEF + && searchAST.getType() != TokenTypes.ENUM_DEF) { + searchAST = searchAST.getParent(); + } + return searchAST; + } + + /** + * Checks if the given class (given CLASS_DEF node) can be subclassed. + * @param classDef class definition token. + * @return true if the containing class can be subclassed. + */ + private static boolean canBeSubclassed(DetailAST classDef) { + final DetailAST modifiers = classDef.findFirstToken(TokenTypes.MODIFIERS); + return classDef.getType() != TokenTypes.ENUM_DEF + && modifiers.findFirstToken(TokenTypes.FINAL) == null + && hasDefaultOrExplicitNonPrivateCtor(classDef); } /** - * Has Default Or Explicit Non Private Ctor. - * @param classDef class ast - * @return true if Check should make a violation + * Checks whether a class has default or explicit non-private constructor. + * @param classDef class ast token. + * @return true if a class has default or explicit non-private constructor. */ private static boolean hasDefaultOrExplicitNonPrivateCtor(DetailAST classDef) { // check if subclassing is prevented by having only private ctors @@ -141,7 +310,7 @@ final DetailAST ctorMods = candidate.findFirstToken(TokenTypes.MODIFIERS); - if (!ctorMods.branchContains(TokenTypes.LITERAL_PRIVATE)) { + if (ctorMods.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null) { hasExplicitNonPrivateCtor = true; break; } @@ -152,17 +321,4 @@ return hasDefaultConstructor || hasExplicitNonPrivateCtor; } - /** - * Searches the tree towards the root until it finds a CLASS_DEF node. - * @param ast the start node for searching - * @return the CLASS_DEF node. - */ - private static DetailAST findContainingClass(DetailAST ast) { - DetailAST searchAST = ast; - while (searchAST.getType() != TokenTypes.CLASS_DEF - && searchAST.getType() != TokenTypes.ENUM_DEF) { - searchAST = searchAST.getParent(); - } - return searchAST; - } } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/FinalClassCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/FinalClassCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/FinalClassCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/FinalClassCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,8 +21,11 @@ import java.util.ArrayDeque; import java.util.Deque; +import java.util.LinkedList; +import java.util.List; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; @@ -31,7 +34,7 @@ *

      * Checks that class which has only private ctors * is declared as final. Doesn't check for classes nested in interfaces - * or annotations, as they are always final there. + * or annotations, as they are always {@code final} there. *

      *

      * An example of how to configure the check is: @@ -41,8 +44,9 @@ * * @author o_sukhodolsky */ +@FileStatefulCheck public class FinalClassCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -50,65 +54,224 @@ */ public static final String MSG_KEY = "final.class"; + /** + * Character separate package names in qualified name of java class. + */ + private static final String PACKAGE_SEPARATOR = "."; + /** Keeps ClassDesc objects for stack of declared classes. */ - private final Deque classes = new ArrayDeque<>(); + private Deque classes; + + /** Full qualified name of the package. */ + private String packageName; @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.CLASS_DEF, TokenTypes.CTOR_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.CLASS_DEF, TokenTypes.CTOR_DEF, TokenTypes.PACKAGE_DEF}; + } + + @Override + public void beginTree(DetailAST rootAST) { + classes = new ArrayDeque<>(); + packageName = ""; } @Override public void visitToken(DetailAST ast) { final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); + switch (ast.getType()) { + case TokenTypes.PACKAGE_DEF: + packageName = extractQualifiedName(ast); + break; + + case TokenTypes.CLASS_DEF: + registerNestedSubclassToOuterSuperClasses(ast); + + final boolean isFinal = modifiers.findFirstToken(TokenTypes.FINAL) != null; + final boolean isAbstract = modifiers.findFirstToken(TokenTypes.ABSTRACT) != null; + + final String qualifiedClassName = getQualifiedClassName(ast); + classes.push(new ClassDesc(qualifiedClassName, isFinal, isAbstract)); + break; + + case TokenTypes.CTOR_DEF: + if (!ScopeUtils.isInEnumBlock(ast)) { + final ClassDesc desc = classes.peek(); + if (modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null) { + desc.registerNonPrivateCtor(); + } + else { + desc.registerPrivateCtor(); + } + } + break; + + default: + throw new IllegalStateException(ast.toString()); + } + } + + @Override + public void leaveToken(DetailAST ast) { if (ast.getType() == TokenTypes.CLASS_DEF) { - final boolean isFinal = modifiers.branchContains(TokenTypes.FINAL); - final boolean isAbstract = modifiers.branchContains(TokenTypes.ABSTRACT); - classes.push(new ClassDesc(isFinal, isAbstract)); - } - // ctors in enums don't matter - else if (!ScopeUtils.isInEnumBlock(ast)) { - final ClassDesc desc = classes.peek(); - if (modifiers.branchContains(TokenTypes.LITERAL_PRIVATE)) { - desc.reportPrivateCtor(); + final ClassDesc desc = classes.pop(); + if (desc.isWithPrivateCtor() + && !desc.isDeclaredAsAbstract() + && !desc.isDeclaredAsFinal() + && !desc.isWithNonPrivateCtor() + && !desc.isWithNestedSubclass() + && !ScopeUtils.isInInterfaceOrAnnotationBlock(ast)) { + final String qualifiedName = desc.getQualifiedName(); + final String className = getClassNameFromQualifiedName(qualifiedName); + log(ast.getLineNo(), MSG_KEY, className); + } + } + } + + /** + * Get name of class(with qualified package if specified) in extend clause. + * @param classExtend extend clause to extract class name + * @return super class name + */ + private static String extractQualifiedName(DetailAST classExtend) { + final String className; + + if (classExtend.findFirstToken(TokenTypes.IDENT) == null) { + // Name specified with packages, have to traverse DOT + final DetailAST firstChild = classExtend.findFirstToken(TokenTypes.DOT); + final List qualifiedNameParts = new LinkedList<>(); + + qualifiedNameParts.add(0, firstChild.findFirstToken(TokenTypes.IDENT).getText()); + DetailAST traverse = firstChild.findFirstToken(TokenTypes.DOT); + while (traverse != null) { + qualifiedNameParts.add(0, traverse.findFirstToken(TokenTypes.IDENT).getText()); + traverse = traverse.findFirstToken(TokenTypes.DOT); + } + className = String.join(PACKAGE_SEPARATOR, qualifiedNameParts); + } + else { + className = classExtend.findFirstToken(TokenTypes.IDENT).getText(); + } + + return className; + } + + /** + * Register to outer super classes of given classAst that + * given classAst is extending them. + * @param classAst class which outer super classes will be + * informed about nesting subclass + */ + private void registerNestedSubclassToOuterSuperClasses(DetailAST classAst) { + final String currentAstSuperClassName = getSuperClassName(classAst); + if (currentAstSuperClassName != null) { + for (ClassDesc classDesc : classes) { + final String classDescQualifiedName = classDesc.getQualifiedName(); + if (doesNameInExtendMatchSuperClassName(classDescQualifiedName, + currentAstSuperClassName)) { + classDesc.registerNestedSubclass(); + } + } + } + } + + /** + * Get qualified class name from given class Ast. + * @param classAst class to get qualified class name + * @return qualified class name of a class + */ + private String getQualifiedClassName(DetailAST classAst) { + final String className = classAst.findFirstToken(TokenTypes.IDENT).getText(); + String outerClassQualifiedName = null; + if (!classes.isEmpty()) { + outerClassQualifiedName = classes.peek().getQualifiedName(); + } + return getQualifiedClassName(packageName, outerClassQualifiedName, className); + } + + /** + * Calculate qualified class name(package + class name) laying inside given + * outer class. + * @param packageName package name, empty string on default package + * @param outerClassQualifiedName qualified name(package + class) of outer class, + * null if doesn't exist + * @param className class name + * @return qualified class name(package + class name) + */ + private static String getQualifiedClassName(String packageName, String outerClassQualifiedName, + String className) { + final String qualifiedClassName; + + if (outerClassQualifiedName == null) { + if (packageName.isEmpty()) { + qualifiedClassName = className; } else { - desc.reportNonPrivateCtor(); + qualifiedClassName = packageName + PACKAGE_SEPARATOR + className; } } + else { + qualifiedClassName = outerClassQualifiedName + PACKAGE_SEPARATOR + className; + } + return qualifiedClassName; } - @Override - public void leaveToken(DetailAST ast) { - if (ast.getType() != TokenTypes.CLASS_DEF) { - return; + /** + * Get super class name of given class. + * @param classAst class + * @return super class name or null if super class is not specified + */ + private static String getSuperClassName(DetailAST classAst) { + String superClassName = null; + final DetailAST classExtend = classAst.findFirstToken(TokenTypes.EXTENDS_CLAUSE); + if (classExtend != null) { + superClassName = extractQualifiedName(classExtend); } + return superClassName; + } - final ClassDesc desc = classes.pop(); - if (!desc.isDeclaredAsFinal() - && !desc.isDeclaredAsAbstract() - && desc.isWithPrivateCtor() - && !desc.isWithNonPrivateCtor() - && !ScopeUtils.isInInterfaceOrAnnotationBlock(ast)) { - final String className = - ast.findFirstToken(TokenTypes.IDENT).getText(); - log(ast.getLineNo(), MSG_KEY, className); + /** + * Checks if given super class name in extend clause match super class qualified name. + * @param superClassQualifiedName super class qualified name (with package) + * @param superClassInExtendClause name in extend clause + * @return true if given super class name in extend clause match super class qualified name, + * false otherwise + */ + private static boolean doesNameInExtendMatchSuperClassName(String superClassQualifiedName, + String superClassInExtendClause) { + String superClassNormalizedName = superClassQualifiedName; + if (!superClassInExtendClause.contains(PACKAGE_SEPARATOR)) { + superClassNormalizedName = getClassNameFromQualifiedName(superClassQualifiedName); } + return superClassNormalizedName.equals(superClassInExtendClause); + } + + /** + * Get class name from qualified name. + * @param qualifiedName qualified class name + * @return class name + */ + private static String getClassNameFromQualifiedName(String qualifiedName) { + return qualifiedName.substring(qualifiedName.lastIndexOf(PACKAGE_SEPARATOR) + 1); } /** Maintains information about class' ctors. */ private static final class ClassDesc { + + /** Qualified class name(with package). */ + private final String qualifiedName; + /** Is class declared as final. */ private final boolean declaredAsFinal; @@ -121,28 +284,46 @@ /** Does class have private ctors. */ private boolean withPrivateCtor; + /** Does class have nested subclass. */ + private boolean withNestedSubclass; + /** * Create a new ClassDesc instance. + * @param qualifiedName qualified class name(with package) * @param declaredAsFinal indicates if the * class declared as final * @param declaredAsAbstract indicates if the * class declared as abstract */ - ClassDesc(boolean declaredAsFinal, boolean declaredAsAbstract) { + ClassDesc(String qualifiedName, boolean declaredAsFinal, boolean declaredAsAbstract) { + this.qualifiedName = qualifiedName; this.declaredAsFinal = declaredAsFinal; this.declaredAsAbstract = declaredAsAbstract; } + /** + * Get qualified class name. + * @return qualified class name + */ + private String getQualifiedName() { + return qualifiedName; + } + /** Adds private ctor. */ - private void reportPrivateCtor() { + private void registerPrivateCtor() { withPrivateCtor = true; } /** Adds non-private ctor. */ - private void reportNonPrivateCtor() { + private void registerNonPrivateCtor() { withNonPrivateCtor = true; } + /** Adds nested subclass. */ + private void registerNestedSubclass() { + withNestedSubclass = true; + } + /** * Does class have private ctors. * @return true if class has private ctors @@ -160,6 +341,14 @@ } /** + * Does class have nested subclass. + * @return true if class has nested subclass + */ + private boolean isWithNestedSubclass() { + return withNestedSubclass; + } + + /** * Is class declared as final. * @return true if class is declared as final */ @@ -174,5 +363,7 @@ private boolean isDeclaredAsAbstract() { return declaredAsAbstract; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/HideUtilityClassConstructorCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.design; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -33,7 +34,8 @@ * * @author lkuehne */ -public class HideUtilityClassConstructorCheck extends Check { +@StatelessCheck +public class HideUtilityClassConstructorCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -43,74 +45,76 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.CLASS_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.CLASS_DEF}; } @Override public void visitToken(DetailAST ast) { - if (isAbstract(ast)) { - // abstract class could not have private constructor - return; - } - final boolean hasStaticModifier = isStatic(ast); - - final Details details = new Details(ast); - details.invoke(); - - final boolean hasDefaultCtor = details.isHasDefaultCtor(); - final boolean hasPublicCtor = details.isHasPublicCtor(); - final boolean hasMethodOrField = details.isHasMethodOrField(); - final boolean hasNonStaticMethodOrField = details.isHasNonStaticMethodOrField(); - final boolean hasNonPrivateStaticMethodOrField = - details.isHasNonPrivateStaticMethodOrField(); - - final boolean hasAccessibleCtor = hasDefaultCtor || hasPublicCtor; - - // figure out if class extends java.lang.object directly - // keep it simple for now and get a 99% solution - final boolean extendsJlo = - ast.findFirstToken(TokenTypes.EXTENDS_CLAUSE) == null; + // abstract class could not have private constructor + if (!isAbstract(ast)) { + final boolean hasStaticModifier = isStatic(ast); + + final Details details = new Details(ast); + details.invoke(); + + final boolean hasDefaultCtor = details.isHasDefaultCtor(); + final boolean hasPublicCtor = details.isHasPublicCtor(); + final boolean hasMethodOrField = details.isHasMethodOrField(); + final boolean hasNonStaticMethodOrField = details.isHasNonStaticMethodOrField(); + final boolean hasNonPrivateStaticMethodOrField = + details.isHasNonPrivateStaticMethodOrField(); + + final boolean hasAccessibleCtor = hasDefaultCtor || hasPublicCtor; + + // figure out if class extends java.lang.object directly + // keep it simple for now and get a 99% solution + final boolean extendsJlo = + ast.findFirstToken(TokenTypes.EXTENDS_CLAUSE) == null; - final boolean isUtilClass = extendsJlo && hasMethodOrField - && !hasNonStaticMethodOrField && hasNonPrivateStaticMethodOrField; + final boolean isUtilClass = extendsJlo && hasMethodOrField + && !hasNonStaticMethodOrField && hasNonPrivateStaticMethodOrField; - if (isUtilClass && hasAccessibleCtor && !hasStaticModifier) { - log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY); + if (isUtilClass && hasAccessibleCtor && !hasStaticModifier) { + log(ast.getLineNo(), ast.getColumnNo(), MSG_KEY); + } } } /** + * Returns true if given class is abstract or false. * @param ast class definition for check. * @return true if a given class declared as abstract. */ private static boolean isAbstract(DetailAST ast) { return ast.findFirstToken(TokenTypes.MODIFIERS) - .branchContains(TokenTypes.ABSTRACT); + .findFirstToken(TokenTypes.ABSTRACT) != null; } /** + * Returns true if given class is static or false. * @param ast class definition for check. * @return true if a given class declared as static. */ private static boolean isStatic(DetailAST ast) { return ast.findFirstToken(TokenTypes.MODIFIERS) - .branchContains(TokenTypes.LITERAL_STATIC); + .findFirstToken(TokenTypes.LITERAL_STATIC) != null; } /** * Details of class that are required for validation. */ private static class Details { + /** Class ast. */ private final DetailAST ast; /** Result of details gathering. */ @@ -192,9 +196,9 @@ final DetailAST modifiers = child.findFirstToken(TokenTypes.MODIFIERS); final boolean isStatic = - modifiers.branchContains(TokenTypes.LITERAL_STATIC); + modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null; final boolean isPrivate = - modifiers.branchContains(TokenTypes.LITERAL_PRIVATE); + modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) != null; if (!isStatic) { hasNonStaticMethodOrField = true; @@ -207,16 +211,17 @@ hasDefaultCtor = false; final DetailAST modifiers = child.findFirstToken(TokenTypes.MODIFIERS); - if (!modifiers.branchContains(TokenTypes.LITERAL_PRIVATE) - && !modifiers.branchContains(TokenTypes.LITERAL_PROTECTED)) { + if (modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) == null + && modifiers.findFirstToken(TokenTypes.LITERAL_PROTECTED) == null) { // treat package visible as public // for the purpose of this Check hasPublicCtor = true; } - } child = child.getNextSibling(); } } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/InnerTypeLastCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/InnerTypeLastCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/InnerTypeLastCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/InnerTypeLastCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.design; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; @@ -32,7 +33,8 @@ * * @author Ruslan Dyachenko */ -public class InnerTypeLastCheck extends Check { +@FileStatefulCheck +public class InnerTypeLastCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -45,17 +47,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF}; } @Override @@ -85,4 +87,5 @@ rootClass = true; } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/InterfaceIsTypeCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/InterfaceIsTypeCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/InterfaceIsTypeCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/InterfaceIsTypeCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.design; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -41,8 +42,9 @@ * * @author lkuehne */ +@StatelessCheck public final class InterfaceIsTypeCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -55,17 +57,17 @@ @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.INTERFACE_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] {TokenTypes.INTERFACE_DEF}; } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.INTERFACE_DEF}; + return getRequiredTokens(); } @Override @@ -82,7 +84,6 @@ if (methodDef == null && methodRequired) { log(ast.getLineNo(), MSG_KEY); } - } /** @@ -92,4 +93,5 @@ public void setAllowMarkerInterfaces(boolean flag) { allowMarkerInterfaces = flag; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/MutableExceptionCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/MutableExceptionCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/MutableExceptionCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/MutableExceptionCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,10 +23,10 @@ import java.util.Deque; import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

      Ensures that exceptions (classes with names conforming to some regular @@ -41,7 +41,8 @@ * * @author Simon Harris */ -public final class MutableExceptionCheck extends Check { +@FileStatefulCheck +public final class MutableExceptionCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -54,45 +55,41 @@ /** Stack of checking information for classes. */ private final Deque checkingStack = new ArrayDeque<>(); /** Pattern for class name that is being extended. */ - private String extendedClassNameFormat = DEFAULT_FORMAT; + private Pattern extendedClassNameFormat = Pattern.compile(DEFAULT_FORMAT); /** Should we check current class or not. */ private boolean checking; - /** The format string of the regexp. */ - private String format = DEFAULT_FORMAT; /** The regexp to match against. */ - private Pattern regexp = Pattern.compile(format); + private Pattern format = Pattern.compile(DEFAULT_FORMAT); /** * Sets the format of extended class name to the specified regular expression. * @param extendedClassNameFormat a {@code String} value */ - public void setExtendedClassNameFormat(String extendedClassNameFormat) { + public void setExtendedClassNameFormat(Pattern extendedClassNameFormat) { this.extendedClassNameFormat = extendedClassNameFormat; } /** - * Set the format to the specified regular expression. - * @param format a {@code String} value - * @throws org.apache.commons.beanutils.ConversionException unable to parse format - */ - public void setFormat(String format) { - this.format = format; - regexp = CommonUtils.createPattern(format); + * Set the format for the specified regular expression. + * @param pattern the new pattern + */ + public void setFormat(Pattern pattern) { + format = pattern; } @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.CLASS_DEF, TokenTypes.VARIABLE_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] {TokenTypes.CLASS_DEF, TokenTypes.VARIABLE_DEF}; } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.CLASS_DEF, TokenTypes.VARIABLE_DEF}; + return getRequiredTokens(); } @Override @@ -153,7 +150,7 @@ */ private boolean isNamedAsException(DetailAST ast) { final String className = ast.findFirstToken(TokenTypes.IDENT).getText(); - return regexp.matcher(className).find(); + return format.matcher(className).find(); } /** @@ -162,6 +159,7 @@ * @return true if extended class name conforms to specified format */ private boolean isExtendedClassNamedAsException(DetailAST ast) { + boolean result = false; final DetailAST extendsClause = ast.findFirstToken(TokenTypes.EXTENDS_CLAUSE); if (extendsClause != null) { DetailAST currentNode = extendsClause; @@ -169,8 +167,9 @@ currentNode = currentNode.getLastChild(); } final String extendedClassName = currentNode.getText(); - return extendedClassName.matches(extendedClassNameFormat); + result = extendedClassNameFormat.matcher(extendedClassName).matches(); } - return false; + return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/OneTopLevelClassCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/OneTopLevelClassCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/OneTopLevelClassCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/OneTopLevelClassCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,18 +23,18 @@ import java.util.SortedMap; import java.util.TreeMap; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * Checks that each top-level class, interface * or enum resides in a source file of its own. *

      * Official description of a 'top-level' term: + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-7.html#jls-7.6"> * 7.6. Top Level Type Declarations. If file doesn't contains * public class, enum or interface, top-level type is the first type in file. *

      @@ -84,7 +84,8 @@ * * @author maxvetrenko */ -public class OneTopLevelClassCheck extends Check { +@FileStatefulCheck +public class OneTopLevelClassCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -103,18 +104,18 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } - // ZERO tokens as Check do Traverse of Tree himself, he does not need to subscribed to Tokens @Override public int[] getAcceptableTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return getRequiredTokens(); } + // ZERO tokens as Check do Traverse of Tree himself, he does not need to subscribed to Tokens @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -165,4 +166,5 @@ typeDef.findFirstToken(TokenTypes.MODIFIERS); return modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/ThrowsCountCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/ThrowsCountCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/ThrowsCountCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/ThrowsCountCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.design; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -52,7 +53,8 @@ *

      * @author Simon Harris */ -public final class ThrowsCountCheck extends Check { +@StatelessCheck +public final class ThrowsCountCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -76,21 +78,19 @@ @Override public int[] getDefaultTokens() { - return new int[] { - TokenTypes.LITERAL_THROWS, - }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); + return new int[] { + TokenTypes.LITERAL_THROWS, + }; } @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.LITERAL_THROWS, - }; + return getRequiredTokens(); } /** @@ -143,12 +143,13 @@ private static boolean isOverriding(DetailAST ast) { final DetailAST modifiers = ast.getParent().findFirstToken(TokenTypes.MODIFIERS); boolean isOverriding = false; - if (modifiers.branchContains(TokenTypes.ANNOTATION)) { + if (modifiers.findFirstToken(TokenTypes.ANNOTATION) != null) { DetailAST child = modifiers.getFirstChild(); while (child != null) { if (child.getType() == TokenTypes.ANNOTATION && "Override".equals(getAnnotationName(child))) { isOverriding = true; + break; } child = child.getNextSibling(); } @@ -182,4 +183,5 @@ final DetailAST methodModifiers = ast.getParent().findFirstToken(TokenTypes.MODIFIERS); return methodModifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) != null; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/VisibilityModifierCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/VisibilityModifierCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/VisibilityModifierCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/design/VisibilityModifierCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,20 +21,20 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Pattern; +import java.util.stream.Collectors; import antlr.collections.AST; - -import com.google.common.collect.ImmutableList; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.AnnotationUtility; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; /** @@ -58,6 +58,7 @@ *

      *
        *
      • org.junit.Rule
      • + *
      • org.junit.ClassRule
      • *
      • com.google.common.annotations.VisibleForTesting
      • *
      *

      @@ -71,8 +72,11 @@ * * *

      - * allowPublicImmutableFields - which allows immutable fields be - * declared as public if defined in final class. Default value is true + * allowPublicFinalFields - which allows public final fields. Default value is false. + *

      + *

      + * allowPublicImmutableFields - which allows immutable fields to be + * declared as public if defined in final class. Default value is false *

      *

      * Field is known to be immutable if: @@ -130,21 +134,21 @@ *

      * Examples: *

      - * Default Check's configuration will pass the code below: + * The check will rise 3 violations if it is run with default configuration against the following + * code example: *

      * *
        * {@code
      - * public final class ImmutableClass
      + * public class ImmutableClass
        * {
      - *     public final int intValue; // No warning
      - *     public final java.lang.String notes; // No warning
      - *     public final BigDecimal value; // No warning
      + *     public int intValue; // violation
      + *     public java.lang.String notes; // violation
      + *     public BigDecimal value; // violation
        *
        *     public ImmutableClass(int intValue, BigDecimal value, String notes)
        *     {
      - *         this.includes = ImmutableSet.copyOf(includes);
      - *         this.excludes = ImmutableSet.copyOf(excludes);
      + *         this.intValue = intValue;
        *         this.value = value;
        *         this.notes = notes;
        *     }
      @@ -158,6 +162,7 @@
        * 

      *

      * <module name="VisibilityModifier"> + * <property name="allowPublicImmutableFields" value="true"/> * <property name="immutableClassCanonicalNames" value="java.util.List, * com.google.common.collect.ImmutableSet"/> * </module> @@ -232,8 +237,9 @@ * * @author Aleksey Nesterenko */ +@FileStatefulCheck public class VisibilityModifierCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -242,34 +248,37 @@ public static final String MSG_KEY = "variable.notPrivate"; /** Default immutable types canonical names. */ - private static final List DEFAULT_IMMUTABLE_TYPES = ImmutableList.of( - "java.lang.String", - "java.lang.Integer", - "java.lang.Byte", - "java.lang.Character", - "java.lang.Short", - "java.lang.Boolean", - "java.lang.Long", - "java.lang.Double", - "java.lang.Float", - "java.lang.StackTraceElement", - "java.math.BigInteger", - "java.math.BigDecimal", - "java.io.File", - "java.util.Locale", - "java.util.UUID", - "java.net.URL", - "java.net.URI", - "java.net.Inet4Address", - "java.net.Inet6Address", - "java.net.InetSocketAddress" - ); + private static final List DEFAULT_IMMUTABLE_TYPES = Collections.unmodifiableList( + Arrays.stream(new String[] { + "java.lang.String", + "java.lang.Integer", + "java.lang.Byte", + "java.lang.Character", + "java.lang.Short", + "java.lang.Boolean", + "java.lang.Long", + "java.lang.Double", + "java.lang.Float", + "java.lang.StackTraceElement", + "java.math.BigInteger", + "java.math.BigDecimal", + "java.io.File", + "java.util.Locale", + "java.util.UUID", + "java.net.URL", + "java.net.URI", + "java.net.Inet4Address", + "java.net.Inet6Address", + "java.net.InetSocketAddress", + }).collect(Collectors.toList())); /** Default ignore annotations canonical names. */ - private static final List DEFAULT_IGNORE_ANNOTATIONS = ImmutableList.of( - "org.junit.Rule", - "com.google.common.annotations.VisibleForTesting" - ); + private static final List DEFAULT_IGNORE_ANNOTATIONS = Collections.unmodifiableList( + Arrays.stream(new String[] { + "org.junit.Rule", + "org.junit.ClassRule", + "com.google.common.annotations.VisibleForTesting", + }).collect(Collectors.toList())); /** Name for 'public' access modifier. */ private static final String PUBLIC_ACCESS_MODIFIER = "public"; @@ -296,17 +305,13 @@ PROTECTED_ACCESS_MODIFIER, }; - /** - * Pattern for public members that should be ignored. Note: + /** Regexp for public members that should be ignored. Note: * Earlier versions of checkstyle used ^f[A-Z][a-zA-Z0-9]*$ as the * default to allow CMP for EJB 1.1 with the default settings. * With EJB 2.0 it is not longer necessary to have public access * for persistent fields. */ - private String publicMemberFormat = "^serialVersionUID$"; - - /** Regexp for public members that should be ignored. */ - private Pattern publicMemberPattern = Pattern.compile(publicMemberFormat); + private Pattern publicMemberPattern = Pattern.compile("^serialVersionUID$"); /** List of ignore annotations short names. */ private final List ignoreAnnotationShortNames = @@ -326,8 +331,11 @@ /** Whether package visible members are allowed. */ private boolean packageAllowed; - /** Allows immutable fields to be declared as public. */ - private boolean allowPublicImmutableFields = true; + /** Allows immutable fields of final classes to be declared as public. */ + private boolean allowPublicImmutableFields; + + /** Allows final fields to be declared as public. */ + private boolean allowPublicFinalFields; /** List of immutable classes canonical names. */ private List immutableClassCanonicalNames = new ArrayList<>(DEFAULT_IMMUTABLE_TYPES); @@ -360,16 +368,13 @@ * Set the pattern for public members to ignore. * @param pattern * pattern for public members to ignore. - * @throws org.apache.commons.beanutils.ConversionException - * if unable to create Pattern object */ - public void setPublicMemberPattern(String pattern) { - publicMemberPattern = CommonUtils.createPattern(pattern); - publicMemberFormat = pattern; + public void setPublicMemberPattern(Pattern pattern) { + publicMemberPattern = pattern; } /** - * Sets whether public immutable are allowed. + * Sets whether public immutable fields are allowed. * @param allow user's value. */ public void setAllowPublicImmutableFields(boolean allow) { @@ -377,6 +382,14 @@ } /** + * Sets whether public final fields are allowed. + * @param allow user's value. + */ + public void setAllowPublicFinalFields(boolean allow) { + allowPublicFinalFields = allow; + } + + /** * Set the list of immutable classes types names. * @param classNames array of immutable types canonical names. */ @@ -386,20 +399,20 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.VARIABLE_DEF, - TokenTypes.IMPORT, - }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] { + TokenTypes.VARIABLE_DEF, + TokenTypes.IMPORT, + }; } @Override @@ -538,8 +551,7 @@ || packageAllowed && PACKAGE_ACCESS_MODIFIER.equals(variableScope) || protectedAllowed && PROTECTED_ACCESS_MODIFIER.equals(variableScope) || isIgnoredPublicMember(variableName, variableScope) - || allowPublicImmutableFields - && isImmutableFieldDefinedInFinalClass(variableDef); + || isAllowedPublicField(variableDef); } return result; @@ -568,6 +580,16 @@ } /** + * Checks whether the variable satisfies the public field check. + * @param variableDef Variable definition node. + * @return true if allowed. + */ + private boolean isAllowedPublicField(DetailAST variableDef) { + return allowPublicFinalFields && isFinalField(variableDef) + || allowPublicImmutableFields && isImmutableFieldDefinedInFinalClass(variableDef); + } + + /** * Checks whether immutable field is defined in final class. * @param variableDef Variable definition node. * @return true if immutable field is defined in final class. @@ -575,7 +597,8 @@ private boolean isImmutableFieldDefinedInFinalClass(DetailAST variableDef) { final DetailAST classDef = variableDef.getParent().getParent(); final Set classModifiers = getModifiers(classDef); - return classModifiers.contains(FINAL_KEYWORD) && isImmutableField(variableDef); + return (classModifiers.contains(FINAL_KEYWORD) || classDef.getType() == TokenTypes.ENUM_DEF) + && isImmutableField(variableDef); } /** @@ -594,7 +617,6 @@ } } return modifiersSet; - } /** @@ -625,22 +647,101 @@ */ private boolean isImmutableField(DetailAST variableDef) { boolean result = false; - - final DetailAST modifiers = variableDef.findFirstToken(TokenTypes.MODIFIERS); - final boolean isFinal = modifiers.branchContains(TokenTypes.FINAL); - if (isFinal) { + if (isFinalField(variableDef)) { final DetailAST type = variableDef.findFirstToken(TokenTypes.TYPE); - final boolean isCanonicalName = type.getFirstChild().getType() == TokenTypes.DOT; + final boolean isCanonicalName = isCanonicalName(type); final String typeName = getTypeName(type, isCanonicalName); - - result = !isCanonicalName && isPrimitive(type) - || immutableClassShortNames.contains(typeName) - || isCanonicalName && immutableClassCanonicalNames.contains(typeName); + final DetailAST typeArgs = getGenericTypeArgs(type, isCanonicalName); + if (typeArgs == null) { + result = !isCanonicalName && isPrimitive(type) + || immutableClassShortNames.contains(typeName) + || isCanonicalName && immutableClassCanonicalNames.contains(typeName); + } + else { + final List argsClassNames = getTypeArgsClassNames(typeArgs); + result = (immutableClassShortNames.contains(typeName) + || isCanonicalName && immutableClassCanonicalNames.contains(typeName)) + && areImmutableTypeArguments(argsClassNames); + } } return result; } /** + * Checks whether type definition is in canonical form. + * @param type type definition token. + * @return true if type definition is in canonical form. + */ + private static boolean isCanonicalName(DetailAST type) { + return type.getFirstChild().getType() == TokenTypes.DOT; + } + + /** + * Returns generic type arguments token. + * @param type type token. + * @param isCanonicalName whether type name is in canonical form. + * @return generic type arguments token. + */ + private static DetailAST getGenericTypeArgs(DetailAST type, boolean isCanonicalName) { + final DetailAST typeArgs; + if (isCanonicalName) { + // if type class name is in canonical form, abstract tree has specific structure + typeArgs = type.getFirstChild().findFirstToken(TokenTypes.TYPE_ARGUMENTS); + } + else { + typeArgs = type.findFirstToken(TokenTypes.TYPE_ARGUMENTS); + } + return typeArgs; + } + + /** + * Returns a list of type parameters class names. + * @param typeArgs type arguments token. + * @return a list of type parameters class names. + */ + private static List getTypeArgsClassNames(DetailAST typeArgs) { + final List typeClassNames = new ArrayList<>(); + DetailAST type = typeArgs.findFirstToken(TokenTypes.TYPE_ARGUMENT); + boolean isCanonicalName = isCanonicalName(type); + String typeName = getTypeName(type, isCanonicalName); + typeClassNames.add(typeName); + DetailAST sibling = type.getNextSibling(); + while (sibling.getType() == TokenTypes.COMMA) { + type = sibling.getNextSibling(); + isCanonicalName = isCanonicalName(type); + typeName = getTypeName(type, isCanonicalName); + typeClassNames.add(typeName); + sibling = type.getNextSibling(); + } + return typeClassNames; + } + + /** + * Checks whether all of generic type arguments are immutable. + * If at least one argument is mutable, we assume that the whole list of type arguments + * is mutable. + * @param typeArgsClassNames type arguments class names. + * @return true if all of generic type arguments are immutable. + */ + private boolean areImmutableTypeArguments(List typeArgsClassNames) { + return typeArgsClassNames.stream().noneMatch( + typeName -> { + return !immutableClassShortNames.contains(typeName) + && !immutableClassCanonicalNames.contains(typeName); + }); + } + + /** + * Checks whether current field is final. + * @param variableDef field in consideration. + * @return true if current field is final. + */ + private static boolean isFinalField(DetailAST variableDef) { + final DetailAST modifiers = variableDef.findFirstToken(TokenTypes.MODIFIERS); + return modifiers.findFirstToken(TokenTypes.FINAL) != null; + } + + /** * Gets the name of type from given ast {@link TokenTypes#TYPE TYPE} node. * If type is specified via its canonical name - canonical name will be returned, * else - short type's name. @@ -678,15 +779,17 @@ * @return canonical type's name */ private static String getCanonicalName(DetailAST type) { - final StringBuilder canonicalNameBuilder = new StringBuilder(); + final StringBuilder canonicalNameBuilder = new StringBuilder(256); DetailAST toVisit = type.getFirstChild(); while (toVisit != null) { toVisit = getNextSubTreeNode(toVisit, type); if (toVisit != null && toVisit.getType() == TokenTypes.IDENT) { canonicalNameBuilder.append(toVisit.getText()); - final DetailAST nextSubTreeNode = getNextSubTreeNode(toVisit, - type); + final DetailAST nextSubTreeNode = getNextSubTreeNode(toVisit, type); if (nextSubTreeNode != null) { + if (nextSubTreeNode.getType() == TokenTypes.TYPE_ARGUMENTS) { + break; + } canonicalNameBuilder.append('.'); } } @@ -791,4 +894,5 @@ return matchingAnnotation; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/FileContentsHolder.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/FileContentsHolder.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/FileContentsHolder.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/FileContentsHolder.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,74 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.checks; - -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; -import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.api.FileContents; - -/** - * Holds the current file contents for global access when configured - * as a TreeWalker sub-module. For example, - * a filter can access the current file contents through this module. - * @author Mike McMahon - * @author Rick Giles - */ -public class FileContentsHolder - extends Check { - /** The current file contents. */ - private static final ThreadLocal FILE_CONTENTS = new ThreadLocal<>(); - - /** - * @return the current file contents. - */ - public static FileContents getContents() { - return FILE_CONTENTS.get(); - } - - @Override - public int[] getDefaultTokens() { - return getAcceptableTokens(); - } - - @Override - public int[] getAcceptableTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; - } - - @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); - } - - @Override - public void beginTree(DetailAST rootAST) { - FILE_CONTENTS.set(getFileContents()); - } - - @Override - public void destroy() { - // This needs to be called in destroy, rather than finishTree() - // as finishTree() is called before the messages are passed to the - // filters. Without calling remove, there is a memory leak. - FILE_CONTENTS.remove(); - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/FinalParametersCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,15 +19,17 @@ package com.puppycrawl.tools.checkstyle.checks; +import java.util.Arrays; +import java.util.Collections; import java.util.Set; +import java.util.stream.Collectors; -import org.apache.commons.lang3.ArrayUtils; - -import com.google.common.collect.ImmutableSet; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CheckUtils; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * Check that method/constructor/catch/foreach parameters are final. @@ -38,7 +40,7 @@ *

      * Check has an option ignorePrimitiveTypes which allows ignoring lack of * final modifier at - * + * * primitive data type parameter. Default value false. *

      * E.g.: @@ -53,7 +55,8 @@ * @author Michael Studman * @author Aleksey Nesterenko */ -public class FinalParametersCheck extends Check { +@StatelessCheck +public class FinalParametersCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -63,10 +66,11 @@ /** * Contains - * + * * primitive datatypes. */ - private final Set primitiveDataTypes = ImmutableSet.of( + private final Set primitiveDataTypes = Collections.unmodifiableSet( + Arrays.stream(new Integer[] { TokenTypes.LITERAL_BYTE, TokenTypes.LITERAL_SHORT, TokenTypes.LITERAL_INT, @@ -74,7 +78,8 @@ TokenTypes.LITERAL_FLOAT, TokenTypes.LITERAL_DOUBLE, TokenTypes.LITERAL_BOOLEAN, - TokenTypes.LITERAL_CHAR); + TokenTypes.LITERAL_CHAR, }) + .collect(Collectors.toSet())); /** * Option to ignore primitive types as params. @@ -109,25 +114,23 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override public void visitToken(DetailAST ast) { // don't flag interfaces final DetailAST container = ast.getParent().getParent(); - if (container.getType() == TokenTypes.INTERFACE_DEF) { - return; - } - - if (ast.getType() == TokenTypes.LITERAL_CATCH) { - visitCatch(ast); - } - else if (ast.getType() == TokenTypes.FOR_EACH_CLAUSE) { - visitForEachClause(ast); - } - else { - visitMethod(ast); + if (container.getType() != TokenTypes.INTERFACE_DEF) { + if (ast.getType() == TokenTypes.LITERAL_CATCH) { + visitCatch(ast); + } + else if (ast.getType() == TokenTypes.FOR_EACH_CLAUSE) { + visitForEachClause(ast); + } + else { + visitMethod(ast); + } } } @@ -136,28 +139,26 @@ * @param method method or ctor to check. */ private void visitMethod(final DetailAST method) { - // exit on fast lane if there is nothing to check here - if (!method.branchContains(TokenTypes.PARAMETER_DEF)) { - return; - } - - // ignore abstract method final DetailAST modifiers = method.findFirstToken(TokenTypes.MODIFIERS); - if (modifiers.branchContains(TokenTypes.ABSTRACT)) { - return; - } + // exit on fast lane if there is nothing to check here - // we can now be sure that there is at least one parameter - final DetailAST parameters = - method.findFirstToken(TokenTypes.PARAMETERS); - DetailAST child = parameters.getFirstChild(); - while (child != null) { - // children are PARAMETER_DEF and COMMA - if (child.getType() == TokenTypes.PARAMETER_DEF) { - checkParam(child); + if (method.findFirstToken(TokenTypes.PARAMETERS) + .findFirstToken(TokenTypes.PARAMETER_DEF) != null + // ignore abstract and native methods + && modifiers.findFirstToken(TokenTypes.ABSTRACT) == null + && modifiers.findFirstToken(TokenTypes.LITERAL_NATIVE) == null) { + // we can now be sure that there is at least one parameter + final DetailAST parameters = + method.findFirstToken(TokenTypes.PARAMETERS); + DetailAST child = parameters.getFirstChild(); + while (child != null) { + // children are PARAMETER_DEF and COMMA + if (child.getType() == TokenTypes.PARAMETER_DEF) { + checkParam(child); + } + child = child.getNextSibling(); } - child = child.getNextSibling(); } } @@ -182,7 +183,9 @@ * @param param parameter to check. */ private void checkParam(final DetailAST param) { - if (!param.branchContains(TokenTypes.FINAL) && !isIgnoredParam(param)) { + if (param.findFirstToken(TokenTypes.MODIFIERS).findFirstToken(TokenTypes.FINAL) == null + && !isIgnoredParam(param) + && !CheckUtils.isReceiverParameter(param)) { final DetailAST paramName = param.findFirstToken(TokenTypes.IDENT); final DetailAST firstNode = CheckUtils.getFirstNode(param); log(firstNode.getLineNo(), firstNode.getColumnNo(), @@ -206,4 +209,5 @@ } return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/AbstractHeaderCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/AbstractHeaderCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/AbstractHeaderCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/AbstractHeaderCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,17 +28,17 @@ import java.io.UnsupportedEncodingException; import java.net.URI; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Set; import java.util.regex.Pattern; -import org.apache.commons.beanutils.ConversionException; -import org.apache.commons.lang3.StringUtils; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; import com.google.common.io.Closeables; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** @@ -46,18 +46,20 @@ * Provides support for header and headerFile properties. * @author o_sukhosolsky */ -public abstract class AbstractHeaderCheck extends AbstractFileSetCheck { +public abstract class AbstractHeaderCheck extends AbstractFileSetCheck + implements ExternalResourceHolder { + /** Pattern to detect occurrences of '\n' in text. */ private static final Pattern ESCAPED_LINE_FEED_PATTERN = Pattern.compile("\\\\n"); /** The lines of the header file. */ - private final List readerLines = Lists.newArrayList(); + private final List readerLines = new ArrayList<>(); /** The file that contains the header to check against. */ - private String headerFile; + private URI headerFile; /** Name of a charset to use for loading the header from a file. */ - private String charset = System.getProperty("file.encoding", "UTF-8"); + private String charset = System.getProperty("file.encoding", StandardCharsets.UTF_8.name()); /** * Hook method for post processing header lines. @@ -69,8 +71,9 @@ * Return the header lines to check against. * @return the header lines to check against. */ - protected ImmutableList getHeaderLines() { - return ImmutableList.copyOf(readerLines); + protected List getHeaderLines() { + final List copy = new ArrayList<>(readerLines); + return Collections.unmodifiableList(copy); } /** @@ -88,17 +91,17 @@ /** * Set the header file to check against. - * @param fileName the file that contains the header to check against. + * @param uri the uri of the header to load. * @throws CheckstyleException if fileName is empty. */ - public void setHeaderFile(String fileName) throws CheckstyleException { - if (StringUtils.isBlank(fileName)) { + public void setHeaderFile(URI uri) throws CheckstyleException { + if (uri == null) { throw new CheckstyleException( "property 'headerFile' is missing or invalid in module " + getConfiguration().getName()); } - headerFile = fileName; + headerFile = uri; } /** @@ -109,9 +112,8 @@ checkHeaderNotInitialized(); Reader headerReader = null; try { - final URI uri = CommonUtils.getUriByFilename(headerFile); headerReader = new InputStreamReader(new BufferedInputStream( - uri.toURL().openStream()), charset); + headerFile.toURL().openStream()), charset); loadHeader(headerReader); } catch (final IOException ex) { @@ -125,11 +127,11 @@ /** * Called before initializing the header. - * @throws ConversionException if header has already been set + * @throws IllegalArgumentException if header has already been set */ private void checkHeaderNotInitialized() { if (!readerLines.isEmpty()) { - throw new ConversionException( + throw new IllegalArgumentException( "header has already been set - " + "set either header or headerFile, not both"); } @@ -139,27 +141,25 @@ * Set the header to check against. Individual lines in the header * must be separated by '\n' characters. * @param header header content to check against. - * @throws ConversionException if the header cannot be interpreted + * @throws IllegalArgumentException if the header cannot be interpreted */ public void setHeader(String header) { - if (StringUtils.isBlank(header)) { - return; - } + if (!CommonUtils.isBlank(header)) { + checkHeaderNotInitialized(); - checkHeaderNotInitialized(); + final String headerExpandedNewLines = ESCAPED_LINE_FEED_PATTERN + .matcher(header).replaceAll("\n"); - final String headerExpandedNewLines = ESCAPED_LINE_FEED_PATTERN - .matcher(header).replaceAll("\n"); - - final Reader headerReader = new StringReader(headerExpandedNewLines); - try { - loadHeader(headerReader); - } - catch (final IOException ex) { - throw new ConversionException("unable to load header", ex); - } - finally { - Closeables.closeQuietly(headerReader); + final Reader headerReader = new StringReader(headerExpandedNewLines); + try { + loadHeader(headerReader); + } + catch (final IOException ex) { + throw new IllegalArgumentException("unable to load header", ex); + } + finally { + Closeables.closeQuietly(headerReader); + } } } @@ -170,15 +170,22 @@ */ private void loadHeader(final Reader headerReader) throws IOException { final LineNumberReader lnr = new LineNumberReader(headerReader); - readerLines.clear(); - while (true) { - final String line = lnr.readLine(); - if (line == null) { - break; + try { + while (true) { + String line = lnr.readLine(); + if (line == null) { + break; + } + if (line.isEmpty()) { + line = "^$"; + } + readerLines.add(line); } - readerLines.add(line); + postProcessHeaderLines(); + } + finally { + Closeables.closeQuietly(lnr); } - postProcessHeaderLines(); } @Override @@ -186,8 +193,20 @@ if (headerFile != null) { loadHeaderFile(); } - if (readerLines.isEmpty()) { - setHeader(null); + } + + @Override + public Set getExternalResourceLocations() { + final Set result; + + if (headerFile == null) { + result = Collections.emptySet(); + } + else { + result = Collections.singleton(headerFile.toString()); } + + return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/HeaderCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/HeaderCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/HeaderCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/HeaderCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,7 +21,9 @@ import java.io.File; import java.util.Arrays; -import java.util.List; + +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.FileText; /** * Checks the header of the source against a fixed header file. @@ -31,6 +33,7 @@ * * @author Lars Kühne */ +@StatelessCheck public class HeaderCheck extends AbstractHeaderCheck { /** @@ -52,6 +55,7 @@ private int[] ignoreLines = EMPTY_INT_ARRAY; /** + * Returns true if lineNo is header lines or false. * @param lineNo a line number * @return if {@code lineNo} is one of the ignored header lines. */ @@ -65,7 +69,7 @@ * @param line the line contents * @return true if and only if the line matches the required header line */ - protected boolean isMatch(int lineNumber, String line) { + private boolean isMatch(int lineNumber, String line) { // skip lines we are meant to ignore return isIgnoreLine(lineNumber + 1) || getHeaderLines().get(lineNumber).equals(line); @@ -78,22 +82,22 @@ public void setIgnoreLines(int... list) { if (list.length == 0) { ignoreLines = EMPTY_INT_ARRAY; - return; } - - ignoreLines = new int[list.length]; - System.arraycopy(list, 0, ignoreLines, 0, list.length); - Arrays.sort(ignoreLines); + else { + ignoreLines = new int[list.length]; + System.arraycopy(list, 0, ignoreLines, 0, list.length); + Arrays.sort(ignoreLines); + } } @Override - protected void processFiltered(File file, List lines) { - if (getHeaderLines().size() > lines.size()) { + protected void processFiltered(File file, FileText fileText) { + if (getHeaderLines().size() > fileText.size()) { log(1, MSG_MISSING); } else { for (int i = 0; i < getHeaderLines().size(); i++) { - if (!isMatch(i, lines.get(i))) { + if (!isMatch(i, fileText.get(i))) { log(i + 1, MSG_MISMATCH, getHeaderLines().get(i)); break; } @@ -105,4 +109,5 @@ protected void postProcessHeaderLines() { // no code } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/RegexpHeaderCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/RegexpHeaderCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/RegexpHeaderCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/header/RegexpHeaderCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,15 +20,14 @@ package com.puppycrawl.tools.checkstyle.checks.header; import java.io.File; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; -import org.apache.commons.beanutils.ConversionException; -import org.apache.commons.lang3.StringUtils; - -import com.google.common.collect.Lists; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.FileText; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** @@ -41,6 +40,7 @@ * @author Lars Kühne * @author o_sukhodolsky */ +@StatelessCheck public class RegexpHeaderCheck extends AbstractHeaderCheck { /** @@ -59,7 +59,7 @@ private static final int[] EMPTY_INT_ARRAY = new int[0]; /** The compiled regular expressions. */ - private final List headerRegexps = Lists.newArrayList(); + private final List headerRegexps = new ArrayList<>(); /** The header lines to repeat (0 or more) in the check, sorted. */ private int[] multiLines = EMPTY_INT_ARRAY; @@ -71,18 +71,18 @@ public void setMultiLines(int... list) { if (list.length == 0) { multiLines = EMPTY_INT_ARRAY; - return; } - - multiLines = new int[list.length]; - System.arraycopy(list, 0, multiLines, 0, list.length); - Arrays.sort(multiLines); + else { + multiLines = new int[list.length]; + System.arraycopy(list, 0, multiLines, 0, list.length); + Arrays.sort(multiLines); + } } @Override - protected void processFiltered(File file, List lines) { + protected void processFiltered(File file, FileText fileText) { final int headerSize = getHeaderLines().size(); - final int fileSize = lines.size(); + final int fileSize = fileText.size(); if (headerSize - multiLines.length > fileSize) { log(1, MSG_HEADER_MISSING); @@ -91,7 +91,7 @@ int headerLineNo = 0; int index; for (index = 0; headerLineNo < headerSize && index < fileSize; index++) { - final String line = lines.get(index); + final String line = fileText.get(index); boolean isMatch = isMatch(line, headerLineNo); while (!isMatch && isMultiLine(headerLineNo)) { headerLineNo++; @@ -140,6 +140,7 @@ } /** + * Returns true if line is multiline header lines or false. * @param lineNo a line number * @return if {@code lineNo} is one of the repeat header lines. */ @@ -150,13 +151,12 @@ @Override protected void postProcessHeaderLines() { final List headerLines = getHeaderLines(); - headerRegexps.clear(); for (String line : headerLines) { try { headerRegexps.add(Pattern.compile(line)); } catch (final PatternSyntaxException ex) { - throw new ConversionException("line " + throw new IllegalArgumentException("line " + (headerRegexps.size() + 1) + " in header specification" + " is not a regular expression", ex); @@ -167,18 +167,17 @@ /** * Validates the {@code header} by compiling it with * {@link Pattern#compile(String) } and throws - * {@link PatternSyntaxException} if {@code header} isn't a valid pattern. + * {@link IllegalArgumentException} if {@code header} isn't a valid pattern. * @param header the header value to validate and set (in that order) */ @Override public void setHeader(String header) { - if (StringUtils.isBlank(header)) { - return; - } - if (!CommonUtils.isPatternValid(header)) { - throw new ConversionException("Unable to parse format: " + header); + if (!CommonUtils.isBlank(header)) { + if (!CommonUtils.isPatternValid(header)) { + throw new IllegalArgumentException("Unable to parse format: " + header); + } + super.setHeader(header); } - super.setHeader(header); } } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AbstractImportRule.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AbstractImportRule.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AbstractImportRule.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AbstractImportRule.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,98 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.imports; + +/** + * Base class for import rules. + * @author Jochen Van de Velde + */ +abstract class AbstractImportRule { + + /** Indicates whether to allow access or not. */ + private final boolean allowed; + + /** Indicates if the rule only applies to this package. */ + private final boolean localOnly; + + /** + * Indicates if the name is to be interpreted + * as a regular expression. + */ + private final boolean regExp; + + /** + * Constructs an instance. + * @param allow whether to allow access. + * @param localOnly whether the rule is to be applied locally only. + * @param regExp whether the name is to be interpreted as a regular + * expression. + */ + protected AbstractImportRule(final boolean allow, final boolean localOnly, + final boolean regExp) { + allowed = allow; + this.localOnly = localOnly; + this.regExp = regExp; + } + + /** + * Verifies whether a package name is used. + * @param forImport the import to check. + * @return a result {@link AccessResult} indicating whether it can be used. + */ + public abstract AccessResult verifyImport(String forImport); + + /** + * Return true if the guard is to only be applied locally or false. + * @return whether the guard is to only be applied locally. + */ + public boolean isLocalOnly() { + return localOnly; + } + + /** + * Return true if the name is to be interpreted as a regular expression or false. + * @return whether the name is to be interpreted as a regular expression. + */ + protected boolean isRegExp() { + return regExp; + } + + /** + * Returns the appropriate {@link AccessResult} based on whether there + * was a match and if the rule is to allow access. + * @param matched indicates whether there was a match. + * @return An appropriate {@link AccessResult}. + */ + protected AccessResult calculateResult(final boolean matched) { + AccessResult result = AccessResult.UNKNOWN; + + if (matched) { + if (allowed) { + result = AccessResult.ALLOWED; + } + else { + result = AccessResult.DISALLOWED; + } + } + + return result; + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AccessResult.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AccessResult.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AccessResult.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AccessResult.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,10 +25,12 @@ * @author Oliver Burn */ enum AccessResult { + /** Represents that access is allowed. */ ALLOWED, /** Represents that access is disallowed. */ DISALLOWED, /** Represents that access is unknown. */ UNKNOWN + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AvoidStarImportCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AvoidStarImportCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AvoidStarImportCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AvoidStarImportCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,11 @@ package com.puppycrawl.tools.checkstyle.checks.imports; +import java.util.ArrayList; import java.util.List; -import com.google.common.collect.Lists; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -62,8 +63,9 @@ * @author Bill Schneider * @author Travis Schneeberger */ +@StatelessCheck public class AvoidStarImportCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -75,7 +77,7 @@ private static final String STAR_IMPORT_SUFFIX = ".*"; /** The packages/classes to exempt from this check. */ - private final List excludes = Lists.newArrayList(); + private final List excludes = new ArrayList<>(); /** Whether to allow all class imports. */ private boolean allowClassImports; @@ -85,12 +87,12 @@ @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT}; + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT}; + return getRequiredTokens(); } @Override @@ -114,8 +116,6 @@ * where star imports are ok. */ public void setExcludes(String... excludesParam) { - excludes.clear(); - for (final String exclude : excludesParam) { if (exclude.endsWith(STAR_IMPORT_SUFFIX)) { excludes.add(exclude); diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AvoidStaticImportCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AvoidStaticImportCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AvoidStaticImportCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/AvoidStaticImportCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,12 +19,12 @@ package com.puppycrawl.tools.checkstyle.checks.imports; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

      @@ -63,8 +63,9 @@ *

      * @author Travis Schneeberger */ +@StatelessCheck public class AvoidStaticImportCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -73,21 +74,21 @@ public static final String MSG_KEY = "import.avoidStatic"; /** The classes/static members to exempt from this check. */ - private String[] excludes = ArrayUtils.EMPTY_STRING_ARRAY; + private String[] excludes = CommonUtils.EMPTY_STRING_ARRAY; @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.STATIC_IMPORT}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.STATIC_IMPORT}; } /** @@ -157,4 +158,5 @@ } return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ClassImportRule.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ClassImportRule.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ClassImportRule.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ClassImportRule.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,64 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.imports; + +/** + * Represents whether a class is allowed to be imported or not. + * @author Oliver Burn + */ +class ClassImportRule extends AbstractImportRule { + + /** Package to control access to. */ + private final String className; + + /** + * Constructs an instance. + * @param allow whether to allow access. + * @param localOnly whether the rule is to be applied locally only + * @param className the class to apply the rule on. + * @param regExp whether the class name is to be interpreted as a regular + * expression. + */ + ClassImportRule(final boolean allow, final boolean localOnly, + final String className, final boolean regExp) { + super(allow, localOnly, regExp); + this.className = className; + } + + /** + * Verifies whether a class name is used. + * @param forImport the import to check. + * @return a result {@link AccessResult} indicating whether it can be used. + */ + @Override + public AccessResult verifyImport(final String forImport) { + final boolean classMatch; + + if (isRegExp()) { + classMatch = forImport.matches(className); + } + else { + classMatch = forImport.equals(className); + } + + return calculateResult(classMatch); + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/CustomImportOrderCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/CustomImportOrderCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/CustomImportOrderCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/CustomImportOrderCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,7 +25,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -158,7 +159,7 @@ * stringnull * standardPackageRegExpRegExp for STANDARD_JAVA_PACKAGE group imports. * regular expression^(java|javax)\. - * thirdPartyPackageRegExpRegExp for THIRDPARTY_PACKAGE group imports. + * thirdPartyPackageRegExpRegExp for THIRD_PARTY_PACKAGE group imports. * regular expression.* * specialImportsRegExpRegExp for SPECIAL_IMPORTS group imports. * regular expression^$ @@ -302,7 +303,8 @@ * @author maxvetrenko * @author Aleksey Nesterenko */ -public class CustomImportOrderCheck extends Check { +@FileStatefulCheck +public class CustomImportOrderCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -367,7 +369,7 @@ /** RegExp for STANDARD_JAVA_PACKAGE group imports. */ private Pattern standardPackageRegExp = Pattern.compile("^(java|javax)\\."); - /** RegExp for THIRDPARTY_PACKAGE group imports. */ + /** RegExp for THIRD_PARTY_PACKAGE group imports. */ private Pattern thirdPartyPackageRegExp = Pattern.compile(".*"); /** RegExp for SPECIAL_IMPORTS group imports. */ @@ -386,33 +388,27 @@ * Sets standardRegExp specified by user. * @param regexp * user value. - * @throws org.apache.commons.beanutils.ConversionException - * if unable to create Pattern object. */ - public final void setStandardPackageRegExp(String regexp) { - standardPackageRegExp = CommonUtils.createPattern(regexp); + public final void setStandardPackageRegExp(Pattern regexp) { + standardPackageRegExp = regexp; } /** * Sets thirdPartyRegExp specified by user. * @param regexp * user value. - * @throws org.apache.commons.beanutils.ConversionException - * if unable to create Pattern object. */ - public final void setThirdPartyPackageRegExp(String regexp) { - thirdPartyPackageRegExp = CommonUtils.createPattern(regexp); + public final void setThirdPartyPackageRegExp(Pattern regexp) { + thirdPartyPackageRegExp = regexp; } /** * Sets specialImportsRegExp specified by user. * @param regexp * user value. - * @throws org.apache.commons.beanutils.ConversionException - * if unable to create Pattern object. */ - public final void setSpecialImportsRegExp(String regexp) { - specialImportsRegExp = CommonUtils.createPattern(regexp); + public final void setSpecialImportsRegExp(Pattern regexp) { + specialImportsRegExp = regexp; } /** @@ -440,7 +436,6 @@ * user value. */ public final void setCustomImportOrderRules(final String inputCustomImportOrder) { - customImportOrderRules.clear(); for (String currentState : GROUP_SEPARATOR_PATTERN.split(inputCustomImportOrder)) { addRulesToList(currentState); } @@ -449,11 +444,16 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { return new int[] { TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT, @@ -462,11 +462,6 @@ } @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); - } - - @Override public void beginTree(DetailAST rootAST) { importToGroupList.clear(); } @@ -491,11 +486,13 @@ @Override public void finishTree(DetailAST rootAST) { - - if (importToGroupList.isEmpty()) { - return; + if (!importToGroupList.isEmpty()) { + finishImportList(); } + } + /** Examine the order of all the imports and log any violations. */ + private void finishImportList() { final ImportDetails firstImport = importToGroupList.get(0); String currentGroup = getImportGroup(firstImport.isStaticImport(), firstImport.getImportFullPath()); @@ -506,6 +503,9 @@ final String importGroup = importObject.getImportGroup(); final String fullImportIdent = importObject.getImportFullPath(); + if (getCountOfEmptyLinesBefore(importObject.getLineNumber()) > 1) { + log(importObject.getLineNumber(), MSG_LINE_SEPARATOR, fullImportIdent); + } if (importGroup.equals(currentGroup)) { if (sortImportsInGroupAlphabetically && previousImportFromCurrentGroup != null @@ -523,7 +523,7 @@ final String nextGroup = getNextImportGroup(currentGroupNumber + 1); if (importGroup.equals(nextGroup)) { if (separateLineBetweenGroups - && !hasEmptyLineBefore(importObject.getLineNumber())) { + && getCountOfEmptyLinesBefore(importObject.getLineNumber()) == 0) { log(importObject.getLineNumber(), MSG_LINE_SEPARATOR, fullImportIdent); } currentGroup = nextGroup; @@ -594,12 +594,14 @@ * true, if current group contains at least one import. */ private boolean hasAnyImportInCurrentGroup(String currentGroup) { + boolean result = false; for (ImportDetails currentImport : importToGroupList) { if (currentGroup.equals(currentImport.getImportGroup())) { - return true; + result = true; + break; } } - return false; + return result; } /** @@ -618,7 +620,7 @@ } else if (customImportOrderRules.contains(SAME_PACKAGE_RULE_GROUP)) { final String importPathTrimmedToSamePackageDepth = - getFirstNDomainsFromIdent(samePackageMatchingDepth, importPath); + getFirstDomainsFromIdent(samePackageMatchingDepth, importPath); if (samePackageDomainsRegExp.equals(importPathTrimmedToSamePackageDepth)) { bestMatch.group = SAME_PACKAGE_RULE_GROUP; bestMatch.matchLength = importPath.length(); @@ -632,7 +634,7 @@ } if (SPECIAL_IMPORTS_RULE_GROUP.equals(group)) { bestMatch = findBetterPatternMatch(importPath, - SPECIAL_IMPORTS_RULE_GROUP, specialImportsRegExp, bestMatch); + group, specialImportsRegExp, bestMatch); } } } @@ -687,7 +689,7 @@ final String separator = "\\."; final String[] import1Tokens = import1.split(separator); final String[] import2Tokens = import2.split(separator); - for (int i = 0; i < import1Tokens.length && i != import2Tokens.length; i++) { + for (int i = 0; i != import1Tokens.length && i != import2Tokens.length; i++) { final String import1Token = import1Tokens[i]; final String import2Token = import2Tokens[i]; result = import1Token.compareTo(import2Token); @@ -695,20 +697,30 @@ break; } } + if (result == 0) { + result = Integer.compare(import1Tokens.length, import2Tokens.length); + } return result; } /** - * Checks if a token has a empty line before. + * Counts empty lines before given. * @param lineNo * Line number of current import. - * @return true, if token have empty line before. + * @return count of empty lines before given. */ - private boolean hasEmptyLineBefore(int lineNo) { + private int getCountOfEmptyLinesBefore(int lineNo) { + int result = 0; + final String[] lines = getLines(); // [lineNo - 2] is the number of the previous line // because the numbering starts from zero. - final String lineBefore = getLine(lineNo - 2); - return lineBefore.trim().isEmpty(); + int lineBeforeIndex = lineNo - 2; + while (lineBeforeIndex >= 0 + && CommonUtils.isBlank(lines[lineBeforeIndex])) { + lineBeforeIndex--; + result++; + } + return result; } /** @@ -718,12 +730,11 @@ * @return full path or null. */ private static String getFullImportIdent(DetailAST token) { - if (token == null) { - return ""; - } - else { - return FullIdent.createFullIdent(token.findFirstToken(TokenTypes.DOT)).getText(); + String ident = ""; + if (token != null) { + ident = FullIdent.createFullIdent(token.findFirstToken(TokenTypes.DOT)).getText(); } + return ident; } /** @@ -737,10 +748,8 @@ || STANDARD_JAVA_PACKAGE_RULE_GROUP.equals(ruleStr) || SPECIAL_IMPORTS_RULE_GROUP.equals(ruleStr)) { customImportOrderRules.add(ruleStr); - } else if (ruleStr.startsWith(SAME_PACKAGE_RULE_GROUP)) { - final String rule = ruleStr.substring(ruleStr.indexOf('(') + 1, ruleStr.indexOf(')')); samePackageMatchingDepth = Integer.parseInt(rule); @@ -749,7 +758,6 @@ "SAME_PACKAGE rule parameter should be positive integer: " + ruleStr); } customImportOrderRules.add(SAME_PACKAGE_RULE_GROUP); - } else { throw new IllegalStateException("Unexpected rule: " + ruleStr); @@ -767,11 +775,11 @@ private static String createSamePackageRegexp(int firstPackageDomainsCount, DetailAST packageNode) { final String packageFullPath = getFullImportIdent(packageNode); - return getFirstNDomainsFromIdent(firstPackageDomainsCount, packageFullPath); + return getFirstDomainsFromIdent(firstPackageDomainsCount, packageFullPath); } /** - * Extracts defined amount of domains from the left side of package/import identifier + * Extracts defined amount of domains from the left side of package/import identifier. * @param firstPackageDomainsCount * number of first package domains. * @param packageFullPath @@ -779,9 +787,9 @@ * @return String with defined amount of domains or full identifier * (if full identifier had less domain then specified) */ - private static String getFirstNDomainsFromIdent( + private static String getFirstDomainsFromIdent( final int firstPackageDomainsCount, final String packageFullPath) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(256); final StringTokenizer tokens = new StringTokenizer(packageFullPath, "."); int count = firstPackageDomainsCount; @@ -798,6 +806,7 @@ * @author max */ private static class ImportDetails { + /** Import full path. */ private final String importFullPath; @@ -811,6 +820,7 @@ private final boolean staticImport; /** + * Initialise importFullPath, lineNumber, importGroup, staticImport. * @param importFullPath * import full path. * @param lineNumber @@ -859,6 +869,7 @@ public boolean isStaticImport() { return staticImport; } + } /** @@ -867,6 +878,7 @@ * @author ivanov-alex */ private static class RuleMatchForImport { + /** Position of matching string for current best match. */ private final int matchPosition; /** Length of matching string for current best match. */ @@ -887,5 +899,7 @@ matchLength = length; matchPosition = position; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/Guard.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/Guard.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/Guard.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/Guard.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,151 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.checks.imports; - -/** - * Represents whether a package is allowed to be used or not. - * @author Oliver Burn - */ -class Guard { - /** Indicates if allow access or not. */ - private final boolean allowed; - /** Package to control access to. */ - private final String pkgName; - /** Package to control access to. */ - private final String className; - - /** - * Indicates if must be an exact match. Only valid if guard using a - * package. - */ - private final boolean exactMatch; - /** Indicates if the guard only applies to this package. */ - private final boolean localOnly; - /** - * Indicates if the package and the class names are to be interpreted - * as regular expressions. - */ - private final boolean regExp; - - /** - * Constructs an instance. - * @param allow whether to allow access. - * @param localOnly whether guard is to be applied locally only - * @param pkgName the package to apply guard on. - * @param exactMatch whether the package must match exactly. - * @param regExp whether the package is to be interpreted as regular - * expression. - */ - Guard(final boolean allow, final boolean localOnly, - final String pkgName, final boolean exactMatch, final boolean regExp) { - allowed = allow; - this.localOnly = localOnly; - this.pkgName = pkgName; - this.regExp = regExp; - className = null; - this.exactMatch = exactMatch; - } - - /** - * Constructs an instance. - * @param allow whether to allow access. - * @param localOnly whether guard is to be applied locally only - * @param className the class to apply guard on. - * @param regExp whether the class is to be interpreted as regular - * expression. - */ - Guard(final boolean allow, final boolean localOnly, - final String className, final boolean regExp) { - allowed = allow; - this.localOnly = localOnly; - this.regExp = regExp; - pkgName = null; - this.className = className; - - // not used - exactMatch = true; - } - - /** - * Verifies whether a package name be used. - * @param forImport the package to check. - * @return a result {@link AccessResult} indicating whether it can be used. - */ - AccessResult verifyImport(final String forImport) { - if (className != null) { - final boolean classMatch; - - if (regExp) { - classMatch = forImport.matches(className); - } - else { - classMatch = forImport.equals(className); - } - return calculateResult(classMatch); - } - - // Must be checking a package. First check that we actually match - // the package. Then check if matched and we must be an exact match. - // In this case, the text after the first "." must not contain - // another "." as this indicates that it is not an exact match. - boolean pkgMatch; - if (regExp) { - pkgMatch = forImport.matches(pkgName + "\\..*"); - if (pkgMatch && exactMatch) { - pkgMatch = !forImport.matches(pkgName + "\\..*\\..*"); - } - } - else { - pkgMatch = forImport.startsWith(pkgName + "."); - if (pkgMatch && exactMatch) { - pkgMatch = forImport.indexOf('.', - pkgName.length() + 1) == -1; - } - } - return calculateResult(pkgMatch); - } - - /** - * @return returns whether the guard is to only be applied locally. - */ - boolean isLocalOnly() { - return localOnly; - } - - /** - * Returns the appropriate {@link AccessResult} based on whether there - * was a match and if the guard is to allow access. - * @param matched indicates whether there was a match. - * @return An appropriate {@link AccessResult}. - */ - private AccessResult calculateResult(final boolean matched) { - AccessResult result = AccessResult.UNKNOWN; - - if (matched) { - if (allowed) { - result = AccessResult.ALLOWED; - } - else { - result = AccessResult.DISALLOWED; - } - } - return result; - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/IllegalImportCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,16 @@ package com.puppycrawl.tools.checkstyle.checks.imports; -import com.puppycrawl.tools.checkstyle.api.Check; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

      @@ -57,8 +63,9 @@ * @author Oliver Burn * @author Lars Kühne */ +@StatelessCheck public class IllegalImportCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -66,9 +73,24 @@ */ public static final String MSG_KEY = "import.illegal"; + /** The compiled regular expressions for packages. */ + private final List illegalPkgsRegexps = new ArrayList<>(); + + /** The compiled regular expressions for classes. */ + private final List illegalClassesRegexps = new ArrayList<>(); + /** List of illegal packages. */ private String[] illegalPkgs; + /** List of illegal classes. */ + private String[] illegalClasses; + + /** + * Whether the packages or class names + * should be interpreted as regular expressions. + */ + private boolean regexp; + /** * Creates a new {@code IllegalImportCheck} instance. */ @@ -79,24 +101,49 @@ /** * Set the list of illegal packages. * @param from array of illegal packages + * @noinspection WeakerAccess */ public final void setIllegalPkgs(String... from) { illegalPkgs = from.clone(); + illegalPkgsRegexps.clear(); + for (String illegalPkg : illegalPkgs) { + illegalPkgsRegexps.add(CommonUtils.createPattern("^" + illegalPkg + "\\..*")); + } + } + + /** + * Set the list of illegal classes. + * @param from array of illegal classes + */ + public void setIllegalClasses(String... from) { + illegalClasses = from.clone(); + for (String illegalClass : illegalClasses) { + illegalClassesRegexps.add(CommonUtils.createPattern(illegalClass)); + } + } + + /** + * Controls whether the packages or class names + * should be interpreted as regular expressions. + * @param regexp a {@code Boolean} value + */ + public void setRegexp(boolean regexp) { + this.regexp = regexp; } @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT}; } @Override @@ -118,16 +165,69 @@ } /** - * Checks if an import is from a package that must not be used. + * Checks if an import matches one of the regular expressions + * for illegal packages or illegal class names. * @param importText the argument of the import keyword - * @return if {@code importText} contains an illegal package prefix + * @return if {@code importText} matches one of the regular expressions + * for illegal packages or illegal class names */ - private boolean isIllegalImport(String importText) { + private boolean isIllegalImportByRegularExpressions(String importText) { + boolean result = false; + for (Pattern pattern : illegalPkgsRegexps) { + if (pattern.matcher(importText).matches()) { + result = true; + break; + } + } + if (!result) { + for (Pattern pattern : illegalClassesRegexps) { + if (pattern.matcher(importText).matches()) { + result = true; + break; + } + } + } + return result; + } + + /** + * Checks if an import is from a package or class name that must not be used. + * @param importText the argument of the import keyword + * @return if {@code importText} contains an illegal package prefix or equals illegal class name + */ + private boolean isIllegalImportByPackagesAndClassNames(String importText) { + boolean result = false; for (String element : illegalPkgs) { if (importText.startsWith(element + ".")) { - return true; + result = true; + break; + } + } + if (!result && illegalClasses != null) { + for (String element : illegalClasses) { + if (importText.equals(element)) { + result = true; + break; + } } } - return false; + return result; } + + /** + * Checks if an import is from a package or class name that must not be used. + * @param importText the argument of the import keyword + * @return if {@code importText} is illegal import + */ + private boolean isIllegalImport(String importText) { + final boolean result; + if (regexp) { + result = isIllegalImportByRegularExpressions(importText); + } + else { + result = isIllegalImportByPackagesAndClassNames(importText); + } + return result; + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,15 +19,16 @@ package com.puppycrawl.tools.checkstyle.checks.imports; -import java.io.File; import java.net.URI; +import java.util.Collections; +import java.util.Set; +import java.util.regex.Pattern; -import org.apache.commons.beanutils.ConversionException; -import org.apache.commons.lang3.StringUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -44,7 +45,8 @@ * * @author Oliver Burn */ -public class ImportControlCheck extends Check { +@FileStatefulCheck +public class ImportControlCheck extends AbstractCheck implements ExternalResourceHolder { /** * A key is pointing to the warning message text in "messages.properties" @@ -69,115 +71,131 @@ */ private static final String UNABLE_TO_LOAD = "Unable to load "; + /** Location of import control file. */ + private URI file; + + /** The filepath pattern this check applies to. */ + private Pattern path = Pattern.compile(".*"); + /** Whether to process the current file. */ + private boolean processCurrentFile; + /** The root package controller. */ - private PkgControl root; + private ImportControl root; /** The package doing the import. */ - private String inPkg; + private String packageName; /** * The package controller for the current file. Used for performance * optimisation. */ - private PkgControl currentLeaf; + private ImportControl currentImportControl; @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.PACKAGE_DEF, TokenTypes.IMPORT, - TokenTypes.STATIC_IMPORT, }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.PACKAGE_DEF, TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT, }; } @Override - public void beginTree(final DetailAST rootAST) { - currentLeaf = null; + public void beginTree(DetailAST rootAST) { + currentImportControl = null; + processCurrentFile = path.matcher(getFileContents().getFileName()).find(); } @Override - public void visitToken(final DetailAST ast) { - if (ast.getType() == TokenTypes.PACKAGE_DEF) { - final DetailAST nameAST = ast.getLastChild().getPreviousSibling(); - final FullIdent full = FullIdent.createFullIdent(nameAST); - if (root == null) { - log(nameAST, MSG_MISSING_FILE); - } - else { - inPkg = full.getText(); - currentLeaf = root.locateFinest(inPkg); - if (currentLeaf == null) { - log(nameAST, MSG_UNKNOWN_PKG); + public void visitToken(DetailAST ast) { + if (processCurrentFile) { + if (ast.getType() == TokenTypes.PACKAGE_DEF) { + if (root == null) { + log(ast, MSG_MISSING_FILE); + } + else { + packageName = getPackageText(ast); + currentImportControl = root.locateFinest(packageName); + if (currentImportControl == null) { + log(ast, MSG_UNKNOWN_PKG); + } } } - } - else if (currentLeaf != null) { - final FullIdent imp; - if (ast.getType() == TokenTypes.IMPORT) { - imp = FullIdent.createFullIdentBelow(ast); - } - else { - // know it is a static import - imp = FullIdent.createFullIdent(ast - .getFirstChild().getNextSibling()); - } - final AccessResult access = currentLeaf.checkAccess(imp.getText(), - inPkg); - if (access != AccessResult.ALLOWED) { - log(ast, MSG_DISALLOWED, imp.getText()); + else if (currentImportControl != null) { + final String importText = getImportText(ast); + final AccessResult access = + currentImportControl.checkAccess(packageName, importText); + if (access != AccessResult.ALLOWED) { + log(ast, MSG_DISALLOWED, importText); + } } } } + @Override + public Set getExternalResourceLocations() { + return Collections.singleton(file.toString()); + } + /** - * Set the name for the file containing the import control - * configuration. It will cause the file to be loaded. - * @param name the name of the file to load. - * @throws ConversionException on error loading the file. + * Returns package text. + * @param ast PACKAGE_DEF ast node + * @return String that represents full package name */ - public void setFile(final String name) { - // Handle empty param - if (StringUtils.isBlank(name)) { - return; - } + private static String getPackageText(DetailAST ast) { + final DetailAST nameAST = ast.getLastChild().getPreviousSibling(); + return FullIdent.createFullIdent(nameAST).getText(); + } - try { - root = ImportControlLoader.load(new File(name).toURI()); + /** + * Returns import text. + * @param ast ast node that represents import + * @return String that represents importing class + */ + private static String getImportText(DetailAST ast) { + final FullIdent imp; + if (ast.getType() == TokenTypes.IMPORT) { + imp = FullIdent.createFullIdentBelow(ast); } - catch (final CheckstyleException ex) { - throw new ConversionException(UNABLE_TO_LOAD + name, ex); + else { + // know it is a static import + imp = FullIdent.createFullIdent(ast + .getFirstChild().getNextSibling()); } + return imp.getText(); } /** - * Set the parameter for the url containing the import control - * configuration. It will cause the url to be loaded. - * @param url the url of the file to load. - * @throws ConversionException on error loading the file. + * Set the name for the file containing the import control + * configuration. It can also be a URL or resource in the classpath. + * It will cause the file to be loaded. + * @param uri the uri of the file to load. + * @throws IllegalArgumentException on error loading the file. */ - public void setUrl(final String url) { + public void setFile(URI uri) { // Handle empty param - if (StringUtils.isBlank(url)) { - return; - } - final URI uri; - try { - uri = URI.create(url); - } - catch (final IllegalArgumentException ex) { - throw new ConversionException("Syntax error in url " + url, ex); - } - try { - root = ImportControlLoader.load(uri); - } - catch (final CheckstyleException ex) { - throw new ConversionException(UNABLE_TO_LOAD + url, ex); + if (uri != null) { + try { + root = ImportControlLoader.load(uri); + file = uri; + } + catch (CheckstyleException ex) { + throw new IllegalArgumentException(UNABLE_TO_LOAD + uri, ex); + } } } + + /** + * Set the file path pattern that this check applies to. + * @param pattern the file path regex this check should apply to. + */ + public void setPath(Pattern pattern) { + path = pattern; + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControl.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControl.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControl.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControl.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,353 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.imports; + +import java.util.ArrayList; +import java.util.Deque; +import java.util.LinkedList; +import java.util.List; +import java.util.regex.Pattern; + +/** + * Represents a tree of import rules for controlling whether packages or + * classes are allowed to be used. Each instance must have a single parent or + * be the root node. Each instance may have zero or more children. + * + * @author Oliver Burn + */ +class ImportControl { + + /** The package separator: "." */ + private static final String DOT = "."; + /** A pattern matching the package separator: "." */ + private static final Pattern DOT_PATTERN = Pattern.compile(DOT, Pattern.LITERAL); + /** The regex for the package separator: "\\.". */ + private static final String DOT_REGEX = "\\."; + /** List of {@link AbstractImportRule} objects to check. */ + private final Deque rules = new LinkedList<>(); + /** List of children {@link ImportControl} objects. */ + private final List children = new ArrayList<>(); + /** The parent. Null indicates we are the root node. */ + private final ImportControl parent; + /** The full package name for the node. */ + private final String fullPackage; + /** + * The regex pattern for partial match (exact and for subpackages) - only not + * null if regex is true. + */ + private final Pattern patternForPartialMatch; + /** The regex pattern for exact matches - only not null if regex is true. */ + private final Pattern patternForExactMatch; + /** If this package represents a regular expression. */ + private final boolean regex; + /** Strategy in a case if matching allow/disallow rule was not found. */ + private final MismatchStrategy strategyOnMismatch; + + /** + * Construct a root node. + * @param pkgName the name of the package. + * @param regex flags interpretation of pkgName as regex pattern. + * @param strategyOnMismatch strategy in a case if matching allow/disallow rule was not found. + */ + ImportControl(String pkgName, boolean regex, + MismatchStrategy strategyOnMismatch) { + parent = null; + this.regex = regex; + this.strategyOnMismatch = strategyOnMismatch; + if (regex) { + // ensure that fullPackage is a self-contained regular expression + fullPackage = encloseInGroup(pkgName); + patternForPartialMatch = createPatternForPartialMatch(fullPackage); + patternForExactMatch = createPatternForExactMatch(fullPackage); + } + else { + fullPackage = pkgName; + patternForPartialMatch = null; + patternForExactMatch = null; + } + } + + /** + * Construct a root node. + * @param pkgName the name of the package. + * @param regex flags interpretation of pkgName as regex pattern. + */ + ImportControl(String pkgName, boolean regex) { + this(pkgName, regex, MismatchStrategy.DISALLOWED); + } + + /** + * Construct a child node. The concatenation of regular expressions needs special care: + * see {@link #ensureSelfContainedRegex(String, boolean)} for more details. + * @param parent the parent node. + * @param subPkg the sub package name. + * @param regex flags interpretation of subPkg as regex pattern. + * @param strategyOnMismatch strategy in a case if matching allow/disallow rule was not found. + */ + ImportControl(ImportControl parent, String subPkg, boolean regex, + MismatchStrategy strategyOnMismatch) { + this.parent = parent; + this.strategyOnMismatch = strategyOnMismatch; + if (regex || parent.regex) { + // regex gets inherited + final String parentRegex = ensureSelfContainedRegex(parent.fullPackage, parent.regex); + final String thisRegex = ensureSelfContainedRegex(subPkg, regex); + fullPackage = parentRegex + DOT_REGEX + thisRegex; + patternForPartialMatch = createPatternForPartialMatch(fullPackage); + patternForExactMatch = createPatternForExactMatch(fullPackage); + this.regex = true; + } + else { + fullPackage = parent.fullPackage + DOT + subPkg; + patternForPartialMatch = null; + patternForExactMatch = null; + this.regex = false; + } + } + + /** + * Construct a child node. The concatenation of regular expressions needs special care: + * see {@link #ensureSelfContainedRegex(String, boolean)} for more details. + * @param parent the parent node. + * @param subPkg the sub package name. + * @param regex flags interpretation of subPkg as regex pattern. + */ + ImportControl(ImportControl parent, String subPkg, boolean regex) { + this(parent, subPkg, regex, MismatchStrategy.DELEGATE_TO_PARENT); + } + + /** + * Returns a regex that is suitable for concatenation by 1) either converting a plain string + * into a regular expression (handling special characters) or 2) by enclosing {@code input} in + * a (non-capturing) group if {@code input} already is a regular expression. + * + *

      1) When concatenating a non-regex package component (like "org.google") with a regex + * component (like "[^.]+") the other component has to be converted into a regex too, see + * {@link #toRegex(String)}. + * + *

      2) The grouping is strictly necessary if a) {@code input} is a regular expression that b) + * contains the alteration character ('|') and if c) the pattern is not already enclosed in a + * group - as you see in this example: {@code parent="com|org", child="common|uncommon"} will + * result in the pattern {@code "(?:org|com)\.(?common|uncommon)"} what will match + * {@code "com.common"}, {@code "com.uncommon"}, {@code "org.common"}, and {@code + * "org.uncommon"}. Without the grouping it would be {@code "com|org.common|uncommon"} which + * would match {@code "com"}, {@code "org.common"}, and {@code "uncommon"}, which clearly is + * undesirable. Adding the group fixes this. + * + *

      For simplicity the grouping is added to regular expressions unconditionally. + * + * @param input the input string. + * @param alreadyRegex signals if input already is a regular expression. + * @return a regex string. + */ + private static String ensureSelfContainedRegex(String input, boolean alreadyRegex) { + final String result; + if (alreadyRegex) { + result = encloseInGroup(input); + } + else { + result = toRegex(input); + } + return result; + } + + /** + * Enclose {@code expression} in a (non-capturing) group. + * @param expression the input regular expression + * @return a grouped pattern. + */ + private static String encloseInGroup(String expression) { + return "(?:" + expression + ")"; + } + + /** + * Converts a normal package name into a regex pattern by escaping all + * special characters that may occur in a java package name. + * @param input the input string. + * @return a regex string. + */ + private static String toRegex(String input) { + return DOT_PATTERN.matcher(input).replaceAll(DOT_REGEX); + } + + /** + * Creates a Pattern from {@code expression} that matches exactly and child packages. + * @param expression a self-contained regular expression matching the full package exactly. + * @return a Pattern. + */ + private static Pattern createPatternForPartialMatch(String expression) { + // javadoc of encloseInGroup() explains how to concatenate regular expressions + // no grouping needs to be added to fullPackage since this already have been done. + return Pattern.compile(expression + "(?:\\..*)?"); + } + + /** + * Creates a Pattern from {@code expression}. + * @param expression a self-contained regular expression matching the full package exactly. + * @return a Pattern. + */ + private static Pattern createPatternForExactMatch(String expression) { + return Pattern.compile(expression); + } + + /** + * Adds an {@link AbstractImportRule} to the node. + * @param rule the rule to be added. + */ + protected void addImportRule(AbstractImportRule rule) { + rules.addFirst(rule); + } + + /** + * Adds new child import control. + * @param importControl child import control + */ + public void addChild(ImportControl importControl) { + children.add(importControl); + } + + /** + * Search down the tree to locate the finest match for a supplied package. + * @param forPkg the package to search for. + * @return the finest match, or null if no match at all. + */ + public ImportControl locateFinest(String forPkg) { + ImportControl finestMatch = null; + // Check if we are a match. + if (matchesAtFront(forPkg)) { + // If there won't be match so I am the best there is. + finestMatch = this; + // Check if any of the children match. + for (ImportControl child : children) { + final ImportControl match = child.locateFinest(forPkg); + if (match != null) { + finestMatch = match; + break; + } + } + } + return finestMatch; + } + + /** + * Matches other package name exactly or partially at front. + * @param pkg the package to compare with. + * @return if it matches. + */ + private boolean matchesAtFront(String pkg) { + final boolean result; + if (regex) { + result = patternForPartialMatch.matcher(pkg).matches(); + } + else { + result = matchesAtFrontNoRegex(pkg); + } + return result; + } + + /** + * Non-regex case. Ensure a trailing dot for subpackages, i.e. "com.puppy" + * will match "com.puppy.crawl" but not "com.puppycrawl.tools". + * @param pkg the package to compare with. + * @return if it matches. + */ + private boolean matchesAtFrontNoRegex(String pkg) { + return pkg.startsWith(fullPackage) + && (pkg.length() == fullPackage.length() + || pkg.charAt(fullPackage.length()) == '.'); + } + + /** + * Returns whether a package or class is allowed to be imported. + * The algorithm checks with the current node for a result, and if none is + * found then calls its parent looking for a match. This will recurse + * looking for match. If there is no clear result then + * {@link AccessResult#UNKNOWN} is returned. + * @param forImport the import to check on. + * @param inPkg the package doing the import. + * @return an {@link AccessResult}. + */ + public AccessResult checkAccess(String inPkg, String forImport) { + final AccessResult result; + final AccessResult returnValue = localCheckAccess(inPkg, forImport); + if (returnValue != AccessResult.UNKNOWN) { + result = returnValue; + } + else if (parent == null) { + if (strategyOnMismatch == MismatchStrategy.ALLOWED) { + result = AccessResult.ALLOWED; + } + else { + result = AccessResult.DISALLOWED; + } + } + else { + if (strategyOnMismatch == MismatchStrategy.ALLOWED) { + result = AccessResult.ALLOWED; + } + else if (strategyOnMismatch == MismatchStrategy.DISALLOWED) { + result = AccessResult.DISALLOWED; + } + else { + result = parent.checkAccess(inPkg, forImport); + } + } + return result; + } + + /** + * Checks whether any of the rules for this node control access to + * a specified package or class. + * @param forImport the import to check. + * @param inPkg the package doing the import. + * @return an {@link AccessResult}. + */ + private AccessResult localCheckAccess(String inPkg, String forImport) { + AccessResult localCheckAccessResult = AccessResult.UNKNOWN; + for (AbstractImportRule importRule : rules) { + // Check if an import rule is only meant to be applied locally. + if (!importRule.isLocalOnly() || matchesExactly(inPkg)) { + final AccessResult result = importRule.verifyImport(forImport); + if (result != AccessResult.UNKNOWN) { + localCheckAccessResult = result; + break; + } + } + } + return localCheckAccessResult; + } + + /** + * Check for equality of this with pkg. + * @param pkg the package to compare with. + * @return if it matches. + */ + private boolean matchesExactly(String pkg) { + final boolean result; + if (regex) { + result = patternForExactMatch.matcher(pkg).matches(); + } + else { + result = fullPackage.equals(pkg); + } + return result; + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportControlLoader.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -34,14 +34,15 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import com.puppycrawl.tools.checkstyle.api.AbstractLoader; +import com.puppycrawl.tools.checkstyle.XmlLoader; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; /** * Responsible for loading the contents of an import control configuration file. * @author Oliver Burn */ -final class ImportControlLoader extends AbstractLoader { +final class ImportControlLoader extends XmlLoader { + /** The public ID for the configuration dtd. */ private static final String DTD_PUBLIC_ID_1_0 = "-//Puppy Crawl//DTD Import Control 1.0//EN"; @@ -50,6 +51,14 @@ private static final String DTD_PUBLIC_ID_1_1 = "-//Puppy Crawl//DTD Import Control 1.1//EN"; + /** The public ID for the configuration dtd. */ + private static final String DTD_PUBLIC_ID_1_2 = + "-//Puppy Crawl//DTD Import Control 1.2//EN"; + + /** The public ID for the configuration dtd. */ + private static final String DTD_PUBLIC_ID_1_3 = + "-//Puppy Crawl//DTD Import Control 1.3//EN"; + /** The resource for the configuration dtd. */ private static final String DTD_RESOURCE_NAME_1_0 = "com/puppycrawl/tools/checkstyle/checks/imports/import_control_1_0.dtd"; @@ -58,24 +67,43 @@ private static final String DTD_RESOURCE_NAME_1_1 = "com/puppycrawl/tools/checkstyle/checks/imports/import_control_1_1.dtd"; + /** The resource for the configuration dtd. */ + private static final String DTD_RESOURCE_NAME_1_2 = + "com/puppycrawl/tools/checkstyle/checks/imports/import_control_1_2.dtd"; + + /** The resource for the configuration dtd. */ + private static final String DTD_RESOURCE_NAME_1_3 = + "com/puppycrawl/tools/checkstyle/checks/imports/import_control_1_3.dtd"; + /** The map to lookup the resource name by the id. */ private static final Map DTD_RESOURCE_BY_ID = new HashMap<>(); /** Name for attribute 'pkg'. */ private static final String PKG_ATTRIBUTE_NAME = "pkg"; + /** Name for attribute 'strategyOnMismatch'. */ + private static final String STRATEGY_ON_MISMATCH_ATTRIBUTE_NAME = "strategyOnMismatch"; + + /** Value "allowed" for attribute 'strategyOnMismatch'. */ + private static final String STRATEGY_ON_MISMATCH_ALLOWED_VALUE = "allowed"; + + /** Value "disallowed" for attribute 'strategyOnMismatch'. */ + private static final String STRATEGY_ON_MISMATCH_DISALLOWED_VALUE = "disallowed"; + /** Qualified name for element 'subpackage'. */ private static final String SUBPACKAGE_ELEMENT_NAME = "subpackage"; /** Qualified name for element 'allow'. */ private static final String ALLOW_ELEMENT_NAME = "allow"; - /** Used to hold the {@link PkgControl} objects. */ - private final Deque stack = new ArrayDeque<>(); + /** Used to hold the {@link ImportControl} objects. */ + private final Deque stack = new ArrayDeque<>(); static { DTD_RESOURCE_BY_ID.put(DTD_PUBLIC_ID_1_0, DTD_RESOURCE_NAME_1_0); DTD_RESOURCE_BY_ID.put(DTD_PUBLIC_ID_1_1, DTD_RESOURCE_NAME_1_1); + DTD_RESOURCE_BY_ID.put(DTD_PUBLIC_ID_1_2, DTD_RESOURCE_NAME_1_2); + DTD_RESOURCE_BY_ID.put(DTD_PUBLIC_ID_1_3, DTD_RESOURCE_NAME_1_3); } /** @@ -89,18 +117,26 @@ } @Override - public void startElement(final String namespaceUri, - final String localName, - final String qName, - final Attributes attributes) - throws SAXException { + public void startElement(String namespaceUri, + String localName, + String qName, + Attributes attributes) + throws SAXException { if ("import-control".equals(qName)) { final String pkg = safeGet(attributes, PKG_ATTRIBUTE_NAME); - stack.push(new PkgControl(pkg)); + final MismatchStrategy strategyOnMismatch = getStrategyForImportControl(attributes); + final boolean regex = containsRegexAttribute(attributes); + stack.push(new ImportControl(pkg, regex, strategyOnMismatch)); } else if (SUBPACKAGE_ELEMENT_NAME.equals(qName)) { final String name = safeGet(attributes, "name"); - stack.push(new PkgControl(stack.peek(), name)); + final MismatchStrategy strategyOnMismatch = getStrategyForSubpackage(attributes); + final boolean regex = containsRegexAttribute(attributes); + final ImportControl parentImportControl = stack.peek(); + final ImportControl importControl = new ImportControl(parentImportControl, name, + regex, strategyOnMismatch); + parentImportControl.addChild(importControl); + stack.push(importControl); } else if (ALLOW_ELEMENT_NAME.equals(qName) || "disallow".equals(qName)) { // Need to handle either "pkg" or "class" attribute. @@ -109,28 +145,35 @@ final boolean isAllow = ALLOW_ELEMENT_NAME.equals(qName); final boolean isLocalOnly = attributes.getValue("local-only") != null; final String pkg = attributes.getValue(PKG_ATTRIBUTE_NAME); - final boolean regex = attributes.getValue("regex") != null; - final Guard guard; + final boolean regex = containsRegexAttribute(attributes); + final AbstractImportRule rule; if (pkg == null) { // handle class names which can be normal class names or regular // expressions final String clazz = safeGet(attributes, "class"); - guard = new Guard(isAllow, isLocalOnly, clazz, regex); + rule = new ClassImportRule(isAllow, isLocalOnly, clazz, regex); } else { final boolean exactMatch = attributes.getValue("exact-match") != null; - guard = new Guard(isAllow, isLocalOnly, pkg, exactMatch, regex); + rule = new PkgImportRule(isAllow, isLocalOnly, pkg, exactMatch, regex); } - - final PkgControl pkgControl = stack.peek(); - pkgControl.addGuard(guard); + stack.peek().addImportRule(rule); } } + /** + * Check if the given attributes contain the regex attribute. + * @param attributes the attributes. + * @return if the regex attribute is contained. + */ + private static boolean containsRegexAttribute(Attributes attributes) { + return attributes.getValue("regex") != null; + } + @Override - public void endElement(final String namespaceUri, final String localName, - final String qName) { + public void endElement(String namespaceUri, String localName, + String qName) { if (SUBPACKAGE_ELEMENT_NAME.equals(qName)) { stack.pop(); } @@ -139,55 +182,107 @@ /** * Loads the import control file from a file. * @param uri the uri of the file to load. - * @return the root {@link PkgControl} object. + * @return the root {@link ImportControl} object. * @throws CheckstyleException if an error occurs. */ - static PkgControl load(final URI uri) throws CheckstyleException { - final InputStream inputStream; + public static ImportControl load(URI uri) throws CheckstyleException { + InputStream inputStream = null; try { inputStream = uri.toURL().openStream(); + final InputSource source = new InputSource(inputStream); + return load(source, uri); } - catch (final MalformedURLException ex) { + catch (MalformedURLException ex) { throw new CheckstyleException("syntax error in url " + uri, ex); } - catch (final IOException ex) { + catch (IOException ex) { throw new CheckstyleException("unable to find " + uri, ex); } - final InputSource source = new InputSource(inputStream); - return load(source, uri); + finally { + closeStream(inputStream); + } } /** * Loads the import control file from a {@link InputSource}. * @param source the source to load from. * @param uri uri of the source being loaded. - * @return the root {@link PkgControl} object. + * @return the root {@link ImportControl} object. * @throws CheckstyleException if an error occurs. */ - private static PkgControl load(final InputSource source, - final URI uri) throws CheckstyleException { + private static ImportControl load(InputSource source, + URI uri) throws CheckstyleException { try { final ImportControlLoader loader = new ImportControlLoader(); loader.parseInputSource(source); return loader.getRoot(); } - catch (final ParserConfigurationException | SAXException ex) { + catch (ParserConfigurationException | SAXException ex) { throw new CheckstyleException("unable to parse " + uri + " - " + ex.getMessage(), ex); } - catch (final IOException ex) { + catch (IOException ex) { throw new CheckstyleException("unable to read " + uri, ex); } } /** - * @return the root {@link PkgControl} object loaded. + * This method exists only due to bug in cobertura library + * https://github.com/cobertura/cobertura/issues/170 + * @param inputStream the InputStream to close + * @throws CheckstyleException if an error occurs. + */ + private static void closeStream(InputStream inputStream) throws CheckstyleException { + if (inputStream != null) { + try { + inputStream.close(); + } + catch (IOException ex) { + throw new CheckstyleException("unable to close input stream", ex); + } + } + } + + /** + * Returns root ImportControl. + * @return the root {@link ImportControl} object loaded. */ - private PkgControl getRoot() { + private ImportControl getRoot() { return stack.peek(); } /** + * Utility to get a strategyOnMismatch property for "import-control" tag. + * @param attributes collect to get attribute from. + * @return the value of the attribute. + */ + private static MismatchStrategy getStrategyForImportControl(Attributes attributes) { + final String returnValue = attributes.getValue(STRATEGY_ON_MISMATCH_ATTRIBUTE_NAME); + MismatchStrategy strategyOnMismatch = MismatchStrategy.DISALLOWED; + if (STRATEGY_ON_MISMATCH_ALLOWED_VALUE.equals(returnValue)) { + strategyOnMismatch = MismatchStrategy.ALLOWED; + } + return strategyOnMismatch; + } + + /** + * Utility to get a strategyOnMismatch property for "subpackage" tag. + * @param attributes collect to get attribute from. + * @return the value of the attribute. + */ + private static MismatchStrategy getStrategyForSubpackage(Attributes attributes) { + final String returnValue = attributes.getValue(STRATEGY_ON_MISMATCH_ATTRIBUTE_NAME); + MismatchStrategy strategyOnMismatch = MismatchStrategy.DELEGATE_TO_PARENT; + if (STRATEGY_ON_MISMATCH_ALLOWED_VALUE.equals(returnValue)) { + strategyOnMismatch = MismatchStrategy.ALLOWED; + } + else if (STRATEGY_ON_MISMATCH_DISALLOWED_VALUE.equals(returnValue)) { + strategyOnMismatch = MismatchStrategy.DISALLOWED; + } + return strategyOnMismatch; + } + + /** * Utility to safely get an attribute. If it does not exist an exception * is thrown. * @param attributes collect to get attribute from. @@ -195,12 +290,15 @@ * @return the value of the attribute. * @throws SAXException if the attribute does not exist. */ - private static String safeGet(final Attributes attributes, final String name) - throws SAXException { + private static String safeGet(Attributes attributes, String name) + throws SAXException { final String returnValue = attributes.getValue(name); if (returnValue == null) { + // -@cs[IllegalInstantiation] SAXException is in the overridden method signature + // of the only method which calls the current one throw new SAXException("missing attribute " + name); } return returnValue; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderCheck.java 2018-01-28 04:16:51.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,20 +23,22 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.beanutils.ConversionException; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** + * Checks the ordering/grouping of imports. Features are: *

        *
      • groups imports: ensures that groups of imports come in a specific order * (e.g., java. comes first, javax. comes second, then everything else)
      • *
      • adds a separation between groups : ensures that a blank line sit between * each group
      • + *
      • import groups aren't separated internally: ensures that + * each group aren't separated internally by blank line or comment
      • *
      • sorts imports inside each group: ensures that imports within each group * are in lexicographic order
      • *
      • sorts according to case: ensures that the comparison between import is @@ -44,7 +46,7 @@ *
      • groups static imports: ensures that static imports are at the top (or the * bottom) of all the imports, or above (or under) each group, or are treated * like non static imports (@see {@link ImportOrderOption}
      • - *
      + *
    . * *
      * Properties:
    @@ -59,11 +61,14 @@
      *   orderedwhether imports within group should be sorted
      *       Booleantrue
      *   separatedwhether imports groups should be separated by, at least,
    - *       one blank lineBooleanfalse
    + *       one blank line or comment and aren't separated internally
    + *       Booleanfalse
      *   caseSensitivewhether string comparison should be case sensitive or not.
      *       Case sensitive sorting is in ASCII sort orderBooleantrue
      *   sortStaticImportsAlphabeticallywhether static imports grouped by top or
      *       bottom option are sorted alphabetically or notBooleanfalse
    + *   useContainerOrderingForStaticwhether to use container ordering
    + *       (Eclipse IDE term) for static imports or notBooleanfalse
      * 
      *
      * 

    @@ -76,7 +81,7 @@ *

  • groups of non-static imports: "java" then "javax" * packages first, then "org" and then all other imports
  • *
  • imports will be sorted in the groups
  • - *
  • groups are separated by, at least, one blank line
  • + *
  • groups are separated by, at least, one blank line and aren't separated internally
  • * * *
    @@ -96,7 +101,7 @@
      *     
  • groups of non-static imports: all imports except of "javax" and * "java", then "javax" and "java"
  • *
  • imports will be sorted in the groups
  • - *
  • groups are separated by, at least, one blank line
  • + *
  • groups are separated by, at least, one blank line and aren't separated internally
  • * * *

    @@ -176,9 +181,11 @@ * @author David DIDIER * @author Steve McKay * @author Aleksey Nesterenko + * @author Andrei Selkin */ +@FileStatefulCheck public class ImportOrderCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -192,6 +199,12 @@ */ public static final String MSG_ORDERING = "import.ordering"; + /** + * A key is pointing to the warning message text in "messages.properties" + * file. + */ + public static final String MSG_SEPARATED_IN_GROUP = "import.groups.separated.internally"; + /** The special wildcard that catches all remaining groups. */ private static final String WILDCARD_GROUP_NAME = "*"; @@ -219,6 +232,8 @@ private boolean beforeFirstImport; /** Whether static imports should be sorted alphabetically or not. */ private boolean sortStaticImportsAlphabetically; + /** Whether to use container ordering (Eclipse IDE term) for static imports or not. */ + private boolean useContainerOrderingForStatic; /** The policy to enforce. */ private ImportOrderOption option = ImportOrderOption.UNDER; @@ -226,14 +241,14 @@ /** * Set the option to enforce. * @param optionStr string to decode option from - * @throws ConversionException if unable to decode + * @throws IllegalArgumentException if unable to decode */ public void setOption(String optionStr) { try { option = ImportOrderOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + optionStr, iae); + throw new IllegalArgumentException("unable to parse " + optionStr, iae); } } @@ -248,7 +263,6 @@ for (int i = 0; i < packageGroups.length; i++) { String pkg = packageGroups[i]; - final StringBuilder pkgBuilder = new StringBuilder(pkg); final Pattern grp; // if the pkg name is the wildcard, make it match zero chars @@ -265,6 +279,7 @@ grp = Pattern.compile(pkg); } else { + final StringBuilder pkgBuilder = new StringBuilder(pkg); if (!CommonUtils.endsWithChar(pkg, '.')) { pkgBuilder.append('.'); } @@ -292,7 +307,7 @@ * by at least one blank line. * * @param separated - * whether groups should be separated by oen blank line. + * whether groups should be separated by one blank line. */ public void setSeparated(boolean separated) { this.separated = separated; @@ -317,6 +332,14 @@ sortStaticImportsAlphabetically = sortAlphabetically; } + /** + * Sets whether to use container ordering (Eclipse IDE term) for static imports or not. + * @param useContainerOrdering whether to use container ordering for static imports or not. + */ + public void setUseContainerOrderingForStatic(boolean useContainerOrdering) { + useContainerOrderingForStatic = useContainerOrdering; + } + @Override public int[] getDefaultTokens() { return getAcceptableTokens(); @@ -341,6 +364,7 @@ beforeFirstImport = true; } + // -@cs[CyclomaticComplexity] SWITCH was transformed into IF-ELSE. @Override public void visitToken(DetailAST ast) { final FullIdent ident; @@ -362,36 +386,37 @@ // using set of IF instead of SWITCH to analyze Enum options to satisfy coverage. // https://github.com/checkstyle/checkstyle/issues/1387 if (option == ImportOrderOption.TOP) { - if (isLastImportAndNonStatic) { lastGroup = Integer.MIN_VALUE; lastImport = ""; } doVisitToken(ident, isStatic, isStaticAndNotLastImport); + if (isStaticAndNotLastImport && !beforeFirstImport) { + log(ident.getLineNo(), MSG_ORDERING, ident.getText()); + } } else if (option == ImportOrderOption.BOTTOM) { - if (isStaticAndNotLastImport) { lastGroup = Integer.MIN_VALUE; lastImport = ""; } doVisitToken(ident, isStatic, isLastImportAndNonStatic); + if (isLastImportAndNonStatic) { + log(ident.getLineNo(), MSG_ORDERING, ident.getText()); + } } else if (option == ImportOrderOption.ABOVE) { // previous non-static but current is static doVisitToken(ident, isStatic, isStaticAndNotLastImport); - } else if (option == ImportOrderOption.UNDER) { doVisitToken(ident, isStatic, isLastImportAndNonStatic); - } else if (option == ImportOrderOption.INFLOW) { // "previous" argument is useless here doVisitToken(ident, isStatic, true); - } else { throw new IllegalStateException( @@ -417,33 +442,65 @@ final int groupIdx = getGroupNumber(name); final int line = ident.getLineNo(); - if (groupIdx == lastGroup - || !beforeFirstImport && isAlphabeticallySortableStaticImport(isStatic)) { - doVisitTokenInSameGroup(isStatic, previous, name, line); - } - else if (groupIdx > lastGroup) { - if (!beforeFirstImport && separated && line - lastImportLine < 2) { + if (groupIdx > lastGroup) { + if (!beforeFirstImport && separated && line - lastImportLine < 2 + && !isInSameGroup(groupIdx, isStatic)) { log(line, MSG_SEPARATION, name); } } + else if (isInSameGroup(groupIdx, isStatic)) { + doVisitTokenInSameGroup(isStatic, previous, name, line); + } else { log(line, MSG_ORDERING, name); } + if (isSeparatorInGroup(groupIdx, isStatic, line)) { + log(line, MSG_SEPARATED_IN_GROUP, name); + } lastGroup = groupIdx; lastImport = name; } /** - * Checks whether static imports grouped by top or bottom option - * are sorted alphabetically or not. - * @param isStatic if current import is static. - * @return true if static imports should be sorted alphabetically. - */ - private boolean isAlphabeticallySortableStaticImport(boolean isStatic) { - return isStatic && sortStaticImportsAlphabetically - && (option == ImportOrderOption.TOP - || option == ImportOrderOption.BOTTOM); + * Checks whether imports group separated internally. + * @param groupIdx group number. + * @param isStatic whether the token is static or not. + * @param line the line of the current import. + * @return true if imports group are separated internally. + */ + private boolean isSeparatorInGroup(int groupIdx, boolean isStatic, int line) { + final boolean inSameGroup = isInSameGroup(groupIdx, isStatic); + return (!separated || inSameGroup) && isSeparatorBeforeImport(line); + } + + /** + * Checks whether there is any separator before current import. + * @param line the line of the current import. + * @return true if there is separator before current import which isn't the first import. + */ + private boolean isSeparatorBeforeImport(int line) { + return !beforeFirstImport && line - lastImportLine > 1; + } + + /** + * Checks whether imports are in same group. + * @param groupIdx group number. + * @param isStatic whether the token is static or not. + * @return true if imports are in same group. + */ + private boolean isInSameGroup(int groupIdx, boolean isStatic) { + final boolean isStaticImportGroupIndependent = + option == ImportOrderOption.TOP || option == ImportOrderOption.BOTTOM; + final boolean result; + if (isStaticImportGroupIndependent) { + result = isStatic && lastImportStatic + || groupIdx == lastGroup && isStatic == lastImportStatic; + } + else { + result = groupIdx == lastGroup; + } + return result; } /** @@ -457,34 +514,123 @@ */ private void doVisitTokenInSameGroup(boolean isStatic, boolean previous, String name, int line) { - if (!ordered) { - return; + if (ordered) { + if (option == ImportOrderOption.INFLOW) { + if (isWrongOrder(name, isStatic)) { + log(line, MSG_ORDERING, name); + } + } + else { + final boolean shouldFireError = + // previous non-static but current is static (above) + // or + // previous static but current is non-static (under) + previous + || + // current and previous static or current and + // previous non-static + lastImportStatic == isStatic + && isWrongOrder(name, isStatic); + + if (shouldFireError) { + log(line, MSG_ORDERING, name); + } + } } + } - if (option == ImportOrderOption.INFLOW) { - // out of lexicographic order - if (compare(lastImport, name, caseSensitive) > 0) { - log(line, MSG_ORDERING, name); + /** + * Checks whether import name is in wrong order. + * @param name import name. + * @param isStatic whether it is a static import name. + * @return true if import name is in wrong order. + */ + private boolean isWrongOrder(String name, boolean isStatic) { + final boolean result; + if (isStatic) { + if (useContainerOrderingForStatic) { + result = compareContainerOrder(lastImport, name, caseSensitive) >= 0; + } + else if (option == ImportOrderOption.TOP + || option == ImportOrderOption.BOTTOM) { + result = sortStaticImportsAlphabetically + && compare(lastImport, name, caseSensitive) >= 0; + } + else { + result = compare(lastImport, name, caseSensitive) >= 0; } } else { - final boolean shouldFireError = - // previous non-static but current is static (above) - // or - // previous static but current is non-static (under) - previous - || - // current and previous static or current and - // previous non-static - lastImportStatic == isStatic - && - // and out of lexicographic order - compare(lastImport, name, caseSensitive) > 0; + // out of lexicographic order + result = compare(lastImport, name, caseSensitive) >= 0; + } + return result; + } - if (shouldFireError) { - log(line, MSG_ORDERING, name); - } + /** + * Compares two import strings. + * We first compare the container of the static import, container being the type enclosing + * the static element being imported. When this returns 0, we compare the qualified + * import name. For e.g. this is what is considered to be container names: + *

    + * import static HttpConstants.COLON => HttpConstants + * import static HttpHeaders.addHeader => HttpHeaders + * import static HttpHeaders.setHeader => HttpHeaders + * import static HttpHeaders.Names.DATE => HttpHeaders.Names + *

    + *

    + * According to this logic, HttpHeaders.Names would come after HttpHeaders. + * + * For more details, see + * static imports comparison method in Eclipse. + *

    + * + * @param importName1 first import name. + * @param importName2 second import name. + * @param caseSensitive whether the comparison of fully qualified import names is case + * sensitive. + * @return the value {@code 0} if str1 is equal to str2; a value + * less than {@code 0} if str is less than the str2 (container order + * or lexicographical); and a value greater than {@code 0} if str1 is greater than str2 + * (container order or lexicographically). + */ + private static int compareContainerOrder(String importName1, String importName2, + boolean caseSensitive) { + final String container1 = getImportContainer(importName1); + final String container2 = getImportContainer(importName2); + final int compareContainersOrderResult; + if (caseSensitive) { + compareContainersOrderResult = container1.compareTo(container2); + } + else { + compareContainersOrderResult = container1.compareToIgnoreCase(container2); + } + final int result; + if (compareContainersOrderResult == 0) { + result = compare(importName1, importName2, caseSensitive); } + else { + result = compareContainersOrderResult; + } + return result; + } + + /** + * Extracts import container name from fully qualified import name. + * An import container name is the type which encloses the static element being imported. + * For example, HttpConstants, HttpHeaders, HttpHeaders.Names are import container names: + *

    + * import static HttpConstants.COLON => HttpConstants + * import static HttpHeaders.addHeader => HttpHeaders + * import static HttpHeaders.setHeader => HttpHeaders + * import static HttpHeaders.Names.DATE => HttpHeaders.Names + *

    + * @param qualifiedImportName fully qualified import name. + * @return import container name. + */ + private static String getImportContainer(String qualifiedImportName) { + final int lastDotIndex = qualifiedImportName.lastIndexOf('.'); + return qualifiedImportName.substring(0, lastDotIndex); } /** @@ -495,21 +641,23 @@ */ private int getGroupNumber(String name) { int bestIndex = groups.length; - int bestLength = -1; - int bestPos = 0; + int bestEnd = -1; + int bestPos = Integer.MAX_VALUE; // find out what group this belongs in // loop over groups and get index for (int i = 0; i < groups.length; i++) { final Matcher matcher = groups[i].matcher(name); - while (matcher.find()) { - final int length = matcher.end() - matcher.start(); - if (length > bestLength - || length == bestLength && matcher.start() < bestPos) { + if (matcher.find()) { + if (matcher.start() < bestPos) { bestIndex = i; - bestLength = length; + bestEnd = matcher.end(); bestPos = matcher.start(); } + else if (matcher.start() == bestPos && matcher.end() > bestEnd) { + bestIndex = i; + bestEnd = matcher.end(); + } } } @@ -542,4 +690,5 @@ return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderOption.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderOption.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderOption.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/ImportOrderOption.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,7 @@ * @see ImportOrderCheck */ public enum ImportOrderOption { + /** * Represents the policy that static imports are all at the top. * For example: @@ -103,4 +104,5 @@ *
    */ BOTTOM + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/MismatchStrategy.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/MismatchStrategy.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/MismatchStrategy.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/MismatchStrategy.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,47 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.imports; + +/** + * Represents the strategy for checking rules inside ImportControl. + * @author Timur Tibeyev + * @see ImportControlCheck + */ +public enum MismatchStrategy { + + /** + * In a case if matching allow/disallow rule was not found, + * decision should be delegated to the parent and continue checking. + */ + DELEGATE_TO_PARENT, + + /** + * In a case if matching allow/disallow rule was not found, + * import will be allowed by default. + */ + ALLOWED, + + /** + * In a case if matching allow/disallow rule was not found, + * import will be disallowed by default. + */ + DISALLOWED + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/PkgControl.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/PkgControl.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/PkgControl.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/PkgControl.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,151 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.checks.imports; - -import java.util.Deque; -import java.util.List; - -import com.google.common.collect.Lists; - -/** - * Represents the a tree of guards for controlling whether packages are allowed - * to be used. Each instance must have a single parent or be the root node. - * Each instance may have zero or more children. - * - * @author Oliver Burn - */ -class PkgControl { - /** List of {@link Guard} objects to check. */ - private final Deque guards = Lists.newLinkedList(); - /** List of children {@link PkgControl} objects. */ - private final List children = Lists.newArrayList(); - /** The parent. Null indicates we are the root node. */ - private final PkgControl parent; - /** The full package name for the node. */ - private final String fullPackage; - - /** - * Construct a root node. - * @param pkgName the name of the package. - */ - PkgControl(final String pkgName) { - parent = null; - fullPackage = pkgName; - } - - /** - * Construct a child node. - * @param parent the parent node. - * @param subPkg the sub package name. - */ - PkgControl(final PkgControl parent, final String subPkg) { - this.parent = parent; - fullPackage = parent.fullPackage + "." + subPkg; - parent.children.add(this); - } - - /** - * Adds a guard to the node. - * @param thug the guard to be added. - */ - void addGuard(final Guard thug) { - guards.addFirst(thug); - } - - /** - * @return the full package name represented by the node. - */ - String getFullPackage() { - return fullPackage; - } - - /** - * Search down the tree to locate the finest match for a supplied package. - * @param forPkg the package to search for. - * @return the finest match, or null if no match at all. - */ - PkgControl locateFinest(final String forPkg) { - PkgControl finestMatch = null; - // Check if we are a match. - // This algorithm should be improved to check for a trailing "." - // or nothing following. - if (forPkg.startsWith(fullPackage)) { - // If there won't be match so I am the best there is. - finestMatch = this; - // Check if any of the children match. - for (PkgControl child : children) { - final PkgControl match = child.locateFinest(forPkg); - if (match != null) { - finestMatch = match; - break; - } - } - } - return finestMatch; - } - - /** - * Returns whether a package is allowed to be used. The algorithm checks - * with the current node for a result, and if none is found then calls - * its parent looking for a match. This will recurse looking for match. - * If there is no clear result then {@link AccessResult#UNKNOWN} is - * returned. - * @param forImport the package to check on. - * @param inPkg the package doing the import. - * @return an {@link AccessResult}. - */ - AccessResult checkAccess(final String forImport, final String inPkg) { - final AccessResult result; - final AccessResult returnValue = localCheckAccess(forImport, inPkg); - if (returnValue != AccessResult.UNKNOWN) { - result = returnValue; - } - else if (parent == null) { - // we are the top, so default to not allowed. - result = AccessResult.DISALLOWED; - } - else { - result = parent.checkAccess(forImport, inPkg); - } - return result; - } - - /** - * Checks whether any of the guards for this node control access to - * a specified package. - * @param forImport the package to check. - * @param inPkg the package doing the import. - * @return an {@link AccessResult}. - */ - private AccessResult localCheckAccess(final String forImport, - final String inPkg) { - for (Guard g : guards) { - // Check if a Guard is only meant to be applied locally. - if (g.isLocalOnly() && !fullPackage.equals(inPkg)) { - continue; - } - final AccessResult result = g.verifyImport(forImport); - if (result != AccessResult.UNKNOWN) { - return result; - } - } - return AccessResult.UNKNOWN; - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/PkgImportRule.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/PkgImportRule.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/PkgImportRule.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/PkgImportRule.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,83 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.imports; + +/** + * Represents whether a package is allowed to be imported or not. + * @author Oliver Burn + */ +class PkgImportRule extends AbstractImportRule { + + /** Package to control access to. */ + private final String pkgName; + + /** Indicates if the package name must be an exact match. */ + private final boolean exactMatch; + + /** + * Constructs an instance. + * @param allow whether to allow access. + * @param localOnly whether the rule is to be applied locally only + * @param pkgName the package to apply the rule on. + * @param exactMatch whether the package name must match exactly. + * @param regExp whether the package name is to be interpreted as a regular + * expression. + */ + PkgImportRule(final boolean allow, final boolean localOnly, + final String pkgName, final boolean exactMatch, final boolean regExp) { + super(allow, localOnly, regExp); + this.pkgName = pkgName; + this.exactMatch = exactMatch; + } + + /** + * Verifies whether a package name is used. + * @param forImport the import to check. + * @return a result {@link AccessResult} indicating whether it can be used. + */ + @Override + public AccessResult verifyImport(final String forImport) { + // First check that we actually match the package. + // Then check if matched and f we must be an exact match. + // In this case, the text after the first "." must not contain + // another "." as this indicates that it is not an exact match. + + boolean pkgMatch; + + if (isRegExp()) { + pkgMatch = forImport.matches(pkgName + "\\..*"); + + if (pkgMatch && exactMatch) { + pkgMatch = !forImport.matches(pkgName + "\\..*\\..*"); + } + } + else { + pkgMatch = forImport.startsWith(pkgName + "."); + + if (pkgMatch && exactMatch) { + pkgMatch = forImport.indexOf('.', + pkgName.length() + 1) == -1; + } + } + + return calculateResult(pkgMatch); + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/RedundantImportCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/RedundantImportCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/RedundantImportCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/RedundantImportCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,10 +19,11 @@ package com.puppycrawl.tools.checkstyle.checks.imports; +import java.util.HashSet; import java.util.Set; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -50,8 +51,9 @@ * * @author Oliver Burn */ +@FileStatefulCheck public class RedundantImportCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -72,9 +74,9 @@ public static final String MSG_DUPLICATE = "import.duplicate"; /** Set of the imports. */ - private final Set imports = Sets.newHashSet(); + private final Set imports = new HashSet<>(); /** Set of static imports. */ - private final Set staticImports = Sets.newHashSet(); + private final Set staticImports = new HashSet<>(); /** Name of package in file. */ private String pkgName; @@ -88,20 +90,19 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] - {TokenTypes.IMPORT, - TokenTypes.STATIC_IMPORT, - TokenTypes.PACKAGE_DEF, }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] { + TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT, TokenTypes.PACKAGE_DEF, + }; } @Override @@ -123,13 +124,10 @@ imp.getText()); } // Check for a duplicate import - for (FullIdent full : imports) { - if (imp.getText().equals(full.getText())) { - log(ast.getLineNo(), ast.getColumnNo(), - MSG_DUPLICATE, full.getLineNo(), - imp.getText()); - } - } + imports.stream().filter(full -> imp.getText().equals(full.getText())) + .forEach(full -> log(ast.getLineNo(), ast.getColumnNo(), + MSG_DUPLICATE, full.getLineNo(), + imp.getText())); imports.add(imp); } @@ -138,12 +136,9 @@ final FullIdent imp = FullIdent.createFullIdent( ast.getLastChild().getPreviousSibling()); - for (FullIdent full : staticImports) { - if (imp.getText().equals(full.getText())) { - log(ast.getLineNo(), ast.getColumnNo(), - MSG_DUPLICATE, full.getLineNo(), imp.getText()); - } - } + staticImports.stream().filter(full -> imp.getText().equals(full.getText())) + .forEach(full -> log(ast.getLineNo(), ast.getColumnNo(), + MSG_DUPLICATE, full.getLineNo(), imp.getText())); staticImports.add(imp); } @@ -157,10 +152,11 @@ */ private static boolean isFromPackage(String importName, String pkg) { // imports from unnamed package are not allowed: - // http://docs.oracle.com/javase/specs/jls/se7/html/jls-7.html#jls-7.5 + // https://docs.oracle.com/javase/specs/jls/se7/html/jls-7.html#jls-7.5 // So '.' must be present in member name and we are not checking for it final int index = importName.lastIndexOf('.'); final String front = importName.substring(0, index); return front.equals(pkg); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/imports/UnusedImportsCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,14 +19,15 @@ package com.puppycrawl.tools.checkstyle.checks.imports; +import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.FullIdent; @@ -50,7 +51,8 @@ * * @author Oliver Burn */ -public class UnusedImportsCheck extends Check { +@FileStatefulCheck +public class UnusedImportsCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -59,23 +61,27 @@ public static final String MSG_KEY = "import.unused"; /** Regex to match class names. */ - private static final Pattern CLASS_NAME = Pattern.compile( + private static final Pattern CLASS_NAME = CommonUtils.createPattern( "((:?[\\p{L}_$][\\p{L}\\p{N}_$]*\\.)*[\\p{L}_$][\\p{L}\\p{N}_$]*)"); /** Regex to match the first class name. */ - private static final Pattern FIRST_CLASS_NAME = Pattern.compile( + private static final Pattern FIRST_CLASS_NAME = CommonUtils.createPattern( "^" + CLASS_NAME); /** Regex to match argument names. */ - private static final Pattern ARGUMENT_NAME = Pattern.compile( + private static final Pattern ARGUMENT_NAME = CommonUtils.createPattern( "[(,]\\s*" + CLASS_NAME.pattern()); + /** Regexp pattern to match java.lang package. */ + private static final Pattern JAVA_LANG_PACKAGE_PATTERN = + CommonUtils.createPattern("^java\\.lang\\.[a-zA-Z]+$"); + /** Suffix for the star import. */ private static final String STAR_IMPORT_SUFFIX = ".*"; /** Set of the imports. */ - private final Set imports = Sets.newHashSet(); + private final Set imports = new HashSet<>(); /** Set of references - possibly to imports or other things. */ - private final Set referenced = Sets.newHashSet(); + private final Set referenced = new HashSet<>(); /** Flag to indicate when time to start collecting references. */ private boolean collect; @@ -101,42 +107,20 @@ @Override public void finishTree(DetailAST rootAST) { // loop over all the imports to see if referenced. - for (final FullIdent imp : imports) { - if (!referenced.contains(CommonUtils.baseClassName(imp.getText()))) { - log(imp.getLineNo(), - imp.getColumnNo(), - MSG_KEY, imp.getText()); - } - } + imports.stream() + .filter(imprt -> isUnusedImport(imprt.getText())) + .forEach(imprt -> log(imprt.getLineNo(), + imprt.getColumnNo(), + MSG_KEY, imprt.getText())); } @Override public int[] getDefaultTokens() { - return new int[] { - TokenTypes.IDENT, - TokenTypes.IMPORT, - TokenTypes.STATIC_IMPORT, - // Definitions that may contain Javadoc... - TokenTypes.PACKAGE_DEF, - TokenTypes.ANNOTATION_DEF, - TokenTypes.ANNOTATION_FIELD_DEF, - TokenTypes.ENUM_DEF, - TokenTypes.ENUM_CONSTANT_DEF, - TokenTypes.CLASS_DEF, - TokenTypes.INTERFACE_DEF, - TokenTypes.METHOD_DEF, - TokenTypes.CTOR_DEF, - TokenTypes.VARIABLE_DEF, - }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getDefaultTokens(); - } - - @Override - public int[] getAcceptableTokens() { return new int[] { TokenTypes.IDENT, TokenTypes.IMPORT, @@ -156,6 +140,11 @@ } @Override + public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override public void visitToken(DetailAST ast) { if (ast.getType() == TokenTypes.IDENT) { if (collect) { @@ -177,6 +166,17 @@ } /** + * Checks whether an import is unused. + * @param imprt an import. + * @return true if an import is unused. + */ + private boolean isUnusedImport(String imprt) { + final Matcher javaLangPackageMatcher = JAVA_LANG_PACKAGE_PATTERN.matcher(imprt); + return !referenced.contains(CommonUtils.baseClassName(imprt)) + || javaLangPackageMatcher.matches(); + } + + /** * Collects references made by IDENT. * @param ast the IDENT node to process */ @@ -235,23 +235,18 @@ * @return a set of classes referenced in the javadoc block */ private static Set collectReferencesFromJavadoc(TextBlock textBlock) { - final Set references = new HashSet<>(); - // process all the @link type tags + final List tags = new ArrayList<>(); + // gather all the inline tags, like @link // INLINE tags inside BLOCKs get hidden when using ALL - for (final JavadocTag tag - : getValidTags(textBlock, JavadocUtils.JavadocTagType.INLINE)) { - if (tag.canReferenceImports()) { - references.addAll(processJavadocTag(tag)); - } - } - // process all the @throws type tags - for (final JavadocTag tag - : getValidTags(textBlock, JavadocUtils.JavadocTagType.BLOCK)) { - if (tag.canReferenceImports()) { - references.addAll( - matchPattern(tag.getFirstArg(), FIRST_CLASS_NAME)); - } - } + tags.addAll(getValidTags(textBlock, JavadocUtils.JavadocTagType.INLINE)); + // gather all the block-level tags, like @throws and @see + tags.addAll(getValidTags(textBlock, JavadocUtils.JavadocTagType.BLOCK)); + + final Set references = new HashSet<>(); + + tags.stream() + .filter(JavadocTag::canReferenceImports) + .forEach(tag -> references.addAll(processJavadocTag(tag))); return references; } @@ -292,8 +287,28 @@ final Set references = new HashSet<>(); final Matcher matcher = pattern.matcher(identifier); while (matcher.find()) { - references.add(matcher.group(1)); + references.add(topLevelType(matcher.group(1))); } return references; } + + /** + * If the given type string contains "." (e.g. "Map.Entry"), returns the + * top level type (e.g. "Map"), as that is what must be imported for the + * type to resolve. Otherwise, returns the type as-is. + * @param type A possibly qualified type name + * @return The simple name of the top level type + */ + private static String topLevelType(String type) { + final String topLevelType; + final int dotIndex = type.indexOf('.'); + if (dotIndex == -1) { + topLevelType = type; + } + else { + topLevelType = type.substring(0, dotIndex); + } + return topLevelType; + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/AbstractExpressionHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/AbstractExpressionHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/AbstractExpressionHandler.java 2016-01-30 23:19:29.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/AbstractExpressionHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -31,6 +31,7 @@ * @author jrichard */ public abstract class AbstractExpressionHandler { + /** * The instance of {@code IndentationCheck} using this handler. */ @@ -77,6 +78,7 @@ * value is returned. * * @return the expected indentation amount + * @noinspection WeakerAccess */ public final IndentLevel getIndent() { if (indent == null) { @@ -102,6 +104,7 @@ * type) * * @return suggested indentation for child + * @noinspection WeakerAccess */ public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) { return new IndentLevel(getIndent(), getBasicOffset()); @@ -181,8 +184,9 @@ * @param ast2 the second expression * * @return true if they are, false otherwise + * @noinspection WeakerAccess */ - static boolean areOnSameLine(DetailAST ast1, DetailAST ast2) { + public static boolean areOnSameLine(DetailAST ast1, DetailAST ast2) { return ast1.getLineNo() == ast2.getLineNo(); } @@ -191,8 +195,9 @@ * which represents first symbol for this sub-tree in file. * @param ast a root of sub-tree in which the search should be performed. * @return a token which occurs first in the file. + * @noinspection WeakerAccess */ - static DetailAST getFirstToken(DetailAST ast) { + public static DetailAST getFirstToken(DetailAST ast) { DetailAST first = ast; DetailAST child = ast.getFirstChild(); @@ -215,8 +220,18 @@ * @return the start of the line for the given expression */ protected final int getLineStart(DetailAST ast) { - final String line = indentCheck.getLine(ast.getLineNo() - 1); - return getLineStart(line); + return getLineStart(ast.getLineNo()); + } + + /** + * Get the start of the line for the given line number. + * + * @param lineNo the line number to find the start for + * + * @return the start of the line for the given expression + */ + protected final int getLineStart(int lineNo) { + return getLineStart(indentCheck.getLine(lineNo - 1)); } /** @@ -226,9 +241,9 @@ * * @return the start of the specified line */ - protected final int getLineStart(String line) { + private int getLineStart(String line) { int index = 0; - while (index < line.length() && Character.isWhitespace(line.charAt(index))) { + while (Character.isWhitespace(line.charAt(index))) { index++; } return CommonUtils.lengthExpandedTabs( @@ -246,27 +261,6 @@ } /** - * Check the indentation of consecutive lines for the expression we are - * handling. - * - * @param startLine the first line to check - * @param endLine the last line to check - * @param indentLevel the required indent level - */ - protected final void checkLinesIndent(int startLine, int endLine, - IndentLevel indentLevel) { - // check first line - checkLineIndent(startLine, indentLevel); - - // check following lines - final IndentLevel offsetLevel = - new IndentLevel(indentLevel, getBasicOffset()); - for (int i = startLine + 1; i <= endLine; i++) { - checkLineIndent(i, offsetLevel); - } - } - - /** * Check the indentation for a set of lines. * * @param lines the set of lines to check @@ -278,60 +272,42 @@ IndentLevel indentLevel, boolean firstLineMatches, int firstLine) { - if (lines.isEmpty()) { - return; - } - - // check first line - final int startLine = lines.firstLine(); - final int endLine = lines.lastLine(); - final int startCol = lines.firstLineCol(); - - final int realStartCol = - getLineStart(indentCheck.getLine(startLine - 1)); - - if (realStartCol == startCol) { - checkLineIndent(startLine, startCol, indentLevel, - firstLineMatches); - } - - // if first line starts the line, following lines are indented - // one level; but if the first line of this expression is - // nested with the previous expression (which is assumed if it - // doesn't start the line) then don't indent more, the first - // indentation is absorbed by the nesting - - IndentLevel theLevel = indentLevel; - if (firstLineMatches - || firstLine > mainAst.getLineNo() && shouldIncreaseIndent()) { - theLevel = new IndentLevel(indentLevel, getBasicOffset()); - } - - // check following lines - for (int i = startLine + 1; i <= endLine; i++) { - final Integer col = lines.getStartColumn(i); - // startCol could be null if this line didn't have an - // expression that was required to be checked (it could be - // checked by a child expression) + if (!lines.isEmpty()) { + // check first line + final int startLine = lines.firstLine(); + final int endLine = lines.lastLine(); + final int startCol = lines.firstLineCol(); + + final int realStartCol = + getLineStart(indentCheck.getLine(startLine - 1)); + + if (realStartCol == startCol) { + checkLineIndent(startLine, startCol, indentLevel, + firstLineMatches); + } - if (col != null) { - checkLineIndent(i, col, theLevel, false); + // if first line starts the line, following lines are indented + // one level; but if the first line of this expression is + // nested with the previous expression (which is assumed if it + // doesn't start the line) then don't indent more, the first + // indentation is absorbed by the nesting + + IndentLevel theLevel = indentLevel; + if (firstLineMatches + || firstLine > mainAst.getLineNo() && shouldIncreaseIndent()) { + theLevel = new IndentLevel(indentLevel, getBasicOffset()); } - } - } - /** - * Check the indent level for a single line. - * - * @param lineNum the line number to check - * @param indentLevel the required indent level - */ - private void checkLineIndent(int lineNum, IndentLevel indentLevel) { - final String line = indentCheck.getLine(lineNum - 1); - if (!line.isEmpty()) { - final int start = getLineStart(line); - if (indentLevel.isGreaterThan(start)) { - logChildError(lineNum, start, indentLevel); + // check following lines + for (int i = startLine + 1; i <= endLine; i++) { + final Integer col = lines.getStartColumn(i); + // startCol could be null if this line didn't have an + // expression that was required to be checked (it could be + // checked by a child expression) + + if (col != null) { + checkLineIndent(i, col, theLevel, false); + } } } } @@ -344,7 +320,6 @@ * @param indentLevel the indentation level * @param mustMatch whether or not the indentation level must match */ - private void checkLineIndent(int lineNum, int colNum, IndentLevel indentLevel, boolean mustMatch) { final String line = indentCheck.getLine(lineNum - 1); @@ -360,6 +335,34 @@ } /** + * Checks indentation on wrapped lines between and including + * {@code firstNode} and {@code lastNode}. + * + * @param firstNode First node to start examining. + * @param lastNode Last node to examine inclusively. + */ + protected void checkWrappingIndentation(DetailAST firstNode, DetailAST lastNode) { + indentCheck.getLineWrappingHandler().checkIndentation(firstNode, lastNode); + } + + /** + * Checks indentation on wrapped lines between and including + * {@code firstNode} and {@code lastNode}. + * + * @param firstNode First node to start examining. + * @param lastNode Last node to examine inclusively. + * @param wrappedIndentLevel Indentation all wrapped lines should use. + * @param startIndent Indentation first line before wrapped lines used. + * @param ignoreFirstLine Test if first line's indentation should be checked or not. + */ + protected void checkWrappingIndentation(DetailAST firstNode, DetailAST lastNode, + int wrappedIndentLevel, int startIndent, boolean ignoreFirstLine) { + indentCheck.getLineWrappingHandler().checkIndentation(firstNode, lastNode, + wrappedIndentLevel, startIndent, + LineWrappingHandler.LineWrappingOptions.ofBoolean(ignoreFirstLine)); + } + + /** * Check the indent level of the children of the specified parent * expression. * @@ -418,7 +421,7 @@ * * @return the first line of the expression */ - protected final int getFirstLine(int startLine, DetailAST tree) { + protected static int getFirstLine(int startLine, DetailAST tree) { int realStart = startLine; final int currLine = tree.getLineNo(); if (currLine < realStart) { @@ -460,23 +463,21 @@ */ protected final void findSubtreeLines(LineSet lines, DetailAST tree, boolean allowNesting) { - if (indentCheck.getHandlerFactory().isHandledType(tree.getType())) { - return; - } - - final int lineNum = tree.getLineNo(); - final Integer colNum = lines.getStartColumn(lineNum); - - final int thisLineColumn = expandedTabsColumnNo(tree); - if (colNum == null || thisLineColumn < colNum) { - lines.addLineAndCol(lineNum, thisLineColumn); - } + if (!indentCheck.getHandlerFactory().isHandledType(tree.getType())) { + final int lineNum = tree.getLineNo(); + final Integer colNum = lines.getStartColumn(lineNum); + + final int thisLineColumn = expandedTabsColumnNo(tree); + if (colNum == null || thisLineColumn < colNum) { + lines.addLineAndCol(lineNum, thisLineColumn); + } - // check children - for (DetailAST node = tree.getFirstChild(); - node != null; - node = node.getNextSibling()) { - findSubtreeLines(lines, node, allowNesting); + // check children + for (DetailAST node = tree.getFirstChild(); + node != null; + node = node.getNextSibling()) { + findSubtreeLines(lines, node, allowNesting); + } } } @@ -546,7 +547,7 @@ * @param rparen parenthesis to check * @param lparen left parenthesis associated with aRparen */ - protected final void checkRParen(DetailAST lparen, DetailAST rparen) { + protected final void checkRightParen(DetailAST lparen, DetailAST rparen) { if (rparen != null) { // the rcurly can either be at the correct indentation, // or not first on the line @@ -566,14 +567,14 @@ * Check the indentation of the left parenthesis. * @param lparen parenthesis to check */ - protected final void checkLParen(final DetailAST lparen) { + protected final void checkLeftParen(final DetailAST lparen) { // the rcurly can either be at the correct indentation, or on the // same line as the lcurly - if (lparen == null - || getIndent().isAcceptable(expandedTabsColumnNo(lparen)) - || !isOnStartOfLine(lparen)) { - return; + if (lparen != null + && !getIndent().isAcceptable(expandedTabsColumnNo(lparen)) + && isOnStartOfLine(lparen)) { + logError(lparen, "lparen", expandedTabsColumnNo(lparen)); } - logError(lparen, "lparen", expandedTabsColumnNo(lparen)); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ArrayInitHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ArrayInitHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ArrayInitHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ArrayInitHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class ArrayInitHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -45,14 +46,16 @@ protected IndentLevel getIndentImpl() { final DetailAST parentAST = getMainAst().getParent(); final int type = parentAST.getType(); + final IndentLevel indentLevel; if (type == TokenTypes.LITERAL_NEW || type == TokenTypes.ASSIGN) { // note: assumes new or assignment is line to align with - return new IndentLevel(getLineStart(parentAST)); + indentLevel = new IndentLevel(getLineStart(parentAST)); } else { // at this point getParent() is instance of BlockParentHandler - return ((BlockParentHandler) getParent()).getChildrenExpectedIndent(); + indentLevel = ((BlockParentHandler) getParent()).getChildrenExpectedIndent(); } + return indentLevel; } @Override @@ -61,7 +64,7 @@ } @Override - protected DetailAST getLCurly() { + protected DetailAST getLeftCurly() { return getMainAst(); } @@ -73,16 +76,11 @@ } @Override - protected DetailAST getRCurly() { + protected DetailAST getRightCurly() { return getMainAst().findFirstToken(TokenTypes.RCURLY); } @Override - protected boolean shouldStartWithRCurly() { - return false; - } - - @Override protected boolean canChildrenBeNested() { return true; } @@ -99,7 +97,7 @@ getIndentCheck().getLineWrappingIndentation()); final int firstLine = getFirstLine(Integer.MAX_VALUE, getListChild()); - final int lcurlyPos = expandedTabsColumnNo(getLCurly()); + final int lcurlyPos = expandedTabsColumnNo(getLeftCurly()); final int firstChildPos = getNextFirstNonBlankOnLineAfter(firstLine, lcurlyPos); if (firstChildPos >= 0) { @@ -110,6 +108,10 @@ } /** + * Returns column number of first non-blank char after + * specified column on specified line or -1 if + * such char doesn't exist. + * * @param lineNo number of line on which we search * @param columnNo number of column after which we search * @@ -127,11 +129,9 @@ } if (realColumnNo == lineLength) { - return -1; - } - else { - return realColumnNo; + realColumnNo = -1; } + return realColumnNo; } /** @@ -142,4 +142,5 @@ private int getLineWrappingIndentation() { return getIndentCheck().getLineWrappingIndentation(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/BlockParentHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/BlockParentHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/BlockParentHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/BlockParentHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -42,6 +42,7 @@ * @author jrichard */ public class BlockParentHandler extends AbstractExpressionHandler { + /** * Children checked by parent handlers. */ @@ -63,6 +64,7 @@ * @param name the name of the handler * @param ast the abstract syntax tree * @param parent the parent handler + * @noinspection WeakerAccess */ public BlockParentHandler(IndentationCheck indentCheck, String name, DetailAST ast, AbstractExpressionHandler parent) { @@ -92,21 +94,19 @@ protected void checkTopLevelToken() { final DetailAST topLevel = getTopLevelAst(); - if (topLevel == null - || getIndent().isAcceptable(expandedTabsColumnNo(topLevel)) || hasLabelBefore()) { - return; - } - if (!shouldTopLevelStartLine() && !isOnStartOfLine(topLevel)) { - return; + if (topLevel != null + && !getIndent().isAcceptable(expandedTabsColumnNo(topLevel)) + && !hasLabelBefore() + && (shouldTopLevelStartLine() || isOnStartOfLine(topLevel))) { + logError(topLevel, "", expandedTabsColumnNo(topLevel)); } - logError(topLevel, "", expandedTabsColumnNo(topLevel)); } /** * Check if the top level token has label before. * @return true if the top level token has label before. */ - protected boolean hasLabelBefore() { + private boolean hasLabelBefore() { final DetailAST parent = getTopLevelAst().getParent(); return parent.getType() == TokenTypes.LABELED_STAT && parent.getLineNo() == getTopLevelAst().getLineNo(); @@ -126,8 +126,8 @@ * * @return true if curly braces are present, false otherwise */ - protected boolean hasCurlies() { - return getLCurly() != null && getRCurly() != null; + private boolean hasCurlies() { + return getLeftCurly() != null && getRightCurly() != null; } /** @@ -135,7 +135,7 @@ * * @return the left curly brace expression */ - protected DetailAST getLCurly() { + protected DetailAST getLeftCurly() { return getMainAst().findFirstToken(TokenTypes.SLIST); } @@ -144,7 +144,7 @@ * * @return the right curly brace expression */ - protected DetailAST getRCurly() { + protected DetailAST getRightCurly() { final DetailAST slist = getMainAst().findFirstToken(TokenTypes.SLIST); return slist.findFirstToken(TokenTypes.RCURLY); } @@ -152,17 +152,15 @@ /** * Check the indentation of the left curly brace. */ - protected void checkLCurly() { + private void checkLeftCurly() { // the lcurly can either be at the correct indentation, or nested // with a previous expression - final DetailAST lcurly = getLCurly(); + final DetailAST lcurly = getLeftCurly(); final int lcurlyPos = expandedTabsColumnNo(lcurly); - if (curlyIndent().isAcceptable(lcurlyPos) || !isOnStartOfLine(lcurly)) { - return; + if (!curlyIndent().isAcceptable(lcurlyPos) && isOnStartOfLine(lcurly)) { + logError(lcurly, "lcurly", lcurlyPos, curlyIndent()); } - - logError(lcurly, "lcurly", lcurlyPos); } /** @@ -175,15 +173,6 @@ } /** - * Determines if the right curly brace must be at the start of the line. - * - * @return true - */ - protected boolean shouldStartWithRCurly() { - return true; - } - - /** * Determines if child elements within the expression may be nested. * * @return false @@ -195,19 +184,14 @@ /** * Check the indentation of the right curly brace. */ - protected void checkRCurly() { - // the rcurly can either be at the correct indentation, or - // on the same line as the lcurly - final DetailAST lcurly = getLCurly(); - final DetailAST rcurly = getRCurly(); + private void checkRightCurly() { + final DetailAST rcurly = getRightCurly(); final int rcurlyPos = expandedTabsColumnNo(rcurly); - if (curlyIndent().isAcceptable(rcurlyPos) - || !shouldStartWithRCurly() && !isOnStartOfLine(rcurly) - || areOnSameLine(rcurly, lcurly)) { - return; + if (!curlyIndent().isAcceptable(rcurlyPos) + && isOnStartOfLine(rcurly)) { + logError(rcurly, "rcurly", rcurlyPos, curlyIndent()); } - logError(rcurly, "rcurly", rcurlyPos, curlyIndent()); } /** @@ -224,12 +208,10 @@ */ private void checkNonListChild() { final DetailAST nonList = getNonListChild(); - if (nonList == null) { - return; + if (nonList != null) { + final IndentLevel expected = new IndentLevel(getIndent(), getBasicOffset()); + checkExpressionSubtree(nonList, expected, false, false); } - - final IndentLevel expected = new IndentLevel(getIndent(), getBasicOffset()); - checkExpressionSubtree(nonList, expected, false, false); } /** @@ -246,7 +228,7 @@ * * @return the right parenthesis expression */ - protected DetailAST getRParen() { + private DetailAST getRightParen() { return getMainAst().findFirstToken(TokenTypes.RPAREN); } @@ -255,7 +237,7 @@ * * @return the left parenthesis expression */ - protected DetailAST getLParen() { + private DetailAST getLeftParen() { return getMainAst().findFirstToken(TokenTypes.LPAREN); } @@ -263,11 +245,11 @@ public void checkIndentation() { checkTopLevelToken(); // separate to allow for eventual configuration - checkLParen(getLParen()); - checkRParen(getLParen(), getRParen()); + checkLeftParen(getLeftParen()); + checkRightParen(getLeftParen(), getRightParen()); if (hasCurlies()) { - checkLCurly(); - checkRCurly(); + checkLeftCurly(); + checkRightCurly(); } final DetailAST listChild = getListChild(); if (listChild == null) { @@ -275,7 +257,7 @@ } else { // NOTE: switch statements usually don't have curlies - if (!hasCurlies() || !areOnSameLine(getLCurly(), getRCurly())) { + if (!hasCurlies() || !areOnSameLine(getLeftCurly(), getRightCurly())) { checkChildren(listChild, getCheckedChildren(), getChildrenExpectedIndent(), @@ -295,10 +277,11 @@ // try to suggest single level to children using curlies' // levels. if (getIndent().isMultiLevel() && hasCurlies()) { - if (isOnStartOfLine(getLCurly())) { - indentLevel = new IndentLevel(expandedTabsColumnNo(getLCurly()) + getBasicOffset()); + if (isOnStartOfLine(getLeftCurly())) { + indentLevel = new IndentLevel(expandedTabsColumnNo(getLeftCurly()) + + getBasicOffset()); } - else if (isOnStartOfLine(getRCurly())) { + else if (isOnStartOfLine(getRightCurly())) { final IndentLevel level = new IndentLevel(curlyIndent(), getBasicOffset()); level.addAcceptedIndent(level.getFirstIndentLevel() + getLineWrappingIndent()); indentLevel = level; @@ -320,4 +303,5 @@ private int getLineWrappingIndent() { return getIndentCheck().getLineWrappingIndentation(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CaseHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CaseHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CaseHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CaseHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class CaseHandler extends AbstractExpressionHandler { + /** * The child elements of a case expression. */ @@ -71,4 +72,5 @@ public void checkIndentation() { checkCase(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CatchHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CatchHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CatchHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CatchHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class CatchHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -52,7 +53,7 @@ private void checkCondExpr() { final DetailAST condAst = getMainAst().findFirstToken(TokenTypes.LPAREN) .getNextSibling(); - checkExpressionSubtree(condAst, getIndent(), false, false); + checkExpressionSubtree(condAst, getIndent(), true, false); } @Override @@ -60,4 +61,5 @@ super.checkIndentation(); checkCondExpr(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ClassDefHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ClassDefHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ClassDefHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ClassDefHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class ClassDefHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -43,13 +44,13 @@ } @Override - protected DetailAST getLCurly() { + protected DetailAST getLeftCurly() { return getMainAst().findFirstToken(TokenTypes.OBJBLOCK) .findFirstToken(TokenTypes.LCURLY); } @Override - protected DetailAST getRCurly() { + protected DetailAST getRightCurly() { return getMainAst().findFirstToken(TokenTypes.OBJBLOCK) .findFirstToken(TokenTypes.RCURLY); } @@ -69,20 +70,27 @@ public void checkIndentation() { final DetailAST modifiers = getMainAst().findFirstToken(TokenTypes.MODIFIERS); if (modifiers.getChildCount() == 0) { - final DetailAST ident = getMainAst().findFirstToken(TokenTypes.IDENT); - final int lineStart = getLineStart(ident); - if (!getIndent().isAcceptable(lineStart)) { - logError(ident, "ident", lineStart); + if (getMainAst().getType() != TokenTypes.ANNOTATION_DEF) { + final DetailAST ident = getMainAst().findFirstToken(TokenTypes.IDENT); + final int lineStart = getLineStart(ident); + if (!getIndent().isAcceptable(lineStart)) { + logError(ident, "ident", lineStart); + } } - } else { checkModifiers(); } - - final LineWrappingHandler lineWrap = - new LineWrappingHandler(getIndentCheck(), getMainAst(), getMainAst().getLastChild()); - lineWrap.checkIndentation(); + if (getMainAst().getType() == TokenTypes.ANNOTATION_DEF) { + final DetailAST atAst = getMainAst().findFirstToken(TokenTypes.AT); + if (isOnStartOfLine(atAst)) { + checkWrappingIndentation(getMainAst(), getListChild(), 0, + getIndent().getFirstIndentLevel(), false); + } + } + else { + checkWrappingIndentation(getMainAst(), getListChild()); + } super.checkIndentation(); } @@ -113,9 +121,13 @@ else if (ast.getType() == TokenTypes.ENUM_DEF) { name = "enum def"; } + else if (ast.getType() == TokenTypes.ANNOTATION_DEF) { + name = "annotation def"; + } else { name = "interface def"; } return name; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CommentsIndentationCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CommentsIndentationCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CommentsIndentationCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/CommentsIndentationCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,12 +19,12 @@ package com.puppycrawl.tools.checkstyle.checks.indentation; +import java.util.ArrayDeque; +import java.util.Deque; import java.util.Locale; -import java.util.Stack; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -34,7 +34,7 @@ * Comments are indented at the same level as the surrounding code. * Detailed info about such convention can be found * + * "http://checkstyle.sourceforge.net/reports/google-java-style-20170228.html#s4.8.6.1-block-comment-style"> * here *

    * Examples: @@ -68,7 +68,8 @@ * @author Aleksey Nesterenko * @author Andrei Selkin */ -public class CommentsIndentationCheck extends Check { +@StatelessCheck +public class CommentsIndentationCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" file. @@ -98,7 +99,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -110,10 +111,8 @@ public void visitToken(DetailAST commentAst) { switch (commentAst.getType()) { case TokenTypes.SINGLE_LINE_COMMENT: - visitSingleLineComment(commentAst); - break; case TokenTypes.BLOCK_COMMENT_BEGIN: - visitBlockComment(commentAst); + visitComment(commentAst); break; default: final String exceptionMsg = "Unexpected token type: " + commentAst.getText(); @@ -122,7 +121,7 @@ } /** - * Checks single line comment indentations over surrounding code, e.g.: + * Checks comment indentations over surrounding code, e.g.: *

    * {@code * // some comment - this is ok @@ -131,151 +130,196 @@ * double d1 = 5.0; * } *

    - * @param singleLineComment {@link TokenTypes#SINGLE_LINE_COMMENT single line comment}. + * @param comment comment to check. */ - private void visitSingleLineComment(DetailAST singleLineComment) { - final DetailAST prevStmt = getPreviousStatementOfSingleLineComment(singleLineComment); - final DetailAST nextStmt = singleLineComment.getNextSibling(); + private void visitComment(DetailAST comment) { + if (!isTrailingComment(comment)) { + final DetailAST prevStmt = getPreviousStatement(comment); + final DetailAST nextStmt = getNextStmt(comment); - if (!isTrailingSingleLineComment(singleLineComment)) { if (isInEmptyCaseBlock(prevStmt, nextStmt)) { - handleSingleLineCommentInEmptyCaseBlock(prevStmt, singleLineComment, - nextStmt); + handleCommentInEmptyCaseBlock(prevStmt, comment, nextStmt); } - else if (isFallThroughSingleLineComment(prevStmt, nextStmt)) { - handleFallThroughtSingleLineComment(prevStmt, singleLineComment, - nextStmt); + else if (isFallThroughComment(prevStmt, nextStmt)) { + handleFallThroughComment(prevStmt, comment, nextStmt); } else if (isInEmptyCodeBlock(prevStmt, nextStmt)) { - handleSingleLineCommentInEmptyCodeBlock(singleLineComment, nextStmt); + handleCommentInEmptyCodeBlock(comment, nextStmt); } - else if (isSingleLineCommentAtTheEndOfTheCodeBlock(nextStmt)) { - handleSIngleLineCommentAtTheEndOfTheCodeBlock(prevStmt, singleLineComment, - nextStmt); + else if (isCommentAtTheEndOfTheCodeBlock(nextStmt)) { + handleCommentAtTheEndOfTheCodeBlock(prevStmt, comment, nextStmt); } - else if (nextStmt != null - && !areSameLevelIndented(singleLineComment, nextStmt, nextStmt)) { - log(singleLineComment.getLineNo(), MSG_KEY_SINGLE, nextStmt.getLineNo(), - singleLineComment.getColumnNo(), nextStmt.getColumnNo()); + else if (nextStmt != null && !areSameLevelIndented(comment, nextStmt, nextStmt)) { + log(comment.getLineNo(), getMessageKey(comment), nextStmt.getLineNo(), + comment.getColumnNo(), nextStmt.getColumnNo()); } } } /** - * Returns the previous statement of a single line comment. - * @param comment single line comment. - * @return the previous statement of a single line comment. + * Returns the next statement of a comment. + * @param comment comment. + * @return the next statement of a comment. + */ + private static DetailAST getNextStmt(DetailAST comment) { + DetailAST nextStmt = comment.getNextSibling(); + while (nextStmt != null + && isComment(nextStmt) + && comment.getColumnNo() != nextStmt.getColumnNo()) { + nextStmt = nextStmt.getNextSibling(); + } + return nextStmt; + } + + /** + * Returns the previous statement of a comment. + * @param comment comment. + * @return the previous statement of a comment. */ - private static DetailAST getPreviousStatementOfSingleLineComment(DetailAST comment) { + private DetailAST getPreviousStatement(DetailAST comment) { final DetailAST prevStatement; if (isDistributedPreviousStatement(comment)) { - prevStatement = getDistributedPreviousStatementOfSingleLineComment(comment); + prevStatement = getDistributedPreviousStatement(comment); } else { - prevStatement = getOneLinePreviousStatementOfSingleLineComment(comment); + prevStatement = getOneLinePreviousStatement(comment); } return prevStatement; } /** - * Checks whether the previous statement of a single line comment is distributed over two or - * more lines. - * @param singleLineComment single line comment. - * @return true if the previous statement of a single line comment is distributed over two or - * more lines. - */ - private static boolean isDistributedPreviousStatement(DetailAST singleLineComment) { - final DetailAST previousSibling = singleLineComment.getPreviousSibling(); - return isDistributedMethodChainOrConcatenationStatement(singleLineComment, previousSibling) + * Checks whether the previous statement of a comment is distributed over two or more lines. + * @param comment comment to check. + * @return true if the previous statement of a comment is distributed over two or more lines. + */ + private boolean isDistributedPreviousStatement(DetailAST comment) { + final DetailAST previousSibling = comment.getPreviousSibling(); + return isDistributedExpression(comment) || isDistributedReturnStatement(previousSibling) || isDistributedThrowStatement(previousSibling); } /** - * Checks whether the previous statement of a single line comment is a method call chain or - * string concatenation statemen distributed over two ore more lines. - * @param comment single line comment. - * @param commentPreviousSibling previous sibling of the sinle line comment. - * @return if the previous statement of a single line comment is a method call chain or - * string concatenation statemen distributed over two ore more lines. - */ - private static boolean isDistributedMethodChainOrConcatenationStatement( - DetailAST comment, DetailAST commentPreviousSibling) { - boolean destributed = false; - if (commentPreviousSibling != null - && commentPreviousSibling.getType() == TokenTypes.SEMI - && comment.getLineNo() - commentPreviousSibling.getLineNo() == 1) { - DetailAST currentToken = commentPreviousSibling.getPreviousSibling(); - while (currentToken.getFirstChild() != null) { - currentToken = currentToken.getFirstChild(); + * Checks whether the previous statement of a comment is a method call chain or + * string concatenation statement distributed over two ore more lines. + * @param comment comment to check. + * @return true if the previous statement is a distributed expression. + */ + private boolean isDistributedExpression(DetailAST comment) { + DetailAST previousSibling = comment.getPreviousSibling(); + while (previousSibling != null && isComment(previousSibling)) { + previousSibling = previousSibling.getPreviousSibling(); + } + boolean isDistributed = false; + if (previousSibling != null) { + if (previousSibling.getType() == TokenTypes.SEMI + && isOnPreviousLineIgnoringComments(comment, previousSibling)) { + DetailAST currentToken = previousSibling.getPreviousSibling(); + while (currentToken.getFirstChild() != null) { + currentToken = currentToken.getFirstChild(); + } + if (currentToken.getType() == TokenTypes.COMMENT_CONTENT) { + currentToken = currentToken.getParent(); + while (isComment(currentToken)) { + currentToken = currentToken.getNextSibling(); + } + } + if (previousSibling.getLineNo() != currentToken.getLineNo()) { + isDistributed = true; + } } - if (currentToken.getType() != TokenTypes.COMMENT_CONTENT - && commentPreviousSibling.getLineNo() != currentToken.getLineNo()) { - destributed = true; + else { + isDistributed = isStatementWithPossibleCurlies(previousSibling); } } - return destributed; + return isDistributed; } /** - * Checks whether the previous statement of a single line comment is a destributed return - * statement. - * @param commentPreviousSibling previous sibling of the single line comment. - * @return true if the previous statement of a single line comment is a destributed return - * statement. + * Whether the statement can have or always have curly brackets. + * @param previousSibling the statement to check. + * @return true if the statement can have or always have curly brackets. + */ + private static boolean isStatementWithPossibleCurlies(DetailAST previousSibling) { + return previousSibling.getType() == TokenTypes.LITERAL_IF + || previousSibling.getType() == TokenTypes.LITERAL_TRY + || previousSibling.getType() == TokenTypes.LITERAL_FOR + || previousSibling.getType() == TokenTypes.LITERAL_DO + || previousSibling.getType() == TokenTypes.LITERAL_WHILE + || previousSibling.getType() == TokenTypes.LITERAL_SWITCH + || isDefinition(previousSibling); + } + + /** + * Whether the statement is a kind of definition (method, class etc.). + * @param previousSibling the statement to check. + * @return true if the statement is a kind of definition. + */ + private static boolean isDefinition(DetailAST previousSibling) { + return previousSibling.getType() == TokenTypes.METHOD_DEF + || previousSibling.getType() == TokenTypes.CLASS_DEF + || previousSibling.getType() == TokenTypes.INTERFACE_DEF + || previousSibling.getType() == TokenTypes.ENUM_DEF + || previousSibling.getType() == TokenTypes.ANNOTATION_DEF; + } + + /** + * Checks whether the previous statement of a comment is a distributed return statement. + * @param commentPreviousSibling previous sibling of the comment. + * @return true if the previous statement of a comment is a distributed return statement. */ private static boolean isDistributedReturnStatement(DetailAST commentPreviousSibling) { - boolean destributed = false; + boolean isDistributed = false; if (commentPreviousSibling != null && commentPreviousSibling.getType() == TokenTypes.LITERAL_RETURN) { final DetailAST firstChild = commentPreviousSibling.getFirstChild(); final DetailAST nextSibling = firstChild.getNextSibling(); if (nextSibling != null) { - destributed = true; + isDistributed = true; } } - return destributed; + return isDistributed; } /** - * Checks whether the previous statement of a single line comment is a destributed throw - * statement. - * @param commentPreviousSibling previous sibling of the single line comment. - * @return true if the previous statement of a single line comment is a destributed throw - * statement. + * Checks whether the previous statement of a comment is a distributed throw statement. + * @param commentPreviousSibling previous sibling of the comment. + * @return true if the previous statement of a comment is a distributed throw statement. */ private static boolean isDistributedThrowStatement(DetailAST commentPreviousSibling) { - boolean destributed = false; + boolean isDistributed = false; if (commentPreviousSibling != null && commentPreviousSibling.getType() == TokenTypes.LITERAL_THROW) { final DetailAST firstChild = commentPreviousSibling.getFirstChild(); final DetailAST nextSibling = firstChild.getNextSibling(); if (nextSibling.getLineNo() != commentPreviousSibling.getLineNo()) { - destributed = true; + isDistributed = true; } } - return destributed; + return isDistributed; } /** - * Returns the first token of the destributed previous statement of single line comment. - * @param comment single line comment. - * @return the first token of the destributed previous statement of single line comment. + * Returns the first token of the distributed previous statement of comment. + * @param comment comment to check. + * @return the first token of the distributed previous statement of comment. */ - private static DetailAST getDistributedPreviousStatementOfSingleLineComment(DetailAST comment) { - final DetailAST previousStatement; + private static DetailAST getDistributedPreviousStatement(DetailAST comment) { DetailAST currentToken = comment.getPreviousSibling(); - if (currentToken.getType() == TokenTypes.LITERAL_RETURN - || currentToken.getType() == TokenTypes.LITERAL_THROW) { - previousStatement = currentToken; + while (isComment(currentToken)) { + currentToken = currentToken.getPreviousSibling(); } - else { + final DetailAST previousStatement; + if (currentToken.getType() == TokenTypes.SEMI) { currentToken = currentToken.getPreviousSibling(); while (currentToken.getFirstChild() != null) { currentToken = currentToken.getFirstChild(); } previousStatement = currentToken; } + else { + previousStatement = currentToken; + } return previousStatement; } @@ -295,7 +339,7 @@ } /** - * Checks whether single line comment is a 'fall through' comment. + * Checks whether comment is a 'fall through' comment. * For example: *

    * {@code @@ -311,9 +355,9 @@ *

    * @param prevStmt previous statement. * @param nextStmt next statement. - * @return true if a single line comment is a 'fall through' comment. + * @return true if a comment is a 'fall through' comment. */ - private static boolean isFallThroughSingleLineComment(DetailAST prevStmt, DetailAST nextStmt) { + private static boolean isFallThroughComment(DetailAST prevStmt, DetailAST nextStmt) { return prevStmt != null && nextStmt != null && prevStmt.getType() != TokenTypes.LITERAL_CASE @@ -322,11 +366,11 @@ } /** - * Checks whether a single line comment is placed at the end of the code block. + * Checks whether a comment is placed at the end of the code block. * @param nextStmt next statement. - * @return true if a single line comment is placed at the end of the block. + * @return true if a comment is placed at the end of the block. */ - private static boolean isSingleLineCommentAtTheEndOfTheCodeBlock(DetailAST nextStmt) { + private static boolean isCommentAtTheEndOfTheCodeBlock(DetailAST nextStmt) { return nextStmt != null && nextStmt.getType() == TokenTypes.RCURLY; } @@ -350,12 +394,14 @@ return prevStmt != null && nextStmt != null && (prevStmt.getType() == TokenTypes.SLIST + || prevStmt.getType() == TokenTypes.LCURLY + || prevStmt.getType() == TokenTypes.ARRAY_INIT || prevStmt.getType() == TokenTypes.OBJBLOCK) && nextStmt.getType() == TokenTypes.RCURLY; } /** - * Handles a single line comment which is plased within empty case block. + * Handles a comment which is placed within empty case block. * Note, if comment is placed at the end of the empty case block, we have Checkstyle's * limitations to clearly detect user intention of explanation target - above or below. The * only case we can assume as a violation is when a single line comment within the empty case @@ -374,9 +420,8 @@ * @param comment single line comment. * @param nextStmt next statement. */ - private void handleSingleLineCommentInEmptyCaseBlock(DetailAST prevStmt, DetailAST comment, - DetailAST nextStmt) { - + private void handleCommentInEmptyCaseBlock(DetailAST prevStmt, DetailAST comment, + DetailAST nextStmt) { if (comment.getColumnNo() < prevStmt.getColumnNo() || comment.getColumnNo() < nextStmt.getColumnNo()) { logMultilineIndentation(prevStmt, comment, nextStmt); @@ -416,18 +461,16 @@ * @param comment single line comment. * @param nextStmt next statement. */ - private void handleFallThroughtSingleLineComment(DetailAST prevStmt, DetailAST comment, - DetailAST nextStmt) { - + private void handleFallThroughComment(DetailAST prevStmt, DetailAST comment, + DetailAST nextStmt) { if (!areSameLevelIndented(comment, prevStmt, nextStmt)) { logMultilineIndentation(prevStmt, comment, nextStmt); } - } /** - * Hendles a single line comment which is placed at the end of non empty code block. - * Note, if single line comment is plcaed at the end of non empty block the comment should have + * Handles a comment which is placed at the end of non empty code block. + * Note, if single line comment is placed at the end of non empty block the comment should have * the same indentation level as the previous statement. For example: *

    * {@code @@ -438,32 +481,52 @@ * } *

    * @param prevStmt previous statement. - * @param comment single line statement. + * @param comment comment to check. * @param nextStmt next statement. */ - private void handleSIngleLineCommentAtTheEndOfTheCodeBlock(DetailAST prevStmt, - DetailAST comment, - DetailAST nextStmt) { + private void handleCommentAtTheEndOfTheCodeBlock(DetailAST prevStmt, DetailAST comment, + DetailAST nextStmt) { if (prevStmt != null) { if (prevStmt.getType() == TokenTypes.LITERAL_CASE || prevStmt.getType() == TokenTypes.CASE_GROUP - || prevStmt.getType() == TokenTypes.LITERAL_DEFAULT - || prevStmt.getType() == TokenTypes.SINGLE_LINE_COMMENT) { + || prevStmt.getType() == TokenTypes.LITERAL_DEFAULT) { if (comment.getColumnNo() < nextStmt.getColumnNo()) { - log(comment.getLineNo(), MSG_KEY_SINGLE, nextStmt.getLineNo(), + log(comment.getLineNo(), getMessageKey(comment), nextStmt.getLineNo(), comment.getColumnNo(), nextStmt.getColumnNo()); } } + else if (isCommentForMultiblock(nextStmt)) { + if (!areSameLevelIndented(comment, prevStmt, nextStmt)) { + logMultilineIndentation(prevStmt, comment, nextStmt); + } + } else if (!areSameLevelIndented(comment, prevStmt, prevStmt)) { - log(comment.getLineNo(), MSG_KEY_SINGLE, prevStmt.getLineNo(), - comment.getColumnNo(), prevStmt.getColumnNo()); + final int prevStmtLineNo = prevStmt.getLineNo(); + log(comment.getLineNo(), getMessageKey(comment), prevStmtLineNo, + comment.getColumnNo(), getLineStart(prevStmtLineNo)); } } + } + /** + * Whether the comment might have been used for the next block in a multi-block structure. + * @param endBlockStmt the end of the current block. + * @return true, if the comment might have been used for the next + * block in a multi-block structure. + */ + private static boolean isCommentForMultiblock(DetailAST endBlockStmt) { + final DetailAST nextBlock = endBlockStmt.getParent().getNextSibling(); + final int endBlockLineNo = endBlockStmt.getLineNo(); + final DetailAST catchAst = endBlockStmt.getParent().getParent(); + final DetailAST finallyAst = catchAst.getNextSibling(); + return nextBlock != null && nextBlock.getLineNo() == endBlockLineNo + || finallyAst != null + && catchAst.getType() == TokenTypes.LITERAL_CATCH + && finallyAst.getLineNo() == endBlockLineNo; } /** - * Handles a single line comment which is placed within the empty code block. + * Handles a comment which is placed within the empty code block. * Note, if comment is placed at the end of the empty code block, we have Checkstyle's * limitations to clearly detect user intention of explanation target - above or below. The * only case we can assume as a violation is when a single line comment within the empty @@ -477,35 +540,38 @@ * } *

    * - * @param comment single line comment. + * @param comment comment to check. * @param nextStmt next statement. */ - private void handleSingleLineCommentInEmptyCodeBlock(DetailAST comment, DetailAST nextStmt) { + private void handleCommentInEmptyCodeBlock(DetailAST comment, DetailAST nextStmt) { if (comment.getColumnNo() < nextStmt.getColumnNo()) { - log(comment.getLineNo(), MSG_KEY_SINGLE, nextStmt.getLineNo(), + log(comment.getLineNo(), getMessageKey(comment), nextStmt.getLineNo(), comment.getColumnNo(), nextStmt.getColumnNo()); } } /** * Does pre-order traverse of abstract syntax tree to find the previous statement of the - * single line comment. If previous statement of the comment is found, then the traverse will + * comment. If previous statement of the comment is found, then the traverse will * be finished. * @param comment current statement. * @return previous statement of the comment or null if the comment does not have previous * statement. */ - private static DetailAST getOneLinePreviousStatementOfSingleLineComment(DetailAST comment) { - DetailAST previousStatement = null; - final Stack stack = new Stack<>(); + private DetailAST getOneLinePreviousStatement(DetailAST comment) { DetailAST root = comment.getParent(); + while (root != null && !isBlockStart(root)) { + root = root.getParent(); + } - while (root != null || !stack.empty()) { - if (!stack.empty()) { + final Deque stack = new ArrayDeque<>(); + DetailAST previousStatement = null; + while (root != null || !stack.isEmpty()) { + if (!stack.isEmpty()) { root = stack.pop(); } while (root != null) { - previousStatement = findPreviousStatementOfSingleLineComment(comment, root); + previousStatement = findPreviousStatement(comment, root); if (previousStatement != null) { root = null; stack.clear(); @@ -521,15 +587,38 @@ } /** - * Finds a previous statement of the single line comment. + * Whether the ast is a comment. + * @param ast the ast to check. + * @return true if the ast is a comment. + */ + private static boolean isComment(DetailAST ast) { + final int astType = ast.getType(); + return astType == TokenTypes.SINGLE_LINE_COMMENT + || astType == TokenTypes.BLOCK_COMMENT_BEGIN + || astType == TokenTypes.COMMENT_CONTENT + || astType == TokenTypes.BLOCK_COMMENT_END; + } + + /** + * Whether the AST node starts a block. + * @param root the AST node to check. + * @return true if the AST node starts a block. + */ + private static boolean isBlockStart(DetailAST root) { + return root.getType() == TokenTypes.SLIST + || root.getType() == TokenTypes.OBJBLOCK + || root.getType() == TokenTypes.ARRAY_INIT + || root.getType() == TokenTypes.CASE_GROUP; + } + + /** + * Finds a previous statement of the comment. * Uses root token of the line while searching. - * @param comment single line comment. + * @param comment comment. * @param root root token of the line. - * @return previous statement of the single line comment or null if previous statement was not - * found. + * @return previous statement of the comment or null if previous statement was not found. */ - private static DetailAST findPreviousStatementOfSingleLineComment(DetailAST comment, - DetailAST root) { + private DetailAST findPreviousStatement(DetailAST comment, DetailAST root) { DetailAST previousStatement = null; if (root.getLineNo() >= comment.getLineNo()) { // ATTENTION: parent of the comment is below the comment in case block @@ -553,7 +642,8 @@ tokenWhichBeginsTheLine = root; } if (tokenWhichBeginsTheLine != null - && isOnPreviousLine(comment, tokenWhichBeginsTheLine)) { + && !isComment(tokenWhichBeginsTheLine) + && isOnPreviousLineIgnoringComments(comment, tokenWhichBeginsTheLine)) { previousStatement = tokenWhichBeginsTheLine; } return previousStatement; @@ -603,30 +693,100 @@ } /** - * Checks whether the checked statement is on previous line. + * Checks whether the checked statement is on the previous line ignoring empty lines + * and lines which contain only comments. * @param currentStatement current statement. * @param checkedStatement checked statement. - * @return true if checked statement is on the line which is previous to current statement. + * @return true if checked statement is on the line which is previous to current statement + * ignoring empty lines and lines which contain only comments. + */ + private boolean isOnPreviousLineIgnoringComments(DetailAST currentStatement, + DetailAST checkedStatement) { + DetailAST nextToken = getNextToken(checkedStatement); + int distanceAim = 1; + if (nextToken != null && isComment(nextToken)) { + distanceAim += countEmptyLines(checkedStatement, currentStatement); + } + + while (nextToken != null && nextToken != currentStatement && isComment(nextToken)) { + if (nextToken.getType() == TokenTypes.BLOCK_COMMENT_BEGIN) { + distanceAim += nextToken.getLastChild().getLineNo() - nextToken.getLineNo(); + } + distanceAim++; + nextToken = nextToken.getNextSibling(); + } + return currentStatement.getLineNo() - checkedStatement.getLineNo() == distanceAim; + } + + /** + * Get the token to start counting the number of lines to add to the distance aim from. + * @param checkedStatement the checked statement. + * @return the token to start counting the number of lines to add to the distance aim from. */ - private static boolean isOnPreviousLine(DetailAST currentStatement, - DetailAST checkedStatement) { - return currentStatement.getLineNo() - checkedStatement.getLineNo() == 1; + private DetailAST getNextToken(DetailAST checkedStatement) { + DetailAST nextToken; + if (checkedStatement.getType() == TokenTypes.SLIST + || checkedStatement.getType() == TokenTypes.ARRAY_INIT + || checkedStatement.getType() == TokenTypes.CASE_GROUP) { + nextToken = checkedStatement.getFirstChild(); + } + else { + nextToken = checkedStatement.getNextSibling(); + } + if (nextToken != null && isComment(nextToken) && isTrailingComment(nextToken)) { + nextToken = nextToken.getNextSibling(); + } + return nextToken; + } + + /** + * Count the number of empty lines between statements. + * @param startStatement start statement. + * @param endStatement end statement. + * @return the number of empty lines between statements. + */ + private int countEmptyLines(DetailAST startStatement, DetailAST endStatement) { + int emptyLinesNumber = 0; + final String[] lines = getLines(); + final int endLineNo = endStatement.getLineNo(); + for (int lineNo = startStatement.getLineNo(); lineNo < endLineNo; lineNo++) { + if (CommonUtils.isBlank(lines[lineNo])) { + emptyLinesNumber++; + } + } + return emptyLinesNumber; } /** * Logs comment which can have the same indentation level as next or previous statement. * @param comment comment. - * @param nextStmt previous statement. - * @param prevStmt next statement. + * @param nextStmt next statement. + * @param prevStmt previous statement. */ private void logMultilineIndentation(DetailAST prevStmt, DetailAST comment, DetailAST nextStmt) { final String multilineNoTemplate = "%d, %d"; - log(comment.getLineNo(), MSG_KEY_SINGLE, + log(comment.getLineNo(), getMessageKey(comment), String.format(Locale.getDefault(), multilineNoTemplate, prevStmt.getLineNo(), nextStmt.getLineNo()), comment.getColumnNo(), - String.format(Locale.getDefault(), multilineNoTemplate, prevStmt.getColumnNo(), - nextStmt.getColumnNo())); + String.format(Locale.getDefault(), multilineNoTemplate, + getLineStart(prevStmt.getLineNo()), getLineStart(nextStmt.getLineNo()))); + } + + /** + * Get a message key depending on a comment type. + * @param comment the comment to process. + * @return a message key. + */ + private static String getMessageKey(DetailAST comment) { + final String msgKey; + if (comment.getType() == TokenTypes.SINGLE_LINE_COMMENT) { + msgKey = MSG_KEY_SINGLE; + } + else { + msgKey = MSG_KEY_BLOCK; + } + return msgKey; } /** @@ -635,15 +795,13 @@ * @return comment's previous statement or null if previous statement is absent. */ private static DetailAST getPrevStatementFromSwitchBlock(DetailAST comment) { - DetailAST prevStmt = null; + final DetailAST prevStmt; final DetailAST parentStatement = comment.getParent(); - if (parentStatement != null) { - if (parentStatement.getType() == TokenTypes.CASE_GROUP) { - prevStmt = getPrevStatementWhenCommentIsUnderCase(parentStatement); - } - else { - prevStmt = getPrevCaseToken(parentStatement); - } + if (parentStatement.getType() == TokenTypes.CASE_GROUP) { + prevStmt = getPrevStatementWhenCommentIsUnderCase(parentStatement); + } + else { + prevStmt = getPrevCaseToken(parentStatement); } return prevStmt; } @@ -658,7 +816,7 @@ final DetailAST prevBlock = parentStatement.getPreviousSibling(); if (prevBlock.getLastChild() != null) { DetailAST blockBody = prevBlock.getLastChild().getLastChild(); - if (blockBody.getPreviousSibling() != null) { + if (blockBody.getType() == TokenTypes.SEMI) { blockBody = blockBody.getPreviousSibling(); } if (blockBody.getType() == TokenTypes.EXPR) { @@ -677,6 +835,9 @@ prevStmt = blockBody; } } + if (isComment(prevStmt)) { + prevStmt = prevStmt.getNextSibling(); + } } return prevStmt; } @@ -689,7 +850,7 @@ private static DetailAST getPrevCaseToken(DetailAST parentStatement) { final DetailAST prevCaseToken; final DetailAST parentBlock = parentStatement.getParent(); - if (parentBlock != null && parentBlock.getParent() != null + if (parentBlock.getParent() != null && parentBlock.getParent().getPreviousSibling() != null && parentBlock.getParent().getPreviousSibling().getType() == TokenTypes.LITERAL_CASE) { @@ -724,17 +885,40 @@ * @param nextStmt next code statement. * @return true if comment and next code statement are indented at the same level. */ - private static boolean areSameLevelIndented(DetailAST comment, DetailAST prevStmt, + private boolean areSameLevelIndented(DetailAST comment, DetailAST prevStmt, DetailAST nextStmt) { - final boolean result; - if (prevStmt == null) { - result = comment.getColumnNo() == nextStmt.getColumnNo(); + return comment.getColumnNo() == getLineStart(nextStmt.getLineNo()) + || comment.getColumnNo() == getLineStart(prevStmt.getLineNo()); + } + + /** + * Get a column number where a code starts. + * @param lineNo the line number to get column number in. + * @return the column number where a code starts. + */ + private int getLineStart(int lineNo) { + final char[] line = getLines()[lineNo - 1].toCharArray(); + int lineStart = 0; + while (Character.isWhitespace(line[lineStart])) { + lineStart++; + } + return lineStart; + } + + /** + * Checks if current comment is a trailing comment. + * @param comment comment to check. + * @return true if current comment is a trailing comment. + */ + private boolean isTrailingComment(DetailAST comment) { + final boolean isTrailingComment; + if (comment.getType() == TokenTypes.SINGLE_LINE_COMMENT) { + isTrailingComment = isTrailingSingleLineComment(comment); } else { - result = comment.getColumnNo() == nextStmt.getColumnNo() - || comment.getColumnNo() == prevStmt.getColumnNo(); + isTrailingComment = isTrailingBlockComment(comment); } - return result; + return isTrailingComment; } /** @@ -754,31 +938,6 @@ } /** - * Checks comment block indentations over surrounding code, e.g.: - *

    - * {@code - * /* some comment */ - this is ok - * double d = 3.14; - * /* some comment */ - this is not ok. - * double d1 = 5.0; - * } - *

    - * @param blockComment {@link TokenTypes#BLOCK_COMMENT_BEGIN block comment begin}. - */ - private void visitBlockComment(DetailAST blockComment) { - final DetailAST nextStatement = blockComment.getNextSibling(); - final DetailAST prevStatement = getPrevStatementFromSwitchBlock(blockComment); - - if (nextStatement != null - && nextStatement.getType() != TokenTypes.RCURLY - && !isTrailingBlockComment(blockComment) - && !areSameLevelIndented(blockComment, prevStatement, nextStatement)) { - log(blockComment.getLineNo(), MSG_KEY_BLOCK, nextStatement.getLineNo(), - blockComment.getColumnNo(), nextStatement.getColumnNo()); - } - } - - /** * Checks if current comment block is trailing comment, e.g.: *

    * {@code @@ -792,7 +951,9 @@ private boolean isTrailingBlockComment(DetailAST blockComment) { final String commentLine = getLine(blockComment.getLineNo() - 1); final int commentColumnNo = blockComment.getColumnNo(); + final DetailAST nextSibling = blockComment.getNextSibling(); return !CommonUtils.hasWhitespaceBefore(commentColumnNo, commentLine) - || blockComment.getNextSibling().getLineNo() == blockComment.getLineNo(); + || nextSibling != null && nextSibling.getLineNo() == blockComment.getLineNo(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/DoWhileHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/DoWhileHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/DoWhileHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/DoWhileHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class DoWhileHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -42,17 +43,29 @@ } /** - * Check the indentation level of the conditional expression. + * Check the indentation level of the while and conditional expression. */ - private void checkCondExpr() { - final DetailAST condAst = getMainAst() - .findFirstToken(TokenTypes.LPAREN).getNextSibling(); + private void checkWhileExpr() { + // check while statement alone + + final DetailAST whileAst = getMainAst().findFirstToken(TokenTypes.DO_WHILE); + + if (isOnStartOfLine(whileAst) + && !getIndent().isAcceptable(expandedTabsColumnNo(whileAst))) { + logError(whileAst, "while", expandedTabsColumnNo(whileAst)); + } + + // check condition alone + + final DetailAST condAst = getMainAst().findFirstToken(TokenTypes.LPAREN).getNextSibling(); + checkExpressionSubtree(condAst, getIndent(), false, false); } @Override public void checkIndentation() { super.checkIndentation(); - checkCondExpr(); + checkWhileExpr(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ElseHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ElseHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ElseHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ElseHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class ElseHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -49,18 +50,21 @@ final DetailAST ifAST = getMainAst().getParent(); final DetailAST slist = ifAST.findFirstToken(TokenTypes.SLIST); - if (slist != null) { + if (slist == null) { + super.checkTopLevelToken(); + } + else { final DetailAST lcurly = slist.getLastChild(); - if (lcurly.getLineNo() == getMainAst().getLineNo()) { - // indentation checked as part of LITERAL IF check - return; + // indentation checked as part of LITERAL IF check + if (lcurly.getLineNo() != getMainAst().getLineNo()) { + super.checkTopLevelToken(); } } - super.checkTopLevelToken(); } @Override protected DetailAST getNonListChild() { return getMainAst().getFirstChild(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/FinallyHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/FinallyHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/FinallyHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/FinallyHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -27,6 +27,7 @@ * @author jrichard */ public class FinallyHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -44,4 +45,5 @@ protected boolean shouldTopLevelStartLine() { return false; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ForHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ForHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ForHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ForHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class ForHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -72,10 +73,7 @@ public void checkIndentation() { checkForParams(); super.checkIndentation(); - final LineWrappingHandler lineWrap = - new LineWrappingHandler(getIndentCheck(), getMainAst(), - getForLoopRightParen(getMainAst())); - lineWrap.checkIndentation(); + checkWrappingIndentation(getMainAst(), getForLoopRightParen(getMainAst())); } /** @@ -87,4 +85,5 @@ private static DetailAST getForLoopRightParen(DetailAST literalForAst) { return literalForAst.findFirstToken(TokenTypes.RPAREN); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/HandlerFactory.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/HandlerFactory.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/HandlerFactory.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/HandlerFactory.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,10 +20,10 @@ package com.puppycrawl.tools.checkstyle.checks.indentation; import java.lang.reflect.Constructor; +import java.util.HashMap; import java.util.Map; import java.util.Set; -import com.google.common.collect.Maps; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -34,15 +34,14 @@ * @author jrichard */ public class HandlerFactory { + /** * Registered handlers. */ - private final Map> typeHandlers = - Maps.newHashMap(); + private final Map> typeHandlers = new HashMap<>(); /** Cache for created method call handlers. */ - private final Map createdHandlers = - Maps.newHashMap(); + private final Map createdHandlers = new HashMap<>(); /** Creates a HandlerFactory. */ public HandlerFactory() { @@ -76,6 +75,8 @@ register(TokenTypes.INDEX_OP, IndexHandler.class); register(TokenTypes.LITERAL_SYNCHRONIZED, SynchronizedHandler.class); register(TokenTypes.LAMBDA, LambdaHandler.class); + register(TokenTypes.ANNOTATION_DEF, ClassDefHandler.class); + register(TokenTypes.ANNOTATION_FIELD_DEF, MethodDefHandler.class); } /** @@ -165,11 +166,11 @@ */ private AbstractExpressionHandler createMethodCallHandler(IndentationCheck indentCheck, DetailAST ast, AbstractExpressionHandler parent) { - AbstractExpressionHandler theParent = parent; DetailAST astNode = ast.getFirstChild(); while (astNode.getType() == TokenTypes.DOT) { astNode = astNode.getFirstChild(); } + AbstractExpressionHandler theParent = parent; if (isHandledType(astNode.getType())) { theParent = getHandler(indentCheck, astNode, theParent); createdHandlers.put(astNode, theParent); @@ -178,7 +179,8 @@ } /** Clears cache of created handlers. */ - void clearCreatedHandlers() { + public void clearCreatedHandlers() { createdHandlers.clear(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IfHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IfHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IfHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IfHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class IfHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -43,18 +44,26 @@ @Override public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) { + final IndentLevel result; if (child instanceof ElseHandler) { - return getIndent(); + result = getIndent(); + } + else { + result = super.getSuggestedChildIndent(child); } - return super.getSuggestedChildIndent(child); + return result; } @Override protected IndentLevel getIndentImpl() { + final IndentLevel result; if (isIfAfterElse()) { - return getParent().getIndent(); + result = getParent().getIndent(); + } + else { + result = super.getIndentImpl(); } - return super.getIndentImpl(); + return result; } /** @@ -72,11 +81,9 @@ @Override protected void checkTopLevelToken() { - if (isIfAfterElse()) { - return; + if (!isIfAfterElse()) { + super.checkTopLevelToken(); } - - super.checkTopLevelToken(); } /** @@ -94,10 +101,7 @@ public void checkIndentation() { super.checkIndentation(); checkCondExpr(); - final LineWrappingHandler lineWrap = - new LineWrappingHandler(getIndentCheck(), getMainAst(), - getIfStatementRightParen(getMainAst())); - lineWrap.checkIndentation(); + checkWrappingIndentation(getMainAst(), getIfStatementRightParen(getMainAst())); } /** @@ -109,4 +113,5 @@ private static DetailAST getIfStatementRightParen(DetailAST literalIfAst) { return literalIfAst.findFirstToken(TokenTypes.RPAREN); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ImportHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ImportHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ImportHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ImportHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class ImportHandler extends AbstractExpressionHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -43,12 +44,15 @@ @Override public void checkIndentation() { - final int lineStart = getMainAst().getLineNo(); - final DetailAST semi = getMainAst().findFirstToken(TokenTypes.SEMI); - final int lineEnd = semi.getLineNo(); + final int columnNo = expandedTabsColumnNo(getMainAst()); - if (getMainAst().getLineNo() != lineEnd) { - checkLinesIndent(lineStart, lineEnd, getIndent()); + if (!getIndent().isAcceptable(columnNo) && isOnStartOfLine(getMainAst())) { + logError(getMainAst(), "", columnNo); } + + final DetailAST semi = getMainAst().findFirstToken(TokenTypes.SEMI); + + checkWrappingIndentation(getMainAst(), semi); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentationCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentationCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentationCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentationCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,8 +21,11 @@ import java.util.ArrayDeque; import java.util.Deque; +import java.util.HashSet; +import java.util.Set; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; /** @@ -30,7 +33,7 @@ * *

    * The basic idea behind this is that while - * pretty printers are sometimes convenient for reformats of + * pretty printers are sometimes convenient for reformatting of * legacy code, they often either aren't configurable enough or * just can't anticipate how format should be done. Sometimes this is * personal preference, other times it is practical experience. In any @@ -78,8 +81,11 @@ * @author o_sukhodolsky * @author Maikel Steneker * @author maxvetrenko + * @noinspection ThisEscapedInObjectConstruction */ -public class IndentationCheck extends Check { +@FileStatefulCheck +public class IndentationCheck extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -110,9 +116,15 @@ /** Handlers currently in use. */ private final Deque handlers = new ArrayDeque<>(); + /** Instance of line wrapping handler to use. */ + private final LineWrappingHandler lineWrappingHandler = new LineWrappingHandler(this); + /** Factory from which handlers are distributed. */ private final HandlerFactory handlerFactory = new HandlerFactory(); + /** Lines logged as having incorrect indentation. */ + private Set incorrectIndentationLines; + /** How many tabs or spaces to use. */ private int basicOffset = DEFAULT_INDENTATION; @@ -272,7 +284,10 @@ * @see java.text.MessageFormat */ public void indentationLog(int line, String key, Object... args) { - log(line, key, args); + if (!incorrectIndentationLines.contains(line)) { + incorrectIndentationLines.add(line); + log(line, key, args); + } } /** @@ -286,17 +301,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return handlerFactory.getHandledTypes(); + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return handlerFactory.getHandledTypes(); } @Override @@ -306,6 +321,7 @@ final PrimordialHandler primordialHandler = new PrimordialHandler(this); handlers.push(primordialHandler); primordialHandler.checkIndentation(); + incorrectIndentationLines = new HashSet<>(); } @Override @@ -322,11 +338,21 @@ } /** + * Accessor for the line wrapping handler. + * + * @return the line wrapping handler + */ + public LineWrappingHandler getLineWrappingHandler() { + return lineWrappingHandler; + } + + /** * Accessor for the handler factory. * * @return the handler factory */ - final HandlerFactory getHandlerFactory() { + public final HandlerFactory getHandlerFactory() { return handlerFactory; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentLevel.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentLevel.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentLevel.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndentLevel.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author o_sukhodolsky */ public class IndentLevel { + /** Set of acceptable indentation levels. */ private final BitSet levels = new BitSet(); @@ -72,6 +73,8 @@ } /** + * Returns true if indent less then minimal of + * acceptable indentation levels, false otherwise. * @param indent indentation to check. * @return true if {@code indent} less then minimal of * acceptable indentation levels, false otherwise. @@ -114,17 +117,22 @@ @Override public String toString() { + final String result; if (levels.cardinality() == 1) { - return String.valueOf(levels.nextSetBit(0)); + result = String.valueOf(levels.nextSetBit(0)); } - final StringBuilder sb = new StringBuilder(); - for (int i = levels.nextSetBit(0); i >= 0; - i = levels.nextSetBit(i + 1)) { - if (sb.length() > 0) { - sb.append(", "); + else { + final StringBuilder sb = new StringBuilder(50); + for (int i = levels.nextSetBit(0); i >= 0; + i = levels.nextSetBit(i + 1)) { + if (sb.length() > 0) { + sb.append(", "); + } + sb.append(i); } - sb.append(i); + result = sb.toString(); } - return sb.toString(); + return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndexHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndexHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndexHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/IndexHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -46,4 +46,5 @@ public void checkIndentation() { // do nothing. Used to provide a correct suggested child level for now. } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LabelHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LabelHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LabelHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LabelHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class LabelHandler extends AbstractExpressionHandler { + /** * The types of expressions that are children of a label. */ @@ -73,4 +74,5 @@ checkExpressionSubtree(parent, expected, true, false); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LambdaHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LambdaHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LambdaHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LambdaHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -27,6 +27,7 @@ * @author pietern */ public class LambdaHandler extends AbstractExpressionHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -45,6 +46,10 @@ return getIndent(); } + /** + * {@inheritDoc}. + * @noinspection MethodWithMultipleReturnPoints + */ @Override protected IndentLevel getIndentImpl() { if (getParent() instanceof MethodCallHandler) { @@ -89,4 +94,5 @@ } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LineSet.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LineSet.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LineSet.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LineSet.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,8 +20,7 @@ package com.puppycrawl.tools.checkstyle.checks.indentation; import java.util.SortedMap; - -import com.google.common.collect.Maps; +import java.util.TreeMap; /** * Represents a set of lines. @@ -29,10 +28,11 @@ * @author jrichard */ public class LineSet { + /** * Maps line numbers to their start column. */ - private final SortedMap lines = Maps.newTreeMap(); + private final SortedMap lines = new TreeMap<>(); /** * Get the starting column for a given line number. @@ -94,6 +94,7 @@ @Override public String toString() { - return "LineSet[firstLine=" + firstLine() + ", lastLine=" + lastLine() + "]"; + return "LineSet[firstLine=" + lines.firstKey() + ", lastLine=" + lines.lastKey() + "]"; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LineWrappingHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LineWrappingHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LineWrappingHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/LineWrappingHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -26,6 +26,7 @@ import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * This class checks line-wrapping into definitions and expressions. The @@ -38,142 +39,180 @@ public class LineWrappingHandler { /** - * The current instance of {@code IndentationCheck} class using this - * handler. This field used to get access to private fields of - * IndentationCheck instance. + * Enum to be used for test if first line's indentation should be checked or not. */ - private final IndentationCheck indentCheck; + public enum LineWrappingOptions { - /** - * Root node for current expression. - */ - private final DetailAST firstNode; - - /** - * Last node for current expression. - */ - private final DetailAST lastNode; + /** + * First line's indentation should NOT be checked. + */ + IGNORE_FIRST_LINE, + /** + * First line's indentation should be checked. + */ + NONE; + + /** + * Builds enum value from boolean. + * @param val value. + * @return enum instance. + * + * @noinspection BooleanParameter + */ + public static LineWrappingOptions ofBoolean(boolean val) { + LineWrappingOptions option = NONE; + if (val) { + option = IGNORE_FIRST_LINE; + } + return option; + } - /** - * User's value of line wrapping indentation. - */ - private final int indentLevel; + } /** - * Force strict condition in line wrapping case. + * The current instance of {@code IndentationCheck} class using this + * handler. This field used to get access to private fields of + * IndentationCheck instance. */ - private final boolean forceStrictCondition; + private final IndentationCheck indentCheck; /** * Sets values of class field, finds last node and calculates indentation level. * * @param instance * instance of IndentationCheck. - * @param firstNode - * root node for current expression. - * @param lastNode - * last node for current expression. */ - public LineWrappingHandler(IndentationCheck instance, DetailAST firstNode, DetailAST lastNode) { + public LineWrappingHandler(IndentationCheck instance) { indentCheck = instance; - this.firstNode = firstNode; - this.lastNode = lastNode; - indentLevel = indentCheck.getLineWrappingIndentation(); - forceStrictCondition = indentCheck.isForceStrictCondition(); } /** - * Getter for lastNode field. - * @return lastNode field + * Checks line wrapping into expressions and definitions using property + * 'lineWrappingIndentation'. + * + * @param firstNode First node to start examining. + * @param lastNode Last node to examine inclusively. */ - protected final DetailAST getLastNode() { - return lastNode; + public void checkIndentation(DetailAST firstNode, DetailAST lastNode) { + checkIndentation(firstNode, lastNode, indentCheck.getLineWrappingIndentation()); } /** * Checks line wrapping into expressions and definitions. - */ - public void checkIndentation() { - final NavigableMap firstNodesOnLines = collectFirstNodes(); + * + * @param firstNode First node to start examining. + * @param lastNode Last node to examine inclusively. + * @param indentLevel Indentation all wrapped lines should use. + */ + private void checkIndentation(DetailAST firstNode, DetailAST lastNode, int indentLevel) { + checkIndentation(firstNode, lastNode, indentLevel, + -1, LineWrappingOptions.IGNORE_FIRST_LINE); + } + + /** + * Checks line wrapping into expressions and definitions. + * + * @param firstNode First node to start examining. + * @param lastNode Last node to examine inclusively. + * @param indentLevel Indentation all wrapped lines should use. + * @param startIndent Indentation first line before wrapped lines used. + * @param ignoreFirstLine Test if first line's indentation should be checked or not. + */ + public void checkIndentation(DetailAST firstNode, DetailAST lastNode, int indentLevel, + int startIndent, LineWrappingOptions ignoreFirstLine) { + final NavigableMap firstNodesOnLines = collectFirstNodes(firstNode, + lastNode); final DetailAST firstLineNode = firstNodesOnLines.get(firstNodesOnLines.firstKey()); if (firstLineNode.getType() == TokenTypes.AT) { - checkAnnotationIndentation(firstLineNode, firstNodesOnLines); + DetailAST node = firstLineNode.getParent(); + while (node != null) { + if (node.getType() == TokenTypes.ANNOTATION) { + final DetailAST atNode = node.getFirstChild(); + final NavigableMap annotationLines = + firstNodesOnLines.subMap( + node.getLineNo(), + true, + getNextNodeLine(firstNodesOnLines, node), + true + ); + checkAnnotationIndentation(atNode, annotationLines, indentLevel); + } + node = node.getNextSibling(); + } + } + + if (ignoreFirstLine == LineWrappingOptions.IGNORE_FIRST_LINE) { + // First node should be removed because it was already checked before. + firstNodesOnLines.remove(firstNodesOnLines.firstKey()); } - // First node should be removed because it was already checked before. - firstNodesOnLines.remove(firstNodesOnLines.firstKey()); - final int firstNodeIndent = getFirstNodeIndent(firstLineNode); + final int firstNodeIndent; + if (startIndent == -1) { + firstNodeIndent = getLineStart(firstLineNode); + } + else { + firstNodeIndent = startIndent; + } final int currentIndent = firstNodeIndent + indentLevel; for (DetailAST node : firstNodesOnLines.values()) { final int currentType = node.getType(); - if (currentType == TokenTypes.RCURLY - || currentType == TokenTypes.RPAREN - || currentType == TokenTypes.ARRAY_INIT) { + if (currentType == TokenTypes.RPAREN) { logWarningMessage(node, firstNodeIndent); } - else { + else if (currentType != TokenTypes.RCURLY && currentType != TokenTypes.ARRAY_INIT) { logWarningMessage(node, currentIndent); } } } /** - * Calculates indentation of first node. + * Gets the next node line from the firstNodesOnLines map unless there is no next line, in + * which case, it returns the last line. * - * @param node - * first node. - * @return indentation of first node. - */ - private static int getFirstNodeIndent(DetailAST node) { - int indentLevel = node.getColumnNo(); - - if (node.getType() == TokenTypes.LITERAL_IF - && node.getParent().getType() == TokenTypes.LITERAL_ELSE) { - final DetailAST lcurly = node.getParent().getPreviousSibling(); - final DetailAST rcurly = lcurly.getLastChild(); - - if (lcurly.getType() == TokenTypes.SLIST - && rcurly.getLineNo() == node.getLineNo()) { - indentLevel = rcurly.getColumnNo(); - } - else { - indentLevel = node.getParent().getColumnNo(); - } + * @param firstNodesOnLines NavigableMap of lines and their first nodes. + * @param node the node for which to find the next node line + * @return the line number of the next line in the map + */ + private static Integer getNextNodeLine( + NavigableMap firstNodesOnLines, DetailAST node) { + Integer nextNodeLine = firstNodesOnLines.higherKey(node.getLastChild().getLineNo()); + if (nextNodeLine == null) { + nextNodeLine = firstNodesOnLines.lastKey(); } - return indentLevel; + return nextNodeLine; } /** * Finds first nodes on line and puts them into Map. * + * @param firstNode First node to start examining. + * @param lastNode Last node to examine inclusively. * @return NavigableMap which contains lines numbers as a key and first * nodes on lines as a values. */ - private NavigableMap collectFirstNodes() { + private NavigableMap collectFirstNodes(DetailAST firstNode, + DetailAST lastNode) { final NavigableMap result = new TreeMap<>(); result.put(firstNode.getLineNo(), firstNode); DetailAST curNode = firstNode.getFirstChild(); - while (curNode != null && curNode != lastNode) { - + while (curNode != lastNode) { if (curNode.getType() == TokenTypes.OBJBLOCK || curNode.getType() == TokenTypes.SLIST) { - curNode = curNode.getNextSibling(); + curNode = curNode.getLastChild(); } - if (curNode != null) { - final DetailAST firstTokenOnLine = result.get(curNode.getLineNo()); + final DetailAST firstTokenOnLine = result.get(curNode.getLineNo()); - if (firstTokenOnLine == null - || firstTokenOnLine.getColumnNo() >= curNode.getColumnNo()) { - result.put(curNode.getLineNo(), curNode); - } - curNode = getNextCurNode(curNode); + if (firstTokenOnLine == null + || expandedTabsColumnNo(firstTokenOnLine) >= expandedTabsColumnNo(curNode)) { + result.put(curNode.getLineNo(), curNode); } + curNode = getNextCurNode(curNode); } return result; } @@ -203,52 +242,106 @@ * @param atNode at-clause node. * @param firstNodesOnLines map which contains * first nodes as values and line numbers as keys. + * @param indentLevel line wrapping indentation. */ private void checkAnnotationIndentation(DetailAST atNode, - NavigableMap firstNodesOnLines) { - final int currentIndent = atNode.getColumnNo() + indentLevel; - final int firstNodeIndent = atNode.getColumnNo(); + NavigableMap firstNodesOnLines, int indentLevel) { + final int firstNodeIndent = getLineStart(atNode); + final int currentIndent = firstNodeIndent + indentLevel; final Collection values = firstNodesOnLines.values(); - final DetailAST lastAnnotationNode = getLastAnnotationNode(atNode); + final DetailAST lastAnnotationNode = atNode.getParent().getLastChild(); final int lastAnnotationLine = lastAnnotationNode.getLineNo(); final Iterator itr = values.iterator(); while (firstNodesOnLines.size() > 1) { final DetailAST node = itr.next(); - if (node.getLineNo() <= lastAnnotationLine) { - final DetailAST parentNode = node.getParent(); - final boolean isCurrentNodeCloseAnnotationAloneInLine = - node.getLineNo() == lastAnnotationLine - && node.equals(lastAnnotationNode); - if (isCurrentNodeCloseAnnotationAloneInLine - || node.getType() == TokenTypes.AT - && parentNode.getParent().getType() == TokenTypes.MODIFIERS) { - logWarningMessage(node, firstNodeIndent); - } - else { - logWarningMessage(node, currentIndent); - } - itr.remove(); + final DetailAST parentNode = node.getParent(); + final boolean isCurrentNodeCloseAnnotationAloneInLine = + node.getLineNo() == lastAnnotationLine + && isEndOfScope(lastAnnotationNode, node); + if (isCurrentNodeCloseAnnotationAloneInLine + || node.getType() == TokenTypes.AT + && (parentNode.getParent().getType() == TokenTypes.MODIFIERS + || parentNode.getParent().getType() == TokenTypes.ANNOTATIONS) + || node.getLineNo() == atNode.getLineNo()) { + logWarningMessage(node, firstNodeIndent); } else { - break; + logWarningMessage(node, currentIndent); + } + itr.remove(); + } + } + + /** + * Checks line for end of scope. Handles occurrences of close braces and close parenthesis on + * the same line. + * + * @param lastAnnotationNode the last node of the annotation + * @param node the node indicating where to begin checking + * @return true if all the nodes up to the last annotation node are end of scope nodes + * false otherwise + */ + private static boolean isEndOfScope(final DetailAST lastAnnotationNode, final DetailAST node) { + DetailAST checkNode = node; + boolean endOfScope = true; + while (endOfScope && !checkNode.equals(lastAnnotationNode)) { + switch (checkNode.getType()) { + case TokenTypes.RCURLY: + case TokenTypes.RBRACK: + while (checkNode.getNextSibling() == null) { + checkNode = checkNode.getParent(); + } + checkNode = checkNode.getNextSibling(); + break; + default: + endOfScope = false; } } + return endOfScope; + } + + /** + * Get the column number for the start of a given expression, expanding + * tabs out into spaces in the process. + * + * @param ast the expression to find the start of + * + * @return the column number for the start of the expression + */ + private int expandedTabsColumnNo(DetailAST ast) { + final String line = + indentCheck.getLine(ast.getLineNo() - 1); + + return CommonUtils.lengthExpandedTabs(line, ast.getColumnNo(), + indentCheck.getIndentationTabWidth()); } /** - * Finds and returns last annotation node. - * @param atNode first at-clause node. - * @return last annotation node. + * Get the start of the line for the given expression. + * + * @param ast the expression to find the start of the line for + * + * @return the start of the line for the given expression + */ + private int getLineStart(DetailAST ast) { + final String line = indentCheck.getLine(ast.getLineNo() - 1); + return getLineStart(line); + } + + /** + * Get the start of the specified line. + * + * @param line the specified line number + * @return the start of the specified line */ - private static DetailAST getLastAnnotationNode(DetailAST atNode) { - DetailAST lastAnnotation = atNode.getParent(); - while (lastAnnotation.getNextSibling() != null - && lastAnnotation.getNextSibling().getType() == TokenTypes.ANNOTATION) { - lastAnnotation = lastAnnotation.getNextSibling(); + private int getLineStart(String line) { + int index = 0; + while (Character.isWhitespace(line.charAt(index))) { + index++; } - return lastAnnotation.getLastChild(); + return CommonUtils.lengthExpandedTabs(line, index, indentCheck.getIndentationTabWidth()); } /** @@ -260,19 +353,20 @@ * correct indentation. */ private void logWarningMessage(DetailAST currentNode, int currentIndent) { - if (forceStrictCondition) { - if (currentNode.getColumnNo() != currentIndent) { + if (indentCheck.isForceStrictCondition()) { + if (expandedTabsColumnNo(currentNode) != currentIndent) { indentCheck.indentationLog(currentNode.getLineNo(), IndentationCheck.MSG_ERROR, currentNode.getText(), - currentNode.getColumnNo(), currentIndent); + expandedTabsColumnNo(currentNode), currentIndent); } } else { - if (currentNode.getColumnNo() < currentIndent) { + if (expandedTabsColumnNo(currentNode) < currentIndent) { indentCheck.indentationLog(currentNode.getLineNo(), IndentationCheck.MSG_ERROR, currentNode.getText(), - currentNode.getColumnNo(), currentIndent); + expandedTabsColumnNo(currentNode), currentIndent); } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MemberDefHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MemberDefHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MemberDefHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MemberDefHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author o_sukhodolsky */ public class MemberDefHandler extends AbstractExpressionHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -50,11 +51,11 @@ else { checkModifiers(); } - final LineWrappingHandler lineWrap = - new LineWrappingHandler(getIndentCheck(), getMainAst(), - getVarDefStatementSemicolon(getMainAst())); - if (lineWrap.getLastNode() != null && !isArrayDeclaration(getMainAst())) { - lineWrap.checkIndentation(); + final DetailAST firstNode = getMainAst(); + final DetailAST lastNode = getVarDefStatementSemicolon(firstNode); + + if (lastNode != null && !isArrayDeclaration(firstNode)) { + checkWrappingIndentation(firstNode, lastNode); } } @@ -107,4 +108,5 @@ } return lastNode; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MethodCallHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MethodCallHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MethodCallHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MethodCallHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class MethodCallHandler extends AbstractExpressionHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -50,7 +51,8 @@ final MethodCallHandler container = (MethodCallHandler) getParent(); if (areOnSameLine(container.getMainAst(), getMainAst()) - || isChainedMethodCallWrapped()) { + || isChainedMethodCallWrapped() + || areMethodsChained(container.getMainAst(), getMainAst())) { indentLevel = container.getIndent(); } // we should increase indentation only if this is the first @@ -77,6 +79,27 @@ } /** + * Checks if ast2 is a chained method call that starts on the same level as ast1 ends. + * In other words, if the right paren of ast1 is on the same level as the lparen of ast2: + * + * {@code + * value.methodOne( + * argument1 + * ).methodTwo( + * argument2 + * ); + * } + * + * @param ast1 Ast1 + * @param ast2 Ast2 + * @return True if ast2 begins on the same level that ast1 ends + */ + private static boolean areMethodsChained(DetailAST ast1, DetailAST ast2) { + final DetailAST rparen = ast1.findFirstToken(TokenTypes.RPAREN); + return rparen.getLineNo() == ast2.getLineNo(); + } + + /** * If this is the first chained method call which was moved to the next line. * @return true if chained class are wrapped */ @@ -148,30 +171,24 @@ @Override public void checkIndentation() { final DetailAST exprNode = getMainAst().getParent(); - if (exprNode.getParent().getType() != TokenTypes.SLIST) { - return; - } - final DetailAST methodName = getMainAst().getFirstChild(); - checkExpressionSubtree(methodName, getIndent(), false, false); - - final DetailAST lparen = getMainAst(); - final DetailAST rparen = getMainAst().findFirstToken(TokenTypes.RPAREN); - checkLParen(lparen); + if (exprNode.getParent().getType() == TokenTypes.SLIST) { + final DetailAST methodName = getMainAst().getFirstChild(); + checkExpressionSubtree(methodName, getIndent(), false, false); + + final DetailAST lparen = getMainAst(); + final DetailAST rparen = getMainAst().findFirstToken(TokenTypes.RPAREN); + checkLeftParen(lparen); + + if (rparen.getLineNo() != lparen.getLineNo()) { + checkExpressionSubtree( + getMainAst().findFirstToken(TokenTypes.ELIST), + new IndentLevel(getIndent(), getBasicOffset()), + false, true); - if (rparen.getLineNo() == lparen.getLineNo()) { - return; + checkRightParen(lparen, rparen); + checkWrappingIndentation(getMainAst(), getMethodCallLastNode(getMainAst())); + } } - - checkExpressionSubtree( - getMainAst().findFirstToken(TokenTypes.ELIST), - new IndentLevel(getIndent(), getBasicOffset()), - false, true); - - checkRParen(lparen, rparen); - final LineWrappingHandler lineWrap = - new LineWrappingHandler(getIndentCheck(), getMainAst(), - getMethodCallLastNode(getMainAst())); - lineWrap.checkIndentation(); } @Override @@ -189,4 +206,5 @@ private static DetailAST getMethodCallLastNode(DetailAST firstNode) { return firstNode.getLastChild(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MethodDefHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MethodDefHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MethodDefHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/MethodDefHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -29,6 +29,7 @@ * @author Maikel Steneker */ public class MethodDefHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -57,19 +58,65 @@ } } + /** + * Check the indentation level of the throws clause. + */ + private void checkThrows() { + final DetailAST throwsAst = getMainAst().findFirstToken(TokenTypes.LITERAL_THROWS); + + if (throwsAst != null) { + checkWrappingIndentation(throwsAst, throwsAst.getNextSibling(), getIndentCheck() + .getThrowsIndent(), getLineStart(getMethodDefLineStart(getMainAst())), + !isOnStartOfLine(throwsAst)); + } + } + + /** + * Gets the start line of the method, excluding any annotations. This is required because the + * current {@link TokenTypes#METHOD_DEF} may not always be the start as seen in + * https://github.com/checkstyle/checkstyle/issues/3145. + * + * @param mainAst + * The method definition ast. + * @return The start column position of the method. + */ + private static int getMethodDefLineStart(DetailAST mainAst) { + // get first type position + int lineStart = mainAst.findFirstToken(TokenTypes.IDENT).getLineNo(); + + // check if there is a type before the indent + final DetailAST typeNode = mainAst.findFirstToken(TokenTypes.TYPE); + if (typeNode != null) { + lineStart = getFirstLine(lineStart, typeNode); + } + + // check if there is a modifier before the type + for (DetailAST node = mainAst.findFirstToken(TokenTypes.MODIFIERS).getFirstChild(); + node != null; + node = node.getNextSibling()) { + // skip annotations as we check them else where as outside the method + if (node.getType() == TokenTypes.ANNOTATION) { + continue; + } + + if (node.getLineNo() < lineStart) { + lineStart = node.getLineNo(); + } + } + + return lineStart; + } + @Override public void checkIndentation() { checkModifiers(); + checkThrows(); - final LineWrappingHandler lineWrap = - new LineWrappingHandler(getIndentCheck(), getMainAst(), - getMethodDefParamRightParen(getMainAst())); - lineWrap.checkIndentation(); - if (getLCurly() == null) { - // abstract method def -- no body - return; + checkWrappingIndentation(getMainAst(), getMethodDefParamRightParen(getMainAst())); + // abstract method def -- no body + if (getLeftCurly() != null) { + super.checkIndentation(); } - super.checkIndentation(); } /** @@ -94,9 +141,13 @@ if (ast.getType() == TokenTypes.CTOR_DEF) { name = "ctor def"; } + else if (ast.getType() == TokenTypes.ANNOTATION_FIELD_DEF) { + name = "annotation field def"; + } else { name = "method def"; } return name; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/NewHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/NewHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/NewHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/NewHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author Ilja Dubinin */ public class NewHandler extends AbstractExpressionHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -50,21 +51,26 @@ } final DetailAST lparen = getMainAst().findFirstToken(TokenTypes.LPAREN); - checkLParen(lparen); + checkLeftParen(lparen); } @Override protected IndentLevel getIndentImpl() { + final IndentLevel result; // if our expression isn't first on the line, just use the start // of the line - if (getLineStart(getMainAst()) != getMainAst().getColumnNo()) { - return new IndentLevel(getLineStart(getMainAst())); + if (getLineStart(getMainAst()) == getMainAst().getColumnNo()) { + result = super.getIndentImpl(); + } + else { + result = new IndentLevel(getLineStart(getMainAst())); } - return super.getIndentImpl(); + return result; } @Override protected boolean shouldIncreaseIndent() { return false; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ObjectBlockHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ObjectBlockHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ObjectBlockHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/ObjectBlockHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class ObjectBlockHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -47,12 +48,12 @@ } @Override - protected DetailAST getLCurly() { + protected DetailAST getLeftCurly() { return getMainAst().findFirstToken(TokenTypes.LCURLY); } @Override - protected DetailAST getRCurly() { + protected DetailAST getRightCurly() { return getMainAst().findFirstToken(TokenTypes.RCURLY); } @@ -81,23 +82,16 @@ // only do this if we have a new for a parent (anonymous inner // class) final DetailAST parentAST = getMainAst().getParent(); - if (parentAST.getType() != TokenTypes.LITERAL_NEW) { - return; + if (parentAST.getType() == TokenTypes.LITERAL_NEW) { + super.checkIndentation(); } - - super.checkIndentation(); } @Override - protected void checkRCurly() { - final DetailAST rcurly = getRCurly(); - final int rcurlyPos = expandedTabsColumnNo(rcurly); - final IndentLevel level = curlyIndent(); - level.addAcceptedIndent(level.getFirstIndentLevel() + getLineWrappingIndentation()); - - if (!level.isAcceptable(rcurlyPos) && isOnStartOfLine(rcurly)) { - logError(rcurly, "rcurly", rcurlyPos, curlyIndent()); - } + protected IndentLevel curlyIndent() { + final IndentLevel indent = super.curlyIndent(); + indent.addAcceptedIndent(indent.getFirstIndentLevel() + getLineWrappingIndentation()); + return indent; } /** @@ -108,4 +102,5 @@ private int getLineWrappingIndentation() { return getIndentCheck().getLineWrappingIndentation(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/PackageDefHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/PackageDefHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/PackageDefHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/PackageDefHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class PackageDefHandler extends AbstractExpressionHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -44,12 +45,14 @@ @Override public void checkIndentation() { final int columnNo = expandedTabsColumnNo(getMainAst()); - if (!getIndent().isAcceptable(columnNo)) { + + if (!getIndent().isAcceptable(columnNo) && isOnStartOfLine(getMainAst())) { logError(getMainAst(), "", columnNo); } - checkLinesIndent(getMainAst().getLineNo(), - getMainAst().findFirstToken(TokenTypes.SEMI).getLineNo(), - getIndent()); + final DetailAST semi = getMainAst().findFirstToken(TokenTypes.SEMI); + + checkWrappingIndentation(getMainAst(), semi); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/PrimordialHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/PrimordialHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/PrimordialHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/PrimordialHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,7 @@ * @author jrichard */ public class PrimordialHandler extends AbstractExpressionHandler { + /** * Construct an instance of this handler with the given indentation check. * @@ -41,11 +42,12 @@ @Override public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) { - return new IndentLevel(0); + return getIndentImpl(); } @Override protected IndentLevel getIndentImpl() { return new IndentLevel(0); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SlistHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SlistHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SlistHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SlistHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -78,14 +78,18 @@ // ... the case SLIST is followed by a user-created SLIST and // preceded by a switch + final IndentLevel result; // if our parent is a block handler we want to be transparent if (getParent() instanceof BlockParentHandler && !(getParent() instanceof SlistHandler) || child instanceof SlistHandler && getParent() instanceof CaseHandler) { - return getParent().getSuggestedChildIndent(child); + result = getParent().getSuggestedChildIndent(child); } - return super.getSuggestedChildIndent(child); + else { + result = super.getSuggestedChildIndent(child); + } + return result; } @Override @@ -94,12 +98,12 @@ } @Override - protected DetailAST getLCurly() { + protected DetailAST getLeftCurly() { return getMainAst(); } @Override - protected DetailAST getRCurly() { + protected DetailAST getRightCurly() { return getMainAst().findFirstToken(TokenTypes.RCURLY); } @@ -122,10 +126,9 @@ public void checkIndentation() { // only need to check this if parent is not // an if, else, while, do, ctor, method - if (hasBlockParent() || isSameLineCaseGroup()) { - return; + if (!hasBlockParent() && !isSameLineCaseGroup()) { + super.checkIndentation(); } - super.checkIndentation(); } /** @@ -137,4 +140,5 @@ return parentNode.getType() == TokenTypes.CASE_GROUP && getMainAst().getLineNo() == parentNode.getLineNo(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/StaticInitHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/StaticInitHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/StaticInitHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/StaticInitHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -27,6 +27,7 @@ * @author Jeff Weston */ public class StaticInitHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -44,4 +45,5 @@ protected boolean shouldTopLevelStartLine() { return false; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SwitchHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SwitchHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SwitchHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SwitchHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class SwitchHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -42,12 +43,12 @@ } @Override - protected DetailAST getLCurly() { + protected DetailAST getLeftCurly() { return getMainAst().findFirstToken(TokenTypes.LCURLY); } @Override - protected DetailAST getRCurly() { + protected DetailAST getRightCurly() { return getMainAst().findFirstToken(TokenTypes.RCURLY); } @@ -81,4 +82,5 @@ checkSwitchExpr(); super.checkIndentation(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SynchronizedHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SynchronizedHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SynchronizedHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/SynchronizedHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -53,10 +53,8 @@ if (!methodModifier) { super.checkIndentation(); checkSynchronizedExpr(); - final LineWrappingHandler lineWrap = - new LineWrappingHandler(getIndentCheck(), getMainAst(), - getSynchronizedStatementRightParen(getMainAst())); - lineWrap.checkIndentation(); + checkWrappingIndentation(getMainAst(), + getSynchronizedStatementRightParen(getMainAst())); } } @@ -72,7 +70,7 @@ } /** - * Checks if given synchronized is modifier of method* + * Checks if given synchronized is modifier of method. * @param ast synchronized(TokenTypes.LITERAL_SYNCHRONIZED) to check * @return true if synchronized only modifies method */ @@ -88,4 +86,5 @@ private static DetailAST getSynchronizedStatementRightParen(DetailAST syncStatementAST) { return syncStatementAST.findFirstToken(TokenTypes.RPAREN); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/TryHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/TryHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/TryHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/TryHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,6 +20,7 @@ package com.puppycrawl.tools.checkstyle.checks.indentation; import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; /** * Handler for try blocks. @@ -27,6 +28,7 @@ * @author jrichard */ public class TryHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -40,12 +42,125 @@ super(indentCheck, "try", ast, parent); } + /** + * Method to find left parenthesis of try with resources. + * + * @return DetailAst left parenthesis of try with resources + */ + private DetailAST getTryResLparen() { + return getMainAst().getFirstChild().getFirstChild(); + } + + /** + * Method to find right parenthesis of try with resources. + * + * @return DetailAst right parenthesis of try with resources + */ + private DetailAST getTryResRparen() { + return getMainAst().getFirstChild().getLastChild(); + } + @Override public IndentLevel getSuggestedChildIndent(AbstractExpressionHandler child) { + final IndentLevel result; if (child instanceof CatchHandler || child instanceof FinallyHandler) { - return getIndent(); + result = getIndent(); + } + else { + result = super.getSuggestedChildIndent(child); + } + return result; + } + + @Override + public void checkIndentation() { + super.checkIndentation(); + if (getMainAst().getFirstChild().getType() == TokenTypes.RESOURCE_SPECIFICATION) { + checkTryResParen(getTryResLparen(), "lparen"); + checkTryResParen(getTryResRparen(), "rparen"); + checkTryResources(getMainAst().getFirstChild()); } - return super.getSuggestedChildIndent(child); } + + /** + * Method to check the indentation of left paren or right paren. + * This method itself checks whether either of these are on start of line. This method + * takes care of line wrapping strict condition as well. + * + * @param parenAst lparen or rparen ast to check + * @param subType name to be used in log message + */ + private void checkTryResParen(final DetailAST parenAst, + final String subType) { + if (isOnStartOfLine(parenAst)) { + final IndentLevel expectedIdent = new IndentLevel(getIndent(), 0, + getIndentCheck().getLineWrappingIndentation()); + + checkChildIndentation(parenAst, subType, expectedIdent); + } + } + + /** + * Method to check indentation of try resources children. + * It takes into account forceStrictCondition value when logging errors. + * Example of usage would include checking for try parenthesis and try resources. + * + * @param ast AST to check. + * @param subType String representing child type. + * @param expectedIdent Expected indent level. + */ + private void checkChildIndentation(DetailAST ast, String subType, IndentLevel expectedIdent) { + if (getIndentCheck().isForceStrictCondition()) { + if (!expectedIdent.isAcceptable(expandedTabsColumnNo(ast))) { + logError(ast, subType, expandedTabsColumnNo(ast), expectedIdent); + } + } + else { + if (expandedTabsColumnNo(ast) < expectedIdent.getFirstIndentLevel()) { + logError(ast, subType, expandedTabsColumnNo(ast), expectedIdent); + } + } + } + + /** + * Checks indentation of resources parameters in try resources. + * + * @param resourcesSpecAst Resource specification ast + */ + private void checkTryResources(final DetailAST resourcesSpecAst) { + final DetailAST resourcesAst = resourcesSpecAst.findFirstToken(TokenTypes.RESOURCES); + final int indentation = getIndent().getFirstIndentLevel() + + getIndentCheck().getLineWrappingIndentation(); + final IndentLevel expectedResourceIndent = new IndentLevel(indentation); + + final String subType = "resource"; + + DetailAST resourceAst = resourcesAst.getFirstChild(); + while (resourceAst != null) { + if (resourceAst.getType() == TokenTypes.RESOURCE) { + final DetailAST nextSibling; + if (resourceAst.getNextSibling() == null) { + nextSibling = getTryResRparen(); + } + else { + nextSibling = resourceAst.getNextSibling(); + } + if (isOnStartOfLine(resourceAst)) { + checkChildIndentation(resourceAst, subType, expectedResourceIndent); + checkWrappingIndentation( + resourceAst, + nextSibling, + getIndentCheck().getLineWrappingIndentation(), + expectedResourceIndent.getFirstIndentLevel(), + true); + } + else { + checkWrappingIndentation(resourceAst, nextSibling); + } + } + resourceAst = resourceAst.getNextSibling(); + } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/WhileHandler.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/WhileHandler.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/WhileHandler.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/indentation/WhileHandler.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,7 @@ * @author jrichard */ public class WhileHandler extends BlockParentHandler { + /** * Construct an instance of this handler with the given indentation check, * abstract syntax tree, and parent handler. @@ -56,4 +57,5 @@ checkCondExpr(); super.checkIndentation(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractJavadocCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,93 +19,85 @@ package com.puppycrawl.tools.checkstyle.checks.javadoc; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; import java.util.Map; +import java.util.Set; -import org.antlr.v4.runtime.ANTLRInputStream; -import org.antlr.v4.runtime.BailErrorStrategy; -import org.antlr.v4.runtime.BaseErrorListener; -import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.ParserRuleContext; -import org.antlr.v4.runtime.RecognitionException; -import org.antlr.v4.runtime.Recognizer; -import org.antlr.v4.runtime.Token; -import org.antlr.v4.runtime.misc.ParseCancellationException; -import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.tree.TerminalNode; - -import com.google.common.base.CaseFormat; -import com.google.common.primitives.Ints; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser; +import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser.ParseErrorMessage; +import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser.ParseStatus; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.DetailNode; import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.grammars.javadoc.JavadocLexer; -import com.puppycrawl.tools.checkstyle.grammars.javadoc.JavadocParser; -import com.puppycrawl.tools.checkstyle.utils.BlockCommentPosition; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; /** * Base class for Checks that process Javadoc comments. * @author Baratali Izmailov + * @noinspection NoopMethodInAbstractClass */ -public abstract class AbstractJavadocCheck extends Check { - /** - * Error message key for common javadoc errors. - */ - public static final String MSG_KEY_PARSE_ERROR = "javadoc.parse.error"; +public abstract class AbstractJavadocCheck extends AbstractCheck { /** - * Unrecognized error from antlr parser. - */ - public static final String MSG_KEY_UNRECOGNIZED_ANTLR_ERROR = - "javadoc.unrecognized.antlr.error"; - /** * Message key of error message. Missed close HTML tag breaks structure * of parse tree, so parser stops parsing and generates such error * message. This case is special because parser prints error like * {@code "no viable alternative at input 'b \n *\n'"} and it is not * clear that error is about missed close HTML tag. */ - public static final String MSG_JAVADOC_MISSED_HTML_CLOSE = "javadoc.missed.html.close"; + public static final String MSG_JAVADOC_MISSED_HTML_CLOSE = + JavadocDetailNodeParser.MSG_JAVADOC_MISSED_HTML_CLOSE; + /** * Message key of error message. */ public static final String MSG_JAVADOC_WRONG_SINGLETON_TAG = - "javadoc.wrong.singleton.html.tag"; + JavadocDetailNodeParser.MSG_JAVADOC_WRONG_SINGLETON_TAG; /** * Parse error while rule recognition. */ - public static final String MSG_JAVADOC_PARSE_RULE_ERROR = "javadoc.parse.rule.error"; + public static final String MSG_JAVADOC_PARSE_RULE_ERROR = + JavadocDetailNodeParser.MSG_JAVADOC_PARSE_RULE_ERROR; /** * Key is "line:column". Value is {@link DetailNode} tree. Map is stored in {@link ThreadLocal} * to guarantee basic thread safety and avoid shared, mutable state when not necessary. */ private static final ThreadLocal> TREE_CACHE = - new ThreadLocal>() { - @Override - protected Map initialValue() { - return new HashMap<>(); - } - }; + ThreadLocal.withInitial(HashMap::new); /** - * Custom error listener. + * The file context. + * @noinspection ThreadLocalNotStaticFinal */ - private DescriptiveErrorListener errorListener; + private final ThreadLocal context = ThreadLocal.withInitial(FileContext::new); + + /** The javadoc tokens the check is interested in. */ + private final Set javadocTokens = new HashSet<>(); /** - * DetailAST node of considered Javadoc comment that is just a block comment - * in Java language syntax tree. + * This property determines if a check should log a violation upon encountering javadoc with + * non-tight html. The default return value for this method is set to false since checks + * generally tend to be fine with non tight html. It can be set through config file if a check + * is to log violation upon encountering non-tight HTML in javadoc. + * + * @see ParseStatus#firstNonTightHtmlTag + * @see ParseStatus#isNonTight() + * @see + * Tight HTML rules */ - private DetailAST blockCommentAst; + private boolean violateExecutionOnNonTightHtml; /** - * Returns the default token types a check is interested in. - * @return the default token types + * Returns the default javadoc token types a check is interested in. + * @return the default javadoc token types * @see JavadocTokenTypes */ public abstract int[] getDefaultJavadocTokens(); @@ -118,9 +110,113 @@ public abstract void visitJavadocToken(DetailNode ast); /** + * The configurable javadoc token set. + * Used to protect Checks against malicious users who specify an + * unacceptable javadoc token set in the configuration file. + * The default implementation returns the check's default javadoc tokens. + * @return the javadoc token set this check is designed for. + * @see JavadocTokenTypes + */ + public int[] getAcceptableJavadocTokens() { + final int[] defaultJavadocTokens = getDefaultJavadocTokens(); + final int[] copy = new int[defaultJavadocTokens.length]; + System.arraycopy(defaultJavadocTokens, 0, copy, 0, defaultJavadocTokens.length); + return copy; + } + + /** + * The javadoc tokens that this check must be registered for. + * @return the javadoc token set this must be registered for. + * @see JavadocTokenTypes + */ + public int[] getRequiredJavadocTokens() { + return CommonUtils.EMPTY_INT_ARRAY; + } + + /** + * This method determines if a check should process javadoc containing non-tight html tags. + * This method must be overridden in checks extending {@code AbstractJavadocCheck} which + * are not supposed to process javadoc containing non-tight html tags. + * + * @return true if the check should or can process javadoc containing non-tight html tags; + * false otherwise + * @see ParseStatus#isNonTight() + * @see + * Tight HTML rules + */ + public boolean acceptJavadocWithNonTightHtml() { + return true; + } + + /** + * Setter for {@link #violateExecutionOnNonTightHtml}. + * @param shouldReportViolation value to which the field shall be set to + * @see + * Tight HTML rules + */ + public final void setViolateExecutionOnNonTightHtml(boolean shouldReportViolation) { + violateExecutionOnNonTightHtml = shouldReportViolation; + } + + /** + * Adds a set of tokens the check is interested in. + * @param strRep the string representation of the tokens interested in + */ + public final void setJavadocTokens(String... strRep) { + javadocTokens.clear(); + for (String str : strRep) { + javadocTokens.add(JavadocUtils.getTokenId(str)); + } + } + + @Override + public void init() { + validateDefaultJavadocTokens(); + if (javadocTokens.isEmpty()) { + for (int id : getDefaultJavadocTokens()) { + javadocTokens.add(id); + } + } + else { + final int[] acceptableJavadocTokens = getAcceptableJavadocTokens(); + Arrays.sort(acceptableJavadocTokens); + for (Integer javadocTokenId : javadocTokens) { + if (Arrays.binarySearch(acceptableJavadocTokens, javadocTokenId) < 0) { + final String message = String.format(Locale.ROOT, "Javadoc Token \"%s\" was " + + "not found in Acceptable javadoc tokens list in check %s", + JavadocUtils.getTokenName(javadocTokenId), getClass().getName()); + throw new IllegalStateException(message); + } + } + } + } + + /** + * Validates that check's required javadoc tokens are subset of default javadoc tokens. + * @throws IllegalStateException when validation of default javadoc tokens fails + */ + private void validateDefaultJavadocTokens() { + if (getRequiredJavadocTokens().length != 0) { + final int[] defaultJavadocTokens = getDefaultJavadocTokens(); + Arrays.sort(defaultJavadocTokens); + for (final int javadocToken : getRequiredJavadocTokens()) { + if (Arrays.binarySearch(defaultJavadocTokens, javadocToken) < 0) { + final String message = String.format(Locale.ROOT, + "Javadoc Token \"%s\" from required javadoc " + + "tokens was not found in default " + + "javadoc tokens list in check %s", + javadocToken, getClass().getName()); + throw new IllegalStateException(message); + } + } + } + } + + /** * Called before the starting to process a tree. * @param rootAst * the root of the tree + * @noinspection WeakerAccess */ public void beginJavadocTree(DetailNode rootAst) { // No code by default, should be overridden only by demand at subclasses @@ -130,6 +226,7 @@ * Called after finished processing a tree. * @param rootAst * the root of the tree + * @noinspection WeakerAccess */ public void finishJavadocTree(DetailNode rootAst) { // No code by default, should be overridden only by demand at subclasses @@ -150,6 +247,16 @@ */ @Override public final int[] getDefaultTokens() { + return getRequiredTokens(); + } + + @Override + public final int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public final int[] getRequiredTokens() { return new int[] {TokenTypes.BLOCK_COMMENT_BEGIN }; } @@ -174,10 +281,9 @@ @Override public final void visitToken(DetailAST blockCommentNode) { - if (JavadocUtils.isJavadocComment(blockCommentNode) - && isCorrectJavadocPosition(blockCommentNode)) { + if (JavadocUtils.isJavadocComment(blockCommentNode)) { // store as field, to share with child Checks - blockCommentAst = blockCommentNode; + context.get().blockCommentAst = blockCommentNode; final String treeCacheKey = blockCommentNode.getLineNo() + ":" + blockCommentNode.getColumnNo(); @@ -188,12 +294,21 @@ result = TREE_CACHE.get().get(treeCacheKey); } else { - result = parseJavadocAsDetailNode(blockCommentNode); + result = context.get().parser + .parseJavadocAsDetailNode(blockCommentNode); TREE_CACHE.get().put(treeCacheKey, result); } if (result.getParseErrorMessage() == null) { - processTree(result.getTree()); + if (acceptJavadocWithNonTightHtml() || !result.isNonTight()) { + processTree(result.getTree()); + } + + if (violateExecutionOnNonTightHtml && result.isNonTight()) { + log(result.getFirstNonTightHtmlTag().getLine(), + JavadocDetailNodeParser.MSG_UNCLOSED_HTML_TAG, + result.getFirstNonTightHtmlTag().getText()); + } } else { final ParseErrorMessage parseErrorMessage = result.getParseErrorMessage(); @@ -202,7 +317,6 @@ parseErrorMessage.getMessageArguments()); } } - } /** @@ -210,332 +324,7 @@ * @return A block comment in the syntax tree. */ protected DetailAST getBlockCommentAst() { - return blockCommentAst; - } - - /** - * Checks Javadoc comment it's in right place. - * From Javadoc util documentation: - * "Placement of comments - Documentation comments are recognized only when placed - * immediately before class, interface, constructor, method, or field - * declarations -- see the class example, method example, and field example. - * Documentation comments placed in the body of a method are ignored. Only one - * documentation comment per declaration statement is recognized by the Javadoc tool." - * - * @param blockComment Block comment AST - * @return true if Javadoc is in right place - */ - private static boolean isCorrectJavadocPosition(DetailAST blockComment) { - return BlockCommentPosition.isOnClass(blockComment) - || BlockCommentPosition.isOnInterface(blockComment) - || BlockCommentPosition.isOnEnum(blockComment) - || BlockCommentPosition.isOnMethod(blockComment) - || BlockCommentPosition.isOnField(blockComment) - || BlockCommentPosition.isOnConstructor(blockComment) - || BlockCommentPosition.isOnEnumConstant(blockComment) - || BlockCommentPosition.isOnAnnotationDef(blockComment); - } - - /** - * Parses Javadoc comment as DetailNode tree. - * @param javadocCommentAst - * DetailAST of Javadoc comment - * @return DetailNode tree of Javadoc comment - */ - private ParseStatus parseJavadocAsDetailNode(DetailAST javadocCommentAst) { - final String javadocComment = JavadocUtils.getJavadocCommentContent(javadocCommentAst); - - // Use a new error listener each time to be able to use - // one check instance for multiple files to be checked - // without getting side effects. - errorListener = new DescriptiveErrorListener(); - - // Log messages should have line number in scope of file, - // not in scope of Javadoc comment. - // Offset is line number of beginning of Javadoc comment. - errorListener.setOffset(javadocCommentAst.getLineNo() - 1); - - final ParseStatus result = new ParseStatus(); - - try { - final ParseTree parseTree = parseJavadocAsParseTree(javadocComment); - - final DetailNode tree = convertParseTreeToDetailNode(parseTree); - result.setTree(tree); - } - catch (ParseCancellationException ex) { - // If syntax error occurs then message is printed by error listener - // and parser throws this runtime exception to stop parsing. - // Just stop processing current Javadoc comment. - ParseErrorMessage parseErrorMessage = errorListener.getErrorMessage(); - - // There are cases when antlr error listener does not handle syntax error - if (parseErrorMessage == null) { - parseErrorMessage = new ParseErrorMessage(javadocCommentAst.getLineNo(), - MSG_KEY_UNRECOGNIZED_ANTLR_ERROR, - javadocCommentAst.getColumnNo(), ex.getMessage()); - } - - result.setParseErrorMessage(parseErrorMessage); - } - - return result; - } - - /** - * Converts ParseTree (that is generated by ANTLRv4) to DetailNode tree. - * - * @param parseTreeNode root node of ParseTree - * @return root of DetailNode tree - */ - private DetailNode convertParseTreeToDetailNode(ParseTree parseTreeNode) { - final JavadocNodeImpl rootJavadocNode = createRootJavadocNode(parseTreeNode); - - JavadocNodeImpl currentJavadocParent = rootJavadocNode; - ParseTree parseTreeParent = parseTreeNode; - - while (currentJavadocParent != null) { - final JavadocNodeImpl[] children = - (JavadocNodeImpl[]) currentJavadocParent.getChildren(); - - insertChildrenNodes(children, parseTreeParent); - - if (children.length > 0) { - currentJavadocParent = children[0]; - parseTreeParent = parseTreeParent.getChild(0); - } - else { - JavadocNodeImpl nextJavadocSibling = (JavadocNodeImpl) JavadocUtils - .getNextSibling(currentJavadocParent); - - ParseTree nextParseTreeSibling = getNextSibling(parseTreeParent); - - if (nextJavadocSibling == null) { - JavadocNodeImpl tempJavadocParent = - (JavadocNodeImpl) currentJavadocParent.getParent(); - - ParseTree tempParseTreeParent = parseTreeParent.getParent(); - - while (nextJavadocSibling == null && tempJavadocParent != null) { - - nextJavadocSibling = (JavadocNodeImpl) JavadocUtils - .getNextSibling(tempJavadocParent); - - nextParseTreeSibling = getNextSibling(tempParseTreeParent); - - tempJavadocParent = (JavadocNodeImpl) tempJavadocParent.getParent(); - tempParseTreeParent = tempParseTreeParent.getParent(); - } - } - currentJavadocParent = nextJavadocSibling; - parseTreeParent = nextParseTreeSibling; - } - } - - return rootJavadocNode; - } - - /** - * Creates child nodes for each node from 'nodes' array. - * @param parseTreeParent original ParseTree parent node - * @param nodes array of JavadocNodeImpl nodes - */ - private void insertChildrenNodes(final JavadocNodeImpl[] nodes, ParseTree parseTreeParent) { - for (int i = 0; i < nodes.length; i++) { - final JavadocNodeImpl currentJavadocNode = nodes[i]; - final ParseTree currentParseTreeNodeChild = parseTreeParent.getChild(i); - final JavadocNodeImpl[] subChildren = - createChildrenNodes(currentJavadocNode, currentParseTreeNodeChild); - currentJavadocNode.setChildren(subChildren); - } - } - - /** - * Creates children Javadoc nodes base on ParseTree node's children. - * @param parentJavadocNode node that will be parent for created children - * @param parseTreeNode original ParseTree node - * @return array of Javadoc nodes - */ - private JavadocNodeImpl[] - createChildrenNodes(JavadocNodeImpl parentJavadocNode, ParseTree parseTreeNode) { - final JavadocNodeImpl[] children = - new JavadocNodeImpl[parseTreeNode.getChildCount()]; - - for (int j = 0; j < children.length; j++) { - final JavadocNodeImpl child = - createJavadocNode(parseTreeNode.getChild(j), parentJavadocNode, j); - - children[j] = child; - } - return children; - } - - /** - * Creates root JavadocNodeImpl node base on ParseTree root node. - * @param parseTreeNode ParseTree root node - * @return root Javadoc node - */ - private JavadocNodeImpl createRootJavadocNode(ParseTree parseTreeNode) { - final JavadocNodeImpl rootJavadocNode = createJavadocNode(parseTreeNode, null, -1); - - final int childCount = parseTreeNode.getChildCount(); - final JavadocNodeImpl[] children = new JavadocNodeImpl[childCount]; - - for (int i = 0; i < childCount; i++) { - final JavadocNodeImpl child = createJavadocNode(parseTreeNode.getChild(i), - rootJavadocNode, i); - children[i] = child; - } - rootJavadocNode.setChildren(children); - return rootJavadocNode; - } - - /** - * Creates JavadocNodeImpl node on base of ParseTree node. - * - * @param parseTree ParseTree node - * @param parent DetailNode that will be parent of new node - * @param index child index that has new node - * @return JavadocNodeImpl node on base of ParseTree node. - */ - private JavadocNodeImpl createJavadocNode(ParseTree parseTree, DetailNode parent, int index) { - final JavadocNodeImpl node = new JavadocNodeImpl(); - node.setText(parseTree.getText()); - node.setColumnNumber(getColumn(parseTree)); - node.setLineNumber(getLine(parseTree) + blockCommentAst.getLineNo()); - node.setIndex(index); - node.setType(getTokenType(parseTree)); - node.setParent(parent); - node.setChildren(new JavadocNodeImpl[parseTree.getChildCount()]); - return node; - } - - /** - * Gets next sibling of ParseTree node. - * @param node ParseTree node - * @return next sibling of ParseTree node. - */ - private static ParseTree getNextSibling(ParseTree node) { - ParseTree nextSibling = null; - - if (node.getParent() != null) { - final ParseTree parent = node.getParent(); - final int childCount = parent.getChildCount(); - - int index = 0; - while (true) { - final ParseTree currentNode = parent.getChild(index); - if (currentNode.equals(node)) { - if (index != childCount - 1) { - nextSibling = parent.getChild(index + 1); - } - break; - } - index++; - } - } - return nextSibling; - } - - /** - * Gets token type of ParseTree node from JavadocTokenTypes class. - * @param node ParseTree node. - * @return token type from JavadocTokenTypes - */ - private static int getTokenType(ParseTree node) { - final int tokenType; - - if (node.getChildCount() == 0) { - tokenType = ((TerminalNode) node).getSymbol().getType(); - } - else { - final String className = getNodeClassNameWithoutContext(node); - final String typeName = - CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, className); - tokenType = JavadocUtils.getTokenId(typeName); - } - - return tokenType; - } - - /** - * Gets class name of ParseTree node and removes 'Context' postfix at the - * end. - * @param node - * ParseTree node. - * @return class name without 'Context' - */ - private static String getNodeClassNameWithoutContext(ParseTree node) { - final String className = node.getClass().getSimpleName(); - // remove 'Context' at the end - final int contextLength = 7; - return className.substring(0, className.length() - contextLength); - } - - /** - * Gets line number from ParseTree node. - * @param tree - * ParseTree node - * @return line number - */ - private static int getLine(ParseTree tree) { - if (tree instanceof TerminalNode) { - return ((TerminalNode) tree).getSymbol().getLine() - 1; - } - else { - final ParserRuleContext rule = (ParserRuleContext) tree; - return rule.start.getLine() - 1; - } - } - - /** - * Gets column number from ParseTree node. - * @param tree - * ParseTree node - * @return column number - */ - private static int getColumn(ParseTree tree) { - if (tree instanceof TerminalNode) { - return ((TerminalNode) tree).getSymbol().getCharPositionInLine(); - } - else { - final ParserRuleContext rule = (ParserRuleContext) tree; - return rule.start.getCharPositionInLine(); - } - } - - /** - * Parses block comment content as javadoc comment. - * @param blockComment - * block comment content. - * @return parse tree - */ - private ParseTree parseJavadocAsParseTree(String blockComment) { - final ANTLRInputStream input = new ANTLRInputStream(blockComment); - - final JavadocLexer lexer = new JavadocLexer(input); - - // remove default error listeners - lexer.removeErrorListeners(); - - // add custom error listener that logs parsing errors - lexer.addErrorListener(errorListener); - - final CommonTokenStream tokens = new CommonTokenStream(lexer); - - final JavadocParser parser = new JavadocParser(tokens); - - // remove default error listeners - parser.removeErrorListeners(); - - // add custom error listener that logs syntax errors - parser.addErrorListener(errorListener); - - // This strategy stops parsing when parser error occurs. - // By default it uses Error Recover Strategy which is slow and useless. - parser.setErrorHandler(new BailErrorStrategy()); - - return parser.javadoc(); + return context.get().blockCommentAst; } /** @@ -555,25 +344,25 @@ * the root of tree for process */ private void walk(DetailNode root) { - final int[] defaultTokenTypes = getDefaultJavadocTokens(); - DetailNode curNode = root; while (curNode != null) { - final boolean waitsFor = Ints.contains(defaultTokenTypes, curNode.getType()); + boolean waitsForProcessing = shouldBeProcessed(curNode); - if (waitsFor) { + if (waitsForProcessing) { visitJavadocToken(curNode); } DetailNode toVisit = JavadocUtils.getFirstChild(curNode); while (curNode != null && toVisit == null) { - - if (waitsFor) { + if (waitsForProcessing) { leaveJavadocToken(curNode); } toVisit = JavadocUtils.getNextSibling(curNode); if (toVisit == null) { curNode = curNode.getParent(); + if (curNode != null) { + waitsForProcessing = shouldBeProcessed(curNode); + } } } curNode = toVisit; @@ -581,186 +370,30 @@ } /** - * Custom error listener for JavadocParser that prints user readable errors. + * Checks whether the current node should be processed by the check. + * @param curNode current node. + * @return true if the current node should be processed by the check. */ - private static class DescriptiveErrorListener extends BaseErrorListener { - - /** - * Offset is line number of beginning of the Javadoc comment. Log - * messages should have line number in scope of file, not in scope of - * Javadoc comment. - */ - private int offset; - - /** - * Error message that appeared while parsing. - */ - private ParseErrorMessage errorMessage; - - /** - * Getter for error message during parsing. - * @return Error message during parsing. - */ - private ParseErrorMessage getErrorMessage() { - return errorMessage; - } - - /** - * Sets offset. Offset is line number of beginning of the Javadoc - * comment. Log messages should have line number in scope of file, not - * in scope of Javadoc comment. - * @param offset - * offset line number - */ - public void setOffset(int offset) { - this.offset = offset; - } - - /** - * Logs parser errors in Checkstyle manner. Parser can generate error - * messages. There is special error that parser can generate. It is - * missed close HTML tag. This case is special because parser prints - * error like {@code "no viable alternative at input 'b \n *\n'"} and it - * is not clear that error is about missed close HTML tag. Other error - * messages are not special and logged simply as "Parse Error...". - * - *

    {@inheritDoc} - */ - @Override - public void syntaxError( - Recognizer recognizer, Object offendingSymbol, - int line, int charPositionInLine, - String msg, RecognitionException ex) { - final int lineNumber = offset + line; - final Token token = (Token) offendingSymbol; - - if (MSG_JAVADOC_MISSED_HTML_CLOSE.equals(msg)) { - errorMessage = new ParseErrorMessage(lineNumber, - MSG_JAVADOC_MISSED_HTML_CLOSE, charPositionInLine, token.getText()); - - throw new ParseCancellationException(msg); - } - else if (MSG_JAVADOC_WRONG_SINGLETON_TAG.equals(msg)) { - errorMessage = new ParseErrorMessage(lineNumber, - MSG_JAVADOC_WRONG_SINGLETON_TAG, charPositionInLine, token.getText()); - - throw new ParseCancellationException(msg); - } - else { - final int ruleIndex = ex.getCtx().getRuleIndex(); - final String ruleName = recognizer.getRuleNames()[ruleIndex]; - final String upperCaseRuleName = CaseFormat.UPPER_CAMEL.to( - CaseFormat.UPPER_UNDERSCORE, ruleName); - - errorMessage = new ParseErrorMessage(lineNumber, - MSG_JAVADOC_PARSE_RULE_ERROR, charPositionInLine, msg, upperCaseRuleName); - } - } + private boolean shouldBeProcessed(DetailNode curNode) { + return javadocTokens.contains(curNode.getType()); } /** - * Contains result of parsing javadoc comment: DetailNode tree and parse - * error message. + * The file context holder. */ - private static class ParseStatus { - /** - * DetailNode tree (is null if parsing fails). - */ - private DetailNode tree; - - /** - * Parse error message (is null if parsing is successful). - */ - private ParseErrorMessage parseErrorMessage; - - /** - * Getter for DetailNode tree. - * @return DetailNode tree if parsing was successful, null otherwise. - */ - public DetailNode getTree() { - return tree; - } - - /** - * Sets DetailNode tree. - * @param tree DetailNode tree. - */ - public void setTree(DetailNode tree) { - this.tree = tree; - } + private static class FileContext { /** - * Getter for error message during parsing. - * @return Error message if parsing was unsuccessful, null otherwise. + * Parses content of Javadoc comment as DetailNode tree. */ - public ParseErrorMessage getParseErrorMessage() { - return parseErrorMessage; - } + private final JavadocDetailNodeParser parser = new JavadocDetailNodeParser(); /** - * Sets parse error message. - * @param parseErrorMessage Parse error message. + * DetailAST node of considered Javadoc comment that is just a block comment + * in Java language syntax tree. */ - public void setParseErrorMessage(ParseErrorMessage parseErrorMessage) { - this.parseErrorMessage = parseErrorMessage; - } + private DetailAST blockCommentAst; } - /** - * Contains information about parse error message. - */ - private static class ParseErrorMessage { - /** - * Line number where parse error occurred. - */ - private final int lineNumber; - - /** - * Key for error message. - */ - private final String messageKey; - - /** - * Error message arguments. - */ - private final Object[] messageArguments; - - /** - * Initializes parse error message. - * - * @param lineNumber line number - * @param messageKey message key - * @param messageArguments message arguments - */ - ParseErrorMessage(int lineNumber, String messageKey, Object ... messageArguments) { - this.lineNumber = lineNumber; - this.messageKey = messageKey; - this.messageArguments = messageArguments.clone(); - } - - /** - * Getter for line number where parse error occurred. - * @return Line number where parse error occurred. - */ - public int getLineNumber() { - return lineNumber; - } - - /** - * Getter for key for error message. - * @return Key for error message. - */ - public String getMessageKey() { - return messageKey; - } - - /** - * Getter for error message arguments. - * @return Array of error message arguments. - */ - public Object[] getMessageArguments() { - return messageArguments.clone(); - } - } } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractTypeAwareCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractTypeAwareCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractTypeAwareCheck.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AbstractTypeAwareCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,592 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.javadoc; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.FullIdent; +import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; + +/** + * Abstract class that endeavours to maintain type information for the Java + * file being checked. It provides helper methods for performing type + * information functions. + * + * @author Oliver Burn + * @deprecated Checkstyle is not type aware tool and all Checks derived from this + * class are potentially unstable. + * @noinspection DeprecatedIsStillUsed, AbstractClassWithOnlyOneDirectInheritor + */ +@Deprecated +@FileStatefulCheck +public abstract class AbstractTypeAwareCheck extends AbstractCheck { + + /** Stack of maps for type params. */ + private final Deque> typeParams = new ArrayDeque<>(); + + /** Imports details. **/ + private final Set imports = new HashSet<>(); + + /** Full identifier for package of the method. **/ + private FullIdent packageFullIdent; + + /** Name of current class. */ + private String currentClassName; + + /** {@code ClassResolver} instance for current tree. */ + private ClassResolver classResolver; + + /** + * Whether to log class loading errors to the checkstyle report + * instead of throwing a RTE. + * + *

    Logging errors will avoid stopping checkstyle completely + * because of a typo in javadoc. However, with modern IDEs that + * support automated refactoring and generate javadoc this will + * occur rarely, so by default we assume a configuration problem + * in the checkstyle classpath and throw an exception. + * + *

    This configuration option was triggered by bug 1422462. + */ + private boolean logLoadErrors = true; + + /** + * Whether to show class loading errors in the checkstyle report. + * Request ID 1491630 + */ + private boolean suppressLoadErrors; + + /** + * Called to process an AST when visiting it. + * @param ast the AST to process. Guaranteed to not be PACKAGE_DEF or + * IMPORT tokens. + */ + protected abstract void processAST(DetailAST ast); + + /** + * Logs error if unable to load class information. + * Abstract, should be overridden in subclasses. + * @param ident class name for which we can no load class. + */ + protected abstract void logLoadError(Token ident); + + /** + * Controls whether to log class loading errors to the checkstyle report + * instead of throwing a RTE. + * + * @param logLoadErrors true if errors should be logged + */ + public final void setLogLoadErrors(boolean logLoadErrors) { + this.logLoadErrors = logLoadErrors; + } + + /** + * Controls whether to show class loading errors in the checkstyle report. + * + * @param suppressLoadErrors true if errors shouldn't be shown + */ + public final void setSuppressLoadErrors(boolean suppressLoadErrors) { + this.suppressLoadErrors = suppressLoadErrors; + } + + @Override + public final int[] getRequiredTokens() { + return new int[] { + TokenTypes.PACKAGE_DEF, + TokenTypes.IMPORT, + TokenTypes.CLASS_DEF, + TokenTypes.INTERFACE_DEF, + TokenTypes.ENUM_DEF, + }; + } + + @Override + public void beginTree(DetailAST rootAST) { + packageFullIdent = FullIdent.createFullIdent(null); + imports.clear(); + // add java.lang.* since it's always imported + imports.add("java.lang.*"); + classResolver = null; + currentClassName = ""; + typeParams.clear(); + } + + @Override + public final void visitToken(DetailAST ast) { + if (ast.getType() == TokenTypes.PACKAGE_DEF) { + processPackage(ast); + } + else if (ast.getType() == TokenTypes.IMPORT) { + processImport(ast); + } + else if (ast.getType() == TokenTypes.CLASS_DEF + || ast.getType() == TokenTypes.INTERFACE_DEF + || ast.getType() == TokenTypes.ENUM_DEF) { + processClass(ast); + } + else { + if (ast.getType() == TokenTypes.METHOD_DEF) { + processTypeParams(ast); + } + processAST(ast); + } + } + + @Override + public final void leaveToken(DetailAST ast) { + if (ast.getType() == TokenTypes.CLASS_DEF + || ast.getType() == TokenTypes.INTERFACE_DEF + || ast.getType() == TokenTypes.ENUM_DEF) { + // perhaps it was inner class + int dotIdx = currentClassName.lastIndexOf('$'); + if (dotIdx == -1) { + // perhaps just a class + dotIdx = currentClassName.lastIndexOf('.'); + } + if (dotIdx == -1) { + // looks like a topmost class + currentClassName = ""; + } + else { + currentClassName = currentClassName.substring(0, dotIdx); + } + typeParams.pop(); + } + else if (ast.getType() == TokenTypes.METHOD_DEF) { + typeParams.pop(); + } + } + + /** + * Is exception is unchecked (subclass of {@code RuntimeException} + * or {@code Error}. + * + * @param exception {@code Class} of exception to check + * @return true if exception is unchecked + * false if exception is checked + */ + protected static boolean isUnchecked(Class exception) { + return isSubclass(exception, RuntimeException.class) + || isSubclass(exception, Error.class); + } + + /** + * Checks if one class is subclass of another. + * + * @param child {@code Class} of class + * which should be child + * @param parent {@code Class} of class + * which should be parent + * @return true if aChild is subclass of aParent + * false otherwise + */ + protected static boolean isSubclass(Class child, Class parent) { + return parent != null && child != null + && parent.isAssignableFrom(child); + } + + /** + * Returns the current tree's ClassResolver. + * @return {@code ClassResolver} for current tree. + */ + private ClassResolver getClassResolver() { + if (classResolver == null) { + classResolver = + new ClassResolver(getClassLoader(), + packageFullIdent.getText(), + imports); + } + return classResolver; + } + + /** + * Attempts to resolve the Class for a specified name. + * @param resolvableClassName name of the class to resolve + * @param className name of surrounding class. + * @return the resolved class or {@code null} + * if unable to resolve the class. + * @noinspection WeakerAccess + */ + // -@cs[ForbidWildcardAsReturnType] The class is deprecated and will be removed soon. + protected final Class resolveClass(String resolvableClassName, + String className) { + Class clazz; + try { + clazz = getClassResolver().resolve(resolvableClassName, className); + } + catch (final ClassNotFoundException ignored) { + clazz = null; + } + return clazz; + } + + /** + * Tries to load class. Logs error if unable. + * @param ident name of class which we try to load. + * @param className name of surrounding class. + * @return {@code Class} for a ident. + * @noinspection WeakerAccess + */ + // -@cs[ForbidWildcardAsReturnType] The class is deprecated and will be removed soon. + protected final Class tryLoadClass(Token ident, String className) { + final Class clazz = resolveClass(ident.getText(), className); + if (clazz == null) { + logLoadError(ident); + } + return clazz; + } + + /** + * Common implementation for logLoadError() method. + * @param lineNo line number of the problem. + * @param columnNo column number of the problem. + * @param msgKey message key to use. + * @param values values to fill the message out. + */ + protected final void logLoadErrorImpl(int lineNo, int columnNo, + String msgKey, Object... values) { + if (!logLoadErrors) { + final LocalizedMessage msg = new LocalizedMessage(lineNo, + columnNo, + getMessageBundle(), + msgKey, + values, + getSeverityLevel(), + getId(), + getClass(), + null); + throw new IllegalStateException(msg.getMessage()); + } + + if (!suppressLoadErrors) { + log(lineNo, columnNo, msgKey, values); + } + } + + /** + * Collects the details of a package. + * @param ast node containing the package details + */ + private void processPackage(DetailAST ast) { + final DetailAST nameAST = ast.getLastChild().getPreviousSibling(); + packageFullIdent = FullIdent.createFullIdent(nameAST); + } + + /** + * Collects the details of imports. + * @param ast node containing the import details + */ + private void processImport(DetailAST ast) { + final FullIdent name = FullIdent.createFullIdentBelow(ast); + imports.add(name.getText()); + } + + /** + * Process type params (if any) for given class, enum or method. + * @param ast class, enum or method to process. + */ + private void processTypeParams(DetailAST ast) { + final DetailAST params = + ast.findFirstToken(TokenTypes.TYPE_PARAMETERS); + + final Map paramsMap = new HashMap<>(); + typeParams.push(paramsMap); + + if (params != null) { + for (DetailAST child = params.getFirstChild(); + child != null; + child = child.getNextSibling()) { + if (child.getType() == TokenTypes.TYPE_PARAMETER) { + final DetailAST bounds = + child.findFirstToken(TokenTypes.TYPE_UPPER_BOUNDS); + if (bounds != null) { + final FullIdent name = + FullIdent.createFullIdentBelow(bounds); + final AbstractClassInfo classInfo = + createClassInfo(new Token(name), currentClassName); + final String alias = + child.findFirstToken(TokenTypes.IDENT).getText(); + paramsMap.put(alias, classInfo); + } + } + } + } + } + + /** + * Processes class definition. + * @param ast class definition to process. + */ + private void processClass(DetailAST ast) { + final DetailAST ident = ast.findFirstToken(TokenTypes.IDENT); + String innerClass = ident.getText(); + + if (!currentClassName.isEmpty()) { + innerClass = "$" + innerClass; + } + currentClassName += innerClass; + processTypeParams(ast); + } + + /** + * Returns current class. + * @return name of current class. + */ + protected final String getCurrentClassName() { + return currentClassName; + } + + /** + * Creates class info for given name. + * @param name name of type. + * @param surroundingClass name of surrounding class. + * @return class info for given name. + */ + protected final AbstractClassInfo createClassInfo(final Token name, + final String surroundingClass) { + final AbstractClassInfo result; + final AbstractClassInfo classInfo = findClassAlias(name.getText()); + if (classInfo == null) { + result = new RegularClass(name, surroundingClass, this); + } + else { + result = new ClassAlias(name, classInfo); + } + return result; + } + + /** + * Looking if a given name is alias. + * @param name given name + * @return ClassInfo for alias if it exists, null otherwise + * @noinspection WeakerAccess + */ + protected final AbstractClassInfo findClassAlias(final String name) { + AbstractClassInfo classInfo = null; + final Iterator> iterator = typeParams.descendingIterator(); + while (iterator.hasNext()) { + final Map paramMap = iterator.next(); + classInfo = paramMap.get(name); + if (classInfo != null) { + break; + } + } + return classInfo; + } + + /** + * Contains class's {@code Token}. + * @noinspection ProtectedInnerClass + */ + protected abstract static class AbstractClassInfo { + + /** {@code FullIdent} associated with this class. */ + private final Token name; + + /** + * Creates new instance of class information object. + * @param className token which represents class name. + */ + protected AbstractClassInfo(final Token className) { + if (className == null) { + throw new IllegalArgumentException( + "ClassInfo's name should be non-null"); + } + name = className; + } + + /** + * Returns class associated with that object. + * @return {@code Class} associated with an object. + */ + // -@cs[ForbidWildcardAsReturnType] The class is deprecated and will be removed soon. + public abstract Class getClazz(); + + /** + * Gets class name. + * @return class name + */ + public final Token getName() { + return name; + } + + } + + /** Represents regular classes/enums. */ + private static final class RegularClass extends AbstractClassInfo { + + /** Name of surrounding class. */ + private final String surroundingClass; + /** The check we use to resolve classes. */ + private final AbstractTypeAwareCheck check; + /** Is class loadable. */ + private boolean loadable = true; + /** {@code Class} object of this class if it's loadable. */ + private Class classObj; + + /** + * Creates new instance of of class information object. + * @param name {@code FullIdent} associated with new object. + * @param surroundingClass name of current surrounding class. + * @param check the check we use to load class. + */ + RegularClass(final Token name, + final String surroundingClass, + final AbstractTypeAwareCheck check) { + super(name); + this.surroundingClass = surroundingClass; + this.check = check; + } + + @Override + public Class getClazz() { + if (loadable && classObj == null) { + setClazz(check.tryLoadClass(getName(), surroundingClass)); + } + return classObj; + } + + /** + * Associates {@code Class} with an object. + * @param clazz {@code Class} to associate with. + */ + private void setClazz(Class clazz) { + classObj = clazz; + loadable = clazz != null; + } + + @Override + public String toString() { + return "RegularClass[name=" + getName() + + ", in class='" + surroundingClass + '\'' + + ", check=" + check.hashCode() + + ", loadable=" + loadable + + ", class=" + classObj + + ']'; + } + + } + + /** Represents type param which is "alias" for real type. */ + private static class ClassAlias extends AbstractClassInfo { + + /** Class information associated with the alias. */ + private final AbstractClassInfo classInfo; + + /** + * Creates new instance of the class. + * @param name token which represents name of class alias. + * @param classInfo class information associated with the alias. + */ + ClassAlias(final Token name, AbstractClassInfo classInfo) { + super(name); + this.classInfo = classInfo; + } + + @Override + public final Class getClazz() { + return classInfo.getClazz(); + } + + @Override + public String toString() { + return "ClassAlias[alias " + getName() + " for " + classInfo.getName() + "]"; + } + + } + + /** + * Represents text element with location in the text. + * @noinspection ProtectedInnerClass + */ + protected static class Token { + + /** Token's column number. */ + private final int columnNo; + /** Token's line number. */ + private final int lineNo; + /** Token's text. */ + private final String text; + + /** + * Creates token. + * @param text token's text + * @param lineNo token's line number + * @param columnNo token's column number + */ + public Token(String text, int lineNo, int columnNo) { + this.text = text; + this.lineNo = lineNo; + this.columnNo = columnNo; + } + + /** + * Converts FullIdent to Token. + * @param fullIdent full ident to convert. + */ + public Token(FullIdent fullIdent) { + text = fullIdent.getText(); + lineNo = fullIdent.getLineNo(); + columnNo = fullIdent.getColumnNo(); + } + + /** + * Gets line number of the token. + * @return line number of the token + */ + public int getLineNo() { + return lineNo; + } + + /** + * Gets column number of the token. + * @return column number of the token + */ + public int getColumnNo() { + return columnNo; + } + + /** + * Gets text of the token. + * @return text of the token + */ + public String getText() { + return text; + } + + @Override + public String toString() { + return "Token[" + text + "(" + lineNo + + "x" + columnNo + ")]"; + } + + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AtclauseOrderCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AtclauseOrderCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AtclauseOrderCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/AtclauseOrderCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -32,7 +32,12 @@ /** *

    - * Checks the order of at-clauses. + * Checks the order of + * + * javadoc block-tags or javadoc tags. + *

    + *

    + * Note: Google used term "at-clauses" for block tags in his guide till 2017-02-28. *

    * *

    @@ -70,8 +75,6 @@ */ public static final String MSG_KEY = "at.clause.order"; - /** Comma literal. */ - private static final String COMMA_SEPARATOR = ","; /** * Default order of atclauses. */ @@ -103,26 +106,24 @@ /** * Sets custom targets. - * @param target user's targets. + * @param targets user's targets. */ - public void setTarget(String target) { + public void setTarget(String... targets) { final List customTarget = new ArrayList<>(); - final String[] sTarget = target.split(COMMA_SEPARATOR); - for (String aSTarget : sTarget) { - customTarget.add(TokenUtils.getTokenId(aSTarget.trim())); + for (String temp : targets) { + customTarget.add(TokenUtils.getTokenId(temp.trim())); } - this.target = customTarget; + target = customTarget; } /** * Sets custom order of atclauses. - * @param order user's order. + * @param orders user's orders. */ - public void setTagOrder(String order) { + public void setTagOrder(String... orders) { final List customOrder = new ArrayList<>(); - final String[] sOrder = order.split(COMMA_SEPARATOR); - for (String aSOrder : sOrder) { - customOrder.add(aSOrder.trim()); + for (String order : orders) { + customOrder.add(order.trim()); } tagOrder = customOrder; } @@ -135,13 +136,8 @@ } @Override - public int[] getAcceptableTokens() { - return new int[] {TokenTypes.BLOCK_COMMENT_BEGIN}; - } - - @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); + public int[] getRequiredJavadocTokens() { + return getAcceptableJavadocTokens(); } @Override @@ -190,4 +186,5 @@ } return type; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/ClassResolver.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/ClassResolver.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/ClassResolver.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/ClassResolver.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,247 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.javadoc; + +import java.util.HashSet; +import java.util.Set; + +/** + * Utility class to resolve a class name to an actual class. Note that loaded + * classes are not initialized. + *

    Limitations: this does not handle inner classes very well.

    + * + * @author Oliver Burn + */ +public class ClassResolver { + + /** Period literal. */ + private static final String PERIOD = "."; + /** Dollar sign literal. */ + private static final String DOLLAR_SIGN = "$"; + + /** Name of the package to check if the class belongs to. **/ + private final String pkg; + /** Set of imports to check against. **/ + private final Set imports; + /** Use to load classes. **/ + private final ClassLoader loader; + + /** + * Creates a new {@code ClassResolver} instance. + * + * @param loader the ClassLoader to load classes with. + * @param pkg the name of the package the class may belong to + * @param imports set of imports to check if the class belongs to + */ + public ClassResolver(ClassLoader loader, String pkg, Set imports) { + this.loader = loader; + this.pkg = pkg; + this.imports = new HashSet<>(imports); + this.imports.add("java.lang.*"); + } + + /** + * Attempts to resolve the Class for a specified name. The algorithm is + * to check: + * - fully qualified name + * - explicit imports + * - enclosing package + * - star imports + * @param name name of the class to resolve + * @param currentClass name of current class (for inner classes). + * @return the resolved class + * @throws ClassNotFoundException if unable to resolve the class + */ + // -@cs[ForbidWildcardAsReturnType] This method can return any type, so no way to avoid wildcard + public Class resolve(String name, String currentClass) + throws ClassNotFoundException { + // See if the class is full qualified + Class clazz = resolveQualifiedName(name); + if (clazz == null) { + // try matching explicit imports + clazz = resolveMatchingExplicitImport(name); + + if (clazz == null) { + // See if in the package + clazz = resolveInPackage(name); + + if (clazz == null) { + // see if inner class of this class + clazz = resolveInnerClass(name, currentClass); + + if (clazz == null) { + clazz = resolveByStarImports(name); + // -@cs[NestedIfDepth] it is better to have single return point from method + if (clazz == null) { + // Giving up, the type is unknown, so load the class to generate an + // exception + clazz = safeLoad(name); + } + } + } + } + } + return clazz; + } + + /** + * Try to find class by search in package. + * @param name class name + * @return class object + */ + private Class resolveInPackage(String name) { + Class clazz = null; + if (pkg != null && !pkg.isEmpty()) { + final Class classFromQualifiedName = resolveQualifiedName(pkg + PERIOD + name); + if (classFromQualifiedName != null) { + clazz = classFromQualifiedName; + } + } + return clazz; + } + + /** + * Try to find class by matching explicit Import. + * @param name class name + * @return class object + */ + private Class resolveMatchingExplicitImport(String name) { + Class clazz = null; + for (String imp : imports) { + // Very important to add the "." in the check below. Otherwise you + // when checking for "DataException", it will match on + // "SecurityDataException". This has been the cause of a very + // difficult bug to resolve! + if (imp.endsWith(PERIOD + name)) { + clazz = resolveQualifiedName(imp); + if (clazz != null) { + break; + } + } + } + return clazz; + } + + /** + * See if inner class of this class. + * @param name name of the search Class to search + * @param currentClass class where search in + * @return class if found , or null if not resolved + * @throws ClassNotFoundException if an error occurs + */ + private Class resolveInnerClass(String name, String currentClass) + throws ClassNotFoundException { + Class clazz = null; + if (!currentClass.isEmpty()) { + String innerClass = currentClass + DOLLAR_SIGN + name; + + if (!pkg.isEmpty()) { + innerClass = pkg + PERIOD + innerClass; + } + + if (isLoadable(innerClass)) { + clazz = safeLoad(innerClass); + } + } + return clazz; + } + + /** + * Try star imports. + * @param name name of the Class to search + * @return class if found , or null if not resolved + */ + private Class resolveByStarImports(String name) { + Class clazz = null; + for (String imp : imports) { + if (imp.endsWith(".*")) { + final String fqn = imp.substring(0, imp.lastIndexOf('.') + 1) + name; + clazz = resolveQualifiedName(fqn); + if (clazz != null) { + break; + } + } + } + return clazz; + } + + /** + * Checks if the given class name can be loaded. + * @param name name of the class to check + * @return whether a specified class is loadable with safeLoad(). + */ + public boolean isLoadable(String name) { + boolean result; + try { + safeLoad(name); + result = true; + } + catch (final ClassNotFoundException | NoClassDefFoundError ignored) { + result = false; + } + return result; + } + + /** + * Will load a specified class is such a way that it will NOT be + * initialised. + * @param name name of the class to load + * @return the {@code Class} for the specified class + * @throws ClassNotFoundException if an error occurs + * @throws NoClassDefFoundError if an error occurs + */ + // -@cs[ForbidWildcardAsReturnType] The class is deprecated and will be removed soon. + private Class safeLoad(String name) throws ClassNotFoundException, NoClassDefFoundError { + // The next line will load the class using the specified class + // loader. The magic is having the "false" parameter. This means the + // class will not be initialised. Very, very important. + return Class.forName(name, false, loader); + } + + /** + * Tries to resolve a class for fully-specified name. + * @param name a given name of class. + * @return Class object for the given name or null. + */ + private Class resolveQualifiedName(final String name) { + Class classObj = null; + try { + if (isLoadable(name)) { + classObj = safeLoad(name); + } + else { + //Perhaps it's fully-qualified inner class + final int dot = name.lastIndexOf('.'); + if (dot != -1) { + final String innerName = + name.substring(0, dot) + DOLLAR_SIGN + name.substring(dot + 1); + classObj = resolveQualifiedName(innerName); + } + } + } + catch (final ClassNotFoundException ex) { + // we shouldn't get this exception here, + // so this is unexpected runtime exception + throw new IllegalStateException(ex); + } + return classObj; + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/HtmlTag.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/HtmlTag.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/HtmlTag.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/HtmlTag.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,6 +25,7 @@ * @author Chris Stillwell */ class HtmlTag { + /** The maximum length of text to display with this tag. */ private static final int MAX_TEXT_LEN = 60; @@ -117,9 +118,22 @@ @Override public String toString() { + return "HtmlTag[id='" + id + '\'' + + ", lineNo=" + lineNo + + ", position=" + position + + ", text='" + text + '\'' + + ", closedTag=" + closedTag + + ", incompleteTag=" + incompleteTag + ']'; + } + + /** + * Returns the comment line of text where this tag appears. + * @return text of the tag + */ + public String getText() { final int startOfText = position; - final int endOfText = - Math.min(startOfText + MAX_TEXT_LEN, text.length()); + final int endOfText = Math.min(startOfText + MAX_TEXT_LEN, text.length()); return text.substring(startOfText, endOfText); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/InvalidJavadocTag.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/InvalidJavadocTag.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/InvalidJavadocTag.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/InvalidJavadocTag.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,6 +24,7 @@ * @author Oliver Burn */ public final class InvalidJavadocTag { + /** The line in which the invalid tag occurs. */ private final int line; /** The column in which the invalid tag occurs. */ @@ -66,4 +67,5 @@ public String getName() { return name; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocMethodCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocMethodCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocMethodCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocMethodCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,7 +20,9 @@ package com.puppycrawl.tools.checkstyle.checks.javadoc; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.ListIterator; @@ -28,15 +30,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.Scope; import com.puppycrawl.tools.checkstyle.api.TextBlock; import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.checks.AbstractTypeAwareCheck; import com.puppycrawl.tools.checkstyle.utils.CheckUtils; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; @@ -47,8 +46,9 @@ * @author Oliver Burn * @author Rick Giles * @author o_sukhodoslky + * + * @noinspection deprecation */ -@SuppressWarnings("deprecation") public class JavadocMethodCheck extends AbstractTypeAwareCheck { /** @@ -100,12 +100,12 @@ public static final String MSG_DUPLICATE_TAG = "javadoc.duplicateTag"; /** Compiled regexp to match Javadoc tags that take an argument. */ - private static final Pattern MATCH_JAVADOC_ARG = - CommonUtils.createPattern("@(throws|exception|param)\\s+(\\S+)\\s+\\S*"); + private static final Pattern MATCH_JAVADOC_ARG = CommonUtils.createPattern( + "^\\s*(?>\\*|\\/\\*\\*)?\\s*@(throws|exception|param)\\s+(\\S+)\\s+\\S*"); /** Compiled regexp to match first part of multilineJavadoc tags. */ - private static final Pattern MATCH_JAVADOC_ARG_MULTILINE_START = - CommonUtils.createPattern("@(throws|exception|param)\\s+(\\S+)\\s*$"); + private static final Pattern MATCH_JAVADOC_ARG_MULTILINE_START = CommonUtils.createPattern( + "^\\s*(?>\\*|\\/\\*\\*)?\\s*@(throws|exception|param)\\s+(\\S+)\\s*$"); /** Compiled regexp to look for a continuation of the comment. */ private static final Pattern MATCH_JAVADOC_MULTILINE_CONT = @@ -118,15 +118,15 @@ /** Compiled regexp to match Javadoc tags with no argument. */ private static final Pattern MATCH_JAVADOC_NOARG = - CommonUtils.createPattern("@(return|see)\\s+\\S"); + CommonUtils.createPattern("^\\s*(?>\\*|\\/\\*\\*)?\\s*@(return|see)\\s+\\S"); /** Compiled regexp to match first part of multilineJavadoc tags. */ private static final Pattern MATCH_JAVADOC_NOARG_MULTILINE_START = - CommonUtils.createPattern("@(return|see)\\s*$"); + CommonUtils.createPattern("^\\s*(?>\\*|\\/\\*\\*)?\\s*@(return|see)\\s*$"); /** Compiled regexp to match Javadoc tags with no argument and {}. */ private static final Pattern MATCH_JAVADOC_NOARG_CURLY = CommonUtils.createPattern("\\{\\s*@(inheritDoc)\\s*\\}"); - /** Default value of minimal amount of lines in method to demand documentation presence.*/ + /** Default value of minimal amount of lines in method to allow no documentation.*/ private static final int DEFAULT_MIN_LINE_COUNT = -1; /** The visibility scope where Javadoc comments are checked. */ @@ -135,13 +135,15 @@ /** The visibility scope where Javadoc comments shouldn't be checked. */ private Scope excludeScope; - /** Minimal amount of lines in method to demand documentation presence.*/ + /** Minimal amount of lines in method to allow no documentation.*/ private int minLineCount = DEFAULT_MIN_LINE_COUNT; /** * Controls whether to allow documented exceptions that are not declared if * they are a subclass of java.lang.RuntimeException. */ + // -@cs[AbbreviationAsWordInName] We can not change it as, + // check's property is part of API (used in configurations). private boolean allowUndeclaredRTE; /** @@ -194,14 +196,14 @@ /** * Set regex for matching method names to ignore. - * @param regex regex for matching method names. + * @param pattern a pattern. */ - public void setIgnoreMethodNamesRegex(String regex) { - ignoreMethodNamesRegex = CommonUtils.createPattern(regex); + public void setIgnoreMethodNamesRegex(Pattern pattern) { + ignoreMethodNamesRegex = pattern; } /** - * Sets minimal amount of lines in method. + * Sets minimal amount of lines in method to allow no documentation. * @param value user's value. */ public void setMinLineCount(int value) { @@ -220,33 +222,26 @@ * Sets list of annotations. * @param userAnnotations user's value. */ - public void setAllowedAnnotations(String userAnnotations) { - final List annotations = new ArrayList<>(); - final String[] sAnnotations = userAnnotations.split(","); - for (int i = 0; i < sAnnotations.length; i++) { - sAnnotations[i] = sAnnotations[i].trim(); - } - - Collections.addAll(annotations, sAnnotations); - allowedAnnotations = annotations; + public void setAllowedAnnotations(String... userAnnotations) { + allowedAnnotations = Arrays.asList(userAnnotations); } /** * Set the scope. * - * @param from a {@code String} value + * @param scope a scope. */ - public void setScope(String from) { - scope = Scope.getInstance(from); + public void setScope(Scope scope) { + this.scope = scope; } /** * Set the excludeScope. * - * @param excludeScope a {@code String} value + * @param excludeScope a scope. */ - public void setExcludeScope(String excludeScope) { - this.excludeScope = Scope.getInstance(excludeScope); + public void setExcludeScope(Scope excludeScope) { + this.excludeScope = excludeScope; } /** @@ -255,6 +250,8 @@ * * @param flag a {@code Boolean} value */ + // -@cs[AbbreviationAsWordInName] We can not change it as, + // check's property is part of API (used in configurations). public void setAllowUndeclaredRTE(boolean flag) { allowUndeclaredRTE = flag; } @@ -368,6 +365,7 @@ * @return Some javadoc. */ private boolean hasAllowedAnnotations(DetailAST methodDef) { + boolean result = false; final DetailAST modifiersNode = methodDef.findFirstToken(TokenTypes.MODIFIERS); DetailAST annotationNode = modifiersNode.findFirstToken(TokenTypes.ANNOTATION); while (annotationNode != null && annotationNode.getType() == TokenTypes.ANNOTATION) { @@ -377,11 +375,12 @@ .findFirstToken(TokenTypes.IDENT); } if (allowedAnnotations.contains(identNode.getText())) { - return true; + result = true; + break; } annotationNode = annotationNode.getNextSibling(); } - return false; + return result; } /** @@ -421,7 +420,7 @@ * @param ast the tree node for the method or constructor. * @return True if this method or constructor doesn't need Javadoc. */ - protected boolean isMissingJavadocAllowed(final DetailAST ast) { + private boolean isMissingJavadocAllowed(final DetailAST ast) { return allowMissingJavadoc || allowMissingPropertyJavadoc && (CheckUtils.isSetterMethod(ast) || CheckUtils.isGetterMethod(ast)) @@ -448,16 +447,17 @@ * @return true if given method name matches the regex. */ private boolean matchesSkipRegex(DetailAST methodDef) { + boolean result = false; if (ignoreMethodNamesRegex != null) { final DetailAST ident = methodDef.findFirstToken(TokenTypes.IDENT); final String methodName = ident.getText(); final Matcher matcher = ignoreMethodNamesRegex.matcher(methodName); if (matcher.matches()) { - return true; + result = true; } } - return false; + return result; } /** @@ -486,33 +486,29 @@ private void checkComment(DetailAST ast, TextBlock comment) { final List tags = getMethodTags(comment); - if (hasShortCircuitTag(ast, tags)) { - return; - } - - final Iterator it = tags.iterator(); - if (ast.getType() == TokenTypes.ANNOTATION_FIELD_DEF) { - checkReturnTag(tags, ast.getLineNo(), true); - } - else { - // Check for inheritDoc - boolean hasInheritDocTag = false; - while (!hasInheritDocTag && it.hasNext()) { - hasInheritDocTag = it.next().isInheritDocTag(); + if (!hasShortCircuitTag(ast, tags)) { + if (ast.getType() == TokenTypes.ANNOTATION_FIELD_DEF) { + checkReturnTag(tags, ast.getLineNo(), true); } + else { + final Iterator it = tags.iterator(); + // Check for inheritDoc + boolean hasInheritDocTag = false; + while (!hasInheritDocTag && it.hasNext()) { + hasInheritDocTag = it.next().isInheritDocTag(); + } + final boolean reportExpectedTags = !hasInheritDocTag && !hasAllowedAnnotations(ast); - checkParamTags(tags, ast, !hasInheritDocTag); - checkThrowsTags(tags, getThrows(ast), !hasInheritDocTag); - if (CheckUtils.isNonVoidMethod(ast)) { - checkReturnTag(tags, ast.getLineNo(), !hasInheritDocTag); + checkParamTags(tags, ast, reportExpectedTags); + checkThrowsTags(tags, getThrows(ast), reportExpectedTags); + if (CheckUtils.isNonVoidMethod(ast)) { + checkReturnTag(tags, ast.getLineNo(), reportExpectedTags); + } } - } - // Dump out all unused tags - for (JavadocTag javadocTag : tags) { - if (!javadocTag.isSeeOrInheritDocTag()) { - log(javadocTag.getLineNo(), MSG_UNUSED_TAG_GENERAL); - } + // Dump out all unused tags + tags.stream().filter(javadocTag -> !javadocTag.isSeeOrInheritDocTag()) + .forEach(javadocTag -> log(javadocTag.getLineNo(), MSG_UNUSED_TAG_GENERAL)); } } @@ -524,20 +520,20 @@ * @param tags the list of Javadoc tags associated with the construct * @return true if the construct has a short circuit tag. */ - private boolean hasShortCircuitTag(final DetailAST ast, - final List tags) { + private boolean hasShortCircuitTag(final DetailAST ast, final List tags) { + boolean result = true; // Check if it contains {@inheritDoc} tag - if (tags.size() != 1 - || !tags.get(0).isInheritDocTag()) { - return false; + if (tags.size() == 1 + && tags.get(0).isInheritDocTag()) { + // Invalid if private, a constructor, or a static method + if (!JavadocTagInfo.INHERIT_DOC.isValidOn(ast)) { + log(ast, MSG_INVALID_INHERIT_DOC); + } } - - // Invalid if private, a constructor, or a static method - if (!JavadocTagInfo.INHERIT_DOC.isValidOn(ast)) { - log(ast, MSG_INVALID_INHERIT_DOC); + else { + result = false; } - - return true; + return result; } /** @@ -549,15 +545,16 @@ * @return the scope of the method/constructor */ private static Scope calculateScope(final DetailAST ast) { - final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS); - final Scope declaredScope = ScopeUtils.getScopeFromMods(mods); + final Scope scope; if (ScopeUtils.isInInterfaceOrAnnotationBlock(ast)) { - return Scope.PUBLIC; + scope = Scope.PUBLIC; } else { - return declaredScope; + final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS); + scope = ScopeUtils.getScopeFromMods(mods); } + return scope; } /** @@ -569,7 +566,7 @@ */ private static List getMethodTags(TextBlock comment) { final String[] lines = comment.getText(); - final List tags = Lists.newArrayList(); + final List tags = new ArrayList<>(); int currentLine = comment.getStartLineNo() - 1; final int startColumnNumber = comment.getStartColNo(); @@ -695,13 +692,15 @@ */ private static List getParameters(DetailAST ast) { final DetailAST params = ast.findFirstToken(TokenTypes.PARAMETERS); - final List returnValue = Lists.newArrayList(); + final List returnValue = new ArrayList<>(); DetailAST child = params.getFirstChild(); while (child != null) { if (child.getType() == TokenTypes.PARAMETER_DEF) { final DetailAST ident = child.findFirstToken(TokenTypes.IDENT); - returnValue.add(ident); + if (ident != null) { + returnValue.add(ident); + } } child = child.getNextSibling(); } @@ -715,7 +714,7 @@ * @return the list of exception nodes for ast. */ private List getThrows(DetailAST ast) { - final List returnValue = Lists.newArrayList(); + final List returnValue = new ArrayList<>(); final DetailAST throwsAST = ast .findFirstToken(TokenTypes.LITERAL_THROWS); if (throwsAST != null) { @@ -765,7 +764,6 @@ if (CommonUtils.startsWithChar(arg1, '<') && CommonUtils.endsWithChar(arg1, '>')) { found = searchMatchingTypeParameter(typeParams, arg1.substring(1, arg1.length() - 1)); - } // Handle extra JavadocTag @@ -884,7 +882,7 @@ List throwsList, boolean reportExpectedTags) { // Loop over the tags, checking to see they exist in the throws. // The foundThrows used for performance only - final Set foundThrows = Sets.newHashSet(); + final Set foundThrows = new HashSet<>(); final ListIterator tagIt = tags.listIterator(); while (tagIt.hasNext()) { final JavadocTag tag = tagIt.next(); @@ -914,21 +912,19 @@ log(tag.getLineNo(), tag.getColumnNo(), MSG_UNUSED_TAG, JavadocTagInfo.THROWS.getText(), tag.getFirstArg()); - } } } // Now dump out all throws without tags :- unless // the user has chosen to suppress these problems if (!allowMissingThrowsTags && reportExpectedTags) { - for (ExceptionInfo exceptionInfo : throwsList) { - if (!exceptionInfo.isFound()) { + throwsList.stream().filter(exceptionInfo -> !exceptionInfo.isFound()) + .forEach(exceptionInfo -> { final Token token = exceptionInfo.getName(); log(token.getLineNo(), token.getColumnNo(), - MSG_EXPECTED_TAG, - JavadocTagInfo.THROWS.getText(), token.getText()); - } - } + MSG_EXPECTED_TAG, + JavadocTagInfo.THROWS.getText(), token.getText()); + }); } } @@ -946,14 +942,12 @@ ExceptionInfo foundException = null; // First look for matches on the exception name - final ListIterator throwIt = throwsList.listIterator(); - while (!found && throwIt.hasNext()) { - final ExceptionInfo exceptionInfo = throwIt.next(); - + for (ExceptionInfo exceptionInfo : throwsList) { if (exceptionInfo.getName().getText().equals( documentedClassInfo.getName().getText())) { found = true; foundException = exceptionInfo; + break; } } @@ -981,6 +975,7 @@ /** Stores useful information about declared exception. */ private static class ExceptionInfo { + /** Class information associated with this exception. */ private final AbstractClassInfo classInfo; /** Does the exception have throws tag associated with. */ @@ -1023,5 +1018,7 @@ private Class getClazz() { return classInfo.getClazz(); } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocNodeImpl.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocNodeImpl.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocNodeImpl.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocNodeImpl.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,6 +20,7 @@ package com.puppycrawl.tools.checkstyle.checks.javadoc; import java.util.Arrays; +import java.util.Objects; import com.puppycrawl.tools.checkstyle.api.DetailNode; import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; @@ -35,7 +36,7 @@ /** * Empty array of {@link DetailNode} type. */ - private static final DetailNode[] EMPTY_DETAIL_NODE_ARRAY = new DetailNode[0]; + public static final JavadocNodeImpl[] EMPTY_DETAIL_NODE_ARRAY = new JavadocNodeImpl[0]; /** * Node index among parent's children. @@ -94,12 +95,11 @@ @Override public DetailNode[] getChildren() { - if (children == null) { - return EMPTY_DETAIL_NODE_ARRAY; - } - else { - return Arrays.copyOf(children, children.length); + DetailNode[] nodeChildren = EMPTY_DETAIL_NODE_ARRAY; + if (children != null) { + nodeChildren = Arrays.copyOf(children, children.length); } + return nodeChildren; } @Override @@ -170,7 +170,14 @@ @Override public String toString() { - return JavadocUtils.getTokenName(type) - + "[" + lineNumber + "x" + columnNumber + "]"; + return "JavadocNodeImpl[" + + "index=" + index + + ", type=" + JavadocUtils.getTokenName(type) + + ", text='" + text + '\'' + + ", lineNumber=" + lineNumber + + ", columnNumber=" + columnNumber + + ", children=" + Objects.hashCode(children) + + ", parent=" + parent + ']'; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocPackageCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocPackageCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocPackageCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocPackageCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,11 +20,13 @@ package com.puppycrawl.tools.checkstyle.checks.javadoc; import java.io.File; -import java.util.List; +import java.io.IOException; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; -import com.google.common.collect.Sets; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.FileText; /** * Checks that all packages have a package documentation. See the documentation @@ -46,7 +48,7 @@ public static final String MSG_PACKAGE_INFO = "javadoc.packageInfo"; /** The directories checked. */ - private final Set directoriesChecked = Sets.newHashSet(); + private final Set directoriesChecked = ConcurrentHashMap.newKeySet(); /** Indicates if allow legacy "package.html" file to be used. */ private boolean allowLegacy; @@ -67,25 +69,30 @@ } @Override - protected void processFiltered(File file, List lines) { + protected void processFiltered(File file, FileText fileText) throws CheckstyleException { // Check if already processed directory - final File dir = file.getParentFile(); - if (directoriesChecked.contains(dir)) { - return; + final File dir; + try { + dir = file.getCanonicalFile().getParentFile(); } - directoriesChecked.add(dir); - - // Check for the preferred file. - final File packageInfo = new File(dir, "package-info.java"); - final File packageHtml = new File(dir, "package.html"); - - if (packageInfo.exists()) { - if (packageHtml.exists()) { - log(0, MSG_LEGACY_PACKAGE_HTML); - } + catch (IOException ex) { + throw new CheckstyleException( + "Exception while getting canonical path to file " + file.getPath(), ex); } - else if (!allowLegacy || !packageHtml.exists()) { - log(0, MSG_PACKAGE_INFO); + final boolean isDirChecked = !directoriesChecked.add(dir); + if (!isDirChecked) { + // Check for the preferred file. + final File packageInfo = new File(dir, "package-info.java"); + final File packageHtml = new File(dir, "package.html"); + + if (packageInfo.exists()) { + if (packageHtml.exists()) { + log(0, MSG_LEGACY_PACKAGE_HTML); + } + } + else if (!allowLegacy || !packageHtml.exists()) { + log(0, MSG_PACKAGE_INFO); + } } } @@ -97,4 +104,5 @@ public void setAllowLegacy(boolean allowLegacy) { this.allowLegacy = allowLegacy; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocParagraphCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocParagraphCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocParagraphCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocParagraphCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,7 +21,6 @@ import com.puppycrawl.tools.checkstyle.api.DetailNode; import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; @@ -120,13 +119,8 @@ } @Override - public int[] getAcceptableTokens() { - return new int[] {TokenTypes.BLOCK_COMMENT_BEGIN}; - } - - @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); + public int[] getRequiredJavadocTokens() { + return getAcceptableJavadocTokens(); } @Override @@ -135,7 +129,7 @@ checkEmptyLine(ast); } else if (ast.getType() == JavadocTokenTypes.HTML_ELEMENT - && JavadocUtils.getFirstChild(ast).getType() == JavadocTokenTypes.P_TAG_OPEN) { + && JavadocUtils.getFirstChild(ast).getType() == JavadocTokenTypes.P_TAG_START) { checkParagraphTag(ast); } } @@ -146,7 +140,8 @@ */ private void checkEmptyLine(DetailNode newline) { final DetailNode nearestToken = getNearestNode(newline); - if (!isLastEmptyLine(newline) && nearestToken.getChildren().length > 1) { + if (!isLastEmptyLine(newline) && nearestToken.getType() == JavadocTokenTypes.TEXT + && !CommonUtils.isBlank(nearestToken.getText())) { log(newline.getLineNumber(), MSG_TAG_AFTER); } } @@ -188,17 +183,18 @@ * @return true, if line is empty line. */ private static boolean isEmptyLine(DetailNode newLine) { + boolean result = false; DetailNode previousSibling = JavadocUtils.getPreviousSibling(newLine); - if (previousSibling == null - || previousSibling.getParent().getType() != JavadocTokenTypes.JAVADOC) { - return false; - } - if (previousSibling.getType() == JavadocTokenTypes.TEXT - && previousSibling.getChildren().length == 1) { - previousSibling = JavadocUtils.getPreviousSibling(previousSibling); + if (previousSibling != null + && previousSibling.getParent().getType() == JavadocTokenTypes.JAVADOC) { + if (previousSibling.getType() == JavadocTokenTypes.TEXT + && CommonUtils.isBlank(previousSibling.getText())) { + previousSibling = JavadocUtils.getPreviousSibling(previousSibling); + } + result = previousSibling != null + && previousSibling.getType() == JavadocTokenTypes.LEADING_ASTERISK; } - return previousSibling != null - && previousSibling.getType() == JavadocTokenTypes.LEADING_ASTERISK; + return result; } /** @@ -207,18 +203,20 @@ * @return true, if line with paragraph tag is first line in javadoc. */ private static boolean isFirstParagraph(DetailNode paragraphTag) { + boolean result = true; DetailNode previousNode = JavadocUtils.getPreviousSibling(paragraphTag); while (previousNode != null) { if (previousNode.getType() == JavadocTokenTypes.TEXT - && previousNode.getChildren().length > 1 + && !CommonUtils.isBlank(previousNode.getText()) || previousNode.getType() != JavadocTokenTypes.LEADING_ASTERISK && previousNode.getType() != JavadocTokenTypes.NEWLINE && previousNode.getType() != JavadocTokenTypes.TEXT) { - return false; + result = false; + break; } previousNode = JavadocUtils.getPreviousSibling(previousNode); } - return true; + return result; } /** @@ -244,16 +242,18 @@ * @return true, if NEWLINE node is a last node in javadoc. */ private static boolean isLastEmptyLine(DetailNode newLine) { + boolean result = true; DetailNode nextNode = JavadocUtils.getNextSibling(newLine); while (nextNode != null && nextNode.getType() != JavadocTokenTypes.JAVADOC_TAG) { if (nextNode.getType() == JavadocTokenTypes.TEXT - && nextNode.getChildren().length > 1 + && !CommonUtils.isBlank(nextNode.getText()) || nextNode.getType() == JavadocTokenTypes.HTML_ELEMENT) { - return false; + result = false; + break; } nextNode = JavadocUtils.getNextSibling(nextNode); } - return true; + return result; } /** @@ -267,4 +267,5 @@ || nextSibling.getType() == JavadocTokenTypes.EOF || CommonUtils.startsWithChar(nextSibling.getText(), ' '); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocStyleCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocStyleCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocStyleCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocStyleCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,22 +20,26 @@ package com.puppycrawl.tools.checkstyle.checks.javadoc; import java.util.ArrayDeque; +import java.util.Arrays; +import java.util.Collections; import java.util.Deque; import java.util.List; import java.util.Locale; import java.util.Set; +import java.util.TreeSet; import java.util.regex.Pattern; +import java.util.stream.Collectors; -import org.apache.commons.lang3.ArrayUtils; - -import com.google.common.collect.ImmutableSortedSet; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.Scope; import com.puppycrawl.tools.checkstyle.api.TextBlock; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CheckUtils; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; /** @@ -45,8 +49,9 @@ * @author Daniel Grenner * @author Travis Schneeberger */ +@StatelessCheck public class JavadocStyleCheck - extends Check { + extends AbstractCheck { /** Message property key for the Unclosed HTML message. */ public static final String MSG_JAVADOC_MISSING = "javadoc.missing"; @@ -61,27 +66,30 @@ public static final String MSG_INCOMPLETE_TAG = "javadoc.incompleteTag"; /** Message property key for the Unclosed HTML message. */ - public static final String MSG_UNCLOSED_HTML = "javadoc.unclosedHtml"; + public static final String MSG_UNCLOSED_HTML = JavadocDetailNodeParser.MSG_UNCLOSED_HTML_TAG; /** Message property key for the Extra HTML message. */ public static final String MSG_EXTRA_HTML = "javadoc.extraHtml"; /** HTML tags that do not require a close tag. */ - private static final Set SINGLE_TAGS = ImmutableSortedSet.of( - "br", "li", "dt", "dd", "hr", "img", "p", "td", "tr", "th"); + private static final Set SINGLE_TAGS = Collections.unmodifiableSortedSet( + Arrays.stream(new String[] {"br", "li", "dt", "dd", "hr", "img", "p", "td", "tr", "th", }) + .collect(Collectors.toCollection(TreeSet::new))); /** HTML tags that are allowed in java docs. - * From http://www.w3schools.com/tags/default.asp + * From https://www.w3schools.com/tags/default.asp * The forms and structure tags are not allowed */ - private static final Set ALLOWED_TAGS = ImmutableSortedSet.of( + private static final Set ALLOWED_TAGS = Collections.unmodifiableSortedSet( + Arrays.stream(new String[] { "a", "abbr", "acronym", "address", "area", "b", "bdo", "big", "blockquote", "br", "caption", "cite", "code", "colgroup", "dd", "del", "div", "dfn", "dl", "dt", "em", "fieldset", "font", "h1", "h2", "h3", "h4", "h5", "h6", "hr", "i", "img", "ins", "kbd", "li", "ol", "p", "pre", "q", "samp", "small", "span", "strong", "style", "sub", "sup", "table", "tbody", "td", "tfoot", "th", - "thead", "tr", "tt", "u", "ul"); + "thead", "tr", "tt", "u", "ul", "var", }) + .collect(Collectors.toCollection(TreeSet::new))); /** The scope to check. */ private Scope scope = Scope.PRIVATE; @@ -90,10 +98,7 @@ private Scope excludeScope; /** Format for matching the end of a sentence. */ - private String endOfSentenceFormat = "([.?!][ \t\n\r\f<])|([.?!]$)"; - - /** Regular expression for matching the end of a sentence. */ - private Pattern endOfSentencePattern; + private Pattern endOfSentenceFormat = Pattern.compile("([.?!][ \t\n\r\f<])|([.?!]$)"); /** * Indicates if the first sentence should be checked for proper end of @@ -134,7 +139,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -202,19 +207,19 @@ if (getFileContents().inPackageInfo()) { log(ast.getLineNo(), MSG_JAVADOC_MISSING); } - return; - } - - if (checkFirstSentence) { - checkFirstSentenceEnding(ast, comment); } + else { + if (checkFirstSentence) { + checkFirstSentenceEnding(ast, comment); + } - if (checkHtml) { - checkHtmlTags(ast, comment); - } + if (checkHtml) { + checkHtmlTags(ast, comment); + } - if (checkEmptyJavadoc) { - checkJavadocIsNotEmpty(comment); + if (checkEmptyJavadoc) { + checkJavadocIsNotEmpty(comment); + } } } @@ -232,7 +237,7 @@ final String commentText = getCommentText(comment.getText()); if (!commentText.isEmpty() - && !getEndOfSentencePattern().matcher(commentText).find() + && !endOfSentenceFormat.matcher(commentText).find() && !(commentText.startsWith("{@inheritDoc}") && JavadocTagInfo.INHERIT_DOC.isValidOn(ast))) { log(comment.getStartLineNo(), MSG_NO_PERIOD); @@ -258,7 +263,7 @@ * @return a comment text String. */ private static String getCommentText(String... comments) { - final StringBuilder builder = new StringBuilder(); + final StringBuilder builder = new StringBuilder(1024); for (final String line : comments) { final int textStart = findTextStart(line); @@ -286,20 +291,21 @@ */ private static int findTextStart(String line) { int textStart = -1; - for (int i = 0; i < line.length();) { - if (!Character.isWhitespace(line.charAt(i))) { - if (line.regionMatches(i, "/**", 0, "/**".length())) { - i += 2; + int index = 0; + while (index < line.length()) { + if (!Character.isWhitespace(line.charAt(index))) { + if (line.regionMatches(index, "/**", 0, "/**".length())) { + index += 2; } - else if (line.regionMatches(i, "*/", 0, 2)) { - i++; + else if (line.regionMatches(index, "*/", 0, 2)) { + index++; } - else if (line.charAt(i) != '*') { - textStart = i; + else if (line.charAt(index) != '*') { + textStart = index; break; } } - i++; + index++; } return textStart; } @@ -314,7 +320,7 @@ if (Character.isWhitespace(builder.charAt(index))) { builder.deleteCharAt(index); } - else if (builder.charAt(index) == '/' + else if (index > 0 && builder.charAt(index) == '/' && builder.charAt(index - 1) == '*') { builder.deleteCharAt(index); builder.deleteCharAt(index - 1); @@ -339,7 +345,9 @@ * @param ast the node with the Javadoc * @param comment the {@code TextBlock} which represents * the Javadoc comment. + * @noinspection MethodWithMultipleReturnPoints */ + // -@cs[ReturnCount] Too complex to break apart. private void checkHtmlTags(final DetailAST ast, final TextBlock comment) { final int lineNo = comment.getStartLineNo(); final Deque htmlStack = new ArrayDeque<>(); @@ -366,7 +374,7 @@ log(tag.getLineNo(), tag.getPosition(), MSG_EXTRA_HTML, - tag); + tag.getText()); } else { // See if there are any unclosed tags that were opened @@ -390,7 +398,8 @@ if (!isSingleTag(htmlTag) && !htmlTag.getId().equals(lastFound) && !typeParameters.contains(htmlTag.getId())) { - log(htmlTag.getLineNo(), htmlTag.getPosition(), MSG_UNCLOSED_HTML, htmlTag); + log(htmlTag.getLineNo(), htmlTag.getPosition(), + MSG_UNCLOSED_HTML, htmlTag.getText()); lastFound = htmlTag.getId(); } } @@ -432,7 +441,7 @@ log(lastOpenTag.getLineNo(), lastOpenTag.getPosition(), MSG_UNCLOSED_HTML, - lastOpenTag); + lastOpenTag.getText()); } } @@ -487,38 +496,26 @@ /** * Sets the scope to check. - * @param from string to get the scope from + * @param scope a scope. */ - public void setScope(String from) { - scope = Scope.getInstance(from); + public void setScope(Scope scope) { + this.scope = scope; } /** * Set the excludeScope. - * @param excludeScope a {@code String} value + * @param excludeScope a scope. */ - public void setExcludeScope(String excludeScope) { - this.excludeScope = Scope.getInstance(excludeScope); + public void setExcludeScope(Scope excludeScope) { + this.excludeScope = excludeScope; } /** * Set the format for matching the end of a sentence. - * @param format format for matching the end of a sentence. + * @param pattern a pattern. */ - public void setEndOfSentenceFormat(String format) { - endOfSentenceFormat = format; - } - - /** - * Returns a regular expression for matching the end of a sentence. - * - * @return a regular expression for matching the end of a sentence. - */ - private Pattern getEndOfSentencePattern() { - if (endOfSentencePattern == null) { - endOfSentencePattern = Pattern.compile(endOfSentenceFormat); - } - return endOfSentencePattern; + public void setEndOfSentenceFormat(Pattern pattern) { + endOfSentenceFormat = pattern; } /** @@ -545,4 +542,5 @@ public void setCheckEmptyJavadoc(boolean flag) { checkEmptyJavadoc = flag; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagContinuationIndentationCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagContinuationIndentationCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagContinuationIndentationCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagContinuationIndentationCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,7 +24,7 @@ import com.puppycrawl.tools.checkstyle.api.DetailNode; import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; /** @@ -73,29 +73,24 @@ } @Override - public int[] getAcceptableTokens() { - return new int[] {TokenTypes.BLOCK_COMMENT_BEGIN }; - } - - @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); + public int[] getRequiredJavadocTokens() { + return getAcceptableJavadocTokens(); } @Override public void visitJavadocToken(DetailNode ast) { - if (isInlineDescription(ast)) { - return; - } - final List textNodes = getAllNewlineNodes(ast); - for (DetailNode newlineNode : textNodes) { - final DetailNode textNode = JavadocUtils.getNextSibling(JavadocUtils - .getNextSibling(newlineNode)); - if (textNode != null && textNode.getType() == JavadocTokenTypes.TEXT - && textNode.getChildren().length > 1) { - final DetailNode whitespace = JavadocUtils.getFirstChild(textNode); - if (whitespace.getText().length() - 1 < offset) { - log(textNode.getLineNumber(), MSG_KEY, offset); + if (!isInlineDescription(ast)) { + final List textNodes = getAllNewlineNodes(ast); + for (DetailNode newlineNode : textNodes) { + final DetailNode textNode = JavadocUtils.getNextSibling(JavadocUtils + .getNextSibling(newlineNode)); + if (textNode != null && textNode.getType() == JavadocTokenTypes.TEXT) { + final String text = textNode.getText(); + if (!CommonUtils.isBlank(text.trim()) + && (text.length() <= offset + || !text.substring(1, offset + 1).trim().isEmpty())) { + log(textNode.getLineNumber(), MSG_KEY, offset); + } } } } @@ -124,13 +119,16 @@ * @return true, if description node is a description of in-line tag. */ private static boolean isInlineDescription(DetailNode description) { + boolean isInline = false; DetailNode inlineTag = description.getParent(); while (inlineTag != null) { if (inlineTag.getType() == JavadocTokenTypes.JAVADOC_INLINE_TAG) { - return true; + isInline = true; + break; } inlineTag = inlineTag.getParent(); } - return false; + return isInline; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagInfo.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagInfo.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagInfo.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTagInfo.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,10 @@ package com.puppycrawl.tools.checkstyle.checks.javadoc; import java.util.Arrays; +import java.util.Collections; import java.util.Map; +import java.util.stream.Collectors; -import com.google.common.collect.ImmutableMap; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.Scope; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -33,7 +34,7 @@ * *

    * This class was modeled after documentation located at - * + * * javadoc * * and @@ -70,6 +71,7 @@ * {@code @author}. */ AUTHOR("@author", "author", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); @@ -79,110 +81,129 @@ || astType == TokenTypes.ENUM_DEF || astType == TokenTypes.ANNOTATION_DEF; } + }, /** * {@code {@code}}. */ CODE("{@code}", "code", Type.INLINE) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0 && !ScopeUtils.isLocalVariableDef(ast); } + }, /** * {@code {@docRoot}}. */ DOC_ROOT("{@docRoot}", "docRoot", Type.INLINE) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0 && !ScopeUtils.isLocalVariableDef(ast); } + }, /** * {@code @deprecated}. */ DEPRECATED("@deprecated", "deprecated", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return Arrays.binarySearch(DEF_TOKEN_TYPES_DEPRECATED, astType) >= 0 && !ScopeUtils.isLocalVariableDef(ast); } + }, /** * {@code @exception}. */ EXCEPTION("@exception", "exception", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return astType == TokenTypes.METHOD_DEF || astType == TokenTypes.CTOR_DEF; } + }, /** * {@code {@inheritDoc}}. */ INHERIT_DOC("{@inheritDoc}", "inheritDoc", Type.INLINE) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return astType == TokenTypes.METHOD_DEF - && !ast.branchContains(TokenTypes.LITERAL_STATIC) + && ast.findFirstToken(TokenTypes.MODIFIERS) + .findFirstToken(TokenTypes.LITERAL_STATIC) == null && ScopeUtils.getScopeFromMods(ast .findFirstToken(TokenTypes.MODIFIERS)) != Scope.PRIVATE; } + }, /** * {@code {@link}}. */ LINK("{@link}", "link", Type.INLINE) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0 && !ScopeUtils.isLocalVariableDef(ast); } + }, /** * {@code {@linkplain}}. */ LINKPLAIN("{@linkplain}", "linkplain", Type.INLINE) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0 && !ScopeUtils.isLocalVariableDef(ast); } + }, /** * {@code {@literal}}. */ LITERAL("{@literal}", "literal", Type.INLINE) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0 && !ScopeUtils.isLocalVariableDef(ast); } + }, /** * {@code @param}. */ PARAM("@param", "param", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); @@ -191,12 +212,14 @@ || astType == TokenTypes.METHOD_DEF || astType == TokenTypes.CTOR_DEF; } + }, /** * {@code @return}. */ RETURN("@return", "return", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); @@ -204,26 +227,29 @@ return astType == TokenTypes.METHOD_DEF && returnType.getFirstChild().getType() != TokenTypes.LITERAL_VOID; - } + }, /** * {@code @see}. */ SEE("@see", "see", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0 && !ScopeUtils.isLocalVariableDef(ast); } + }, /** * {@code @serial}. */ SERIAL("@serial", "serial", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); @@ -231,12 +257,14 @@ return astType == TokenTypes.VARIABLE_DEF && !ScopeUtils.isLocalVariableDef(ast); } + }, /** * {@code @serialData}. */ SERIAL_DATA("@serialData", "serialData", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); @@ -251,12 +279,14 @@ || "writeReplace".equals(methodName) || "readResolve".equals(methodName)); } + }, /** * {@code @serialField}. */ SERIAL_FIELD("@serialField", "serialField", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); @@ -264,50 +294,58 @@ return astType == TokenTypes.VARIABLE_DEF && varType.getFirstChild().getType() == TokenTypes.ARRAY_DECLARATOR - && "ObjectStreafield".equals(varType.getFirstChild().getText()); + && "ObjectStreamField".equals(varType.getFirstChild().getText()); } + }, /** * {@code @since}. */ SINCE("@since", "since", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0 && !ScopeUtils.isLocalVariableDef(ast); } + }, /** * {@code @throws}. */ THROWS("@throws", "throws", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return astType == TokenTypes.METHOD_DEF || astType == TokenTypes.CTOR_DEF; } + }, /** * {@code {@value}}. */ VALUE("{@value}", "value", Type.INLINE) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); return Arrays.binarySearch(DEF_TOKEN_TYPES, astType) >= 0 && !ScopeUtils.isLocalVariableDef(ast); } + }, /** * {@code @version}. */ VERSION("@version", "version", Type.BLOCK) { + @Override public boolean isValidOn(final DetailAST ast) { final int astType = ast.getType(); @@ -317,6 +355,7 @@ || astType == TokenTypes.ENUM_DEF || astType == TokenTypes.ANNOTATION_DEF; } + }; /** Default token types for DEPRECATED Javadoc tag.*/ @@ -350,19 +389,10 @@ private static final Map NAME_TO_TAG; static { - final ImmutableMap.Builder textToTagBuilder = - new ImmutableMap.Builder<>(); - - final ImmutableMap.Builder nameToTagBuilder = - new ImmutableMap.Builder<>(); - - for (final JavadocTagInfo tag : JavadocTagInfo.values()) { - textToTagBuilder.put(tag.text, tag); - nameToTagBuilder.put(tag.name, tag); - } - - TEXT_TO_TAG = textToTagBuilder.build(); - NAME_TO_TAG = nameToTagBuilder.build(); + TEXT_TO_TAG = Collections.unmodifiableMap(Arrays.stream(JavadocTagInfo.values()) + .collect(Collectors.toMap(JavadocTagInfo::getText, tagText -> tagText))); + NAME_TO_TAG = Collections.unmodifiableMap(Arrays.stream(JavadocTagInfo.values()) + .collect(Collectors.toMap(JavadocTagInfo::getName, tagName -> tagName))); //Arrays sorting for binary search Arrays.sort(DEF_TOKEN_TYPES); @@ -499,10 +529,13 @@ * @author Travis Schneeberger */ public enum Type { + /** Block type. **/ BLOCK, /** Inline type. **/ INLINE + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTag.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTag.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTag.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTag.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,6 +24,7 @@ * @author Oliver Burn */ public class JavadocTag { + /** The line number of the tag. **/ private final int lineNo; /** The column number of the tag. **/ @@ -66,6 +67,7 @@ } /** + * Returns first argument. * @return the first argument. null if not set. */ public String getFirstArg() { @@ -90,8 +92,10 @@ @Override public String toString() { - return "JavadocTag{tag='" + getTagName() + "' lineNo=" + lineNo + ", columnNo=" + columnNo - + ", firstArg='" + firstArg + "'}"; + return "JavadocTag[tag='" + tagInfo.getName() + + "' lineNo=" + lineNo + + ", columnNo=" + columnNo + + ", firstArg='" + firstArg + "']"; } /** @@ -142,8 +146,10 @@ public boolean canReferenceImports() { return tagInfo == JavadocTagInfo.SEE || tagInfo == JavadocTagInfo.LINK + || tagInfo == JavadocTagInfo.VALUE || tagInfo == JavadocTagInfo.LINKPLAIN || tagInfo == JavadocTagInfo.THROWS || tagInfo == JavadocTagInfo.EXCEPTION; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTags.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTags.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTags.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTags.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,17 +19,17 @@ package com.puppycrawl.tools.checkstyle.checks.javadoc; +import java.util.ArrayList; import java.util.Collections; import java.util.List; -import com.google.common.collect.ImmutableList; - /** * Value object for combining the list of valid validTags with information * about invalid validTags encountered in a certain Javadoc comment. * @author Oliver Burn */ public final class JavadocTags { + /** Valid validTags. */ private final List validTags; /** Invalid validTags. */ @@ -40,10 +40,11 @@ * @param tags the list of valid tags * @param invalidTags the list of invalid tags */ - public JavadocTags(List tags, - List invalidTags) { - validTags = ImmutableList.copyOf(tags); - this.invalidTags = ImmutableList.copyOf(invalidTags); + public JavadocTags(List tags, List invalidTags) { + final List validTagsCopy = new ArrayList<>(tags); + validTags = Collections.unmodifiableList(validTagsCopy); + final List invalidTagsCopy = new ArrayList<>(invalidTags); + this.invalidTags = Collections.unmodifiableList(invalidTagsCopy); } /** @@ -61,4 +62,5 @@ public List getInvalidTags() { return Collections.unmodifiableList(invalidTags); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTypeCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTypeCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTypeCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocTypeCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,9 +23,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.Scope; @@ -45,8 +44,9 @@ * @author Oliver Burn * @author Michael Tamm */ +@StatelessCheck public class JavadocTypeCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -90,18 +90,22 @@ /** Close angle bracket literal. */ private static final String CLOSE_ANGLE_BRACKET = ">"; + /** Pattern to match type name within angle brackets in javadoc param tag. */ + private static final Pattern TYPE_NAME_IN_JAVADOC_TAG = + Pattern.compile("\\s*<([^>]+)>.*"); + + /** Pattern to split type name field in javadoc param tag. */ + private static final Pattern TYPE_NAME_IN_JAVADOC_TAG_SPLITTER = + Pattern.compile("\\s+"); + /** The scope to check for. */ private Scope scope = Scope.PRIVATE; /** The visibility scope where Javadoc comments shouldn't be checked. **/ private Scope excludeScope; /** Compiled regexp to match author tag content. **/ - private Pattern authorFormatPattern; + private Pattern authorFormat; /** Compiled regexp to match version tag content. **/ - private Pattern versionFormatPattern; - /** Regexp to match author tag content. */ - private String authorFormat; - /** Regexp to match version tag content. */ - private String versionFormat; + private Pattern versionFormat; /** * Controls whether to ignore errors when a method has type parameters but * does not have matching param tags in the javadoc. Defaults to false. @@ -112,36 +116,34 @@ /** * Sets the scope to check. - * @param from string to set scope from + * @param scope a scope. */ - public void setScope(String from) { - scope = Scope.getInstance(from); + public void setScope(Scope scope) { + this.scope = scope; } /** * Set the excludeScope. - * @param excludeScope a {@code String} value + * @param excludeScope a scope. */ - public void setExcludeScope(String excludeScope) { - this.excludeScope = Scope.getInstance(excludeScope); + public void setExcludeScope(Scope excludeScope) { + this.excludeScope = excludeScope; } /** * Set the author tag pattern. - * @param format a {@code String} value + * @param pattern a pattern. */ - public void setAuthorFormat(String format) { - authorFormat = format; - authorFormatPattern = CommonUtils.createPattern(format); + public void setAuthorFormat(Pattern pattern) { + authorFormat = pattern; } /** * Set the version format pattern. - * @param format a {@code String} value + * @param pattern a pattern. */ - public void setVersionFormat(String format) { - versionFormat = format; - versionFormatPattern = CommonUtils.createPattern(format); + public void setVersionFormat(Pattern pattern) { + versionFormat = pattern; } /** @@ -179,7 +181,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -196,9 +198,9 @@ if (ScopeUtils.isOuterMostType(ast)) { // don't check author/version for inner classes checkTag(lineNo, tags, JavadocTagInfo.AUTHOR.getName(), - authorFormatPattern, authorFormat); + authorFormat); checkTag(lineNo, tags, JavadocTagInfo.VERSION.getName(), - versionFormatPattern, versionFormat); + versionFormat); } final List typeParamNames = @@ -223,15 +225,14 @@ * @return whether we should check a given node. */ private boolean shouldCheck(final DetailAST ast) { - final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS); - final Scope declaredScope = ScopeUtils.getScopeFromMods(mods); final Scope customScope; if (ScopeUtils.isInInterfaceOrAnnotationBlock(ast)) { customScope = Scope.PUBLIC; } else { - customScope = declaredScope; + final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS); + customScope = ScopeUtils.getScopeFromMods(mods); } final Scope surroundingScope = ScopeUtils.getSurroundingScope(ast); @@ -266,27 +267,24 @@ * @param tags tags from the Javadoc comment for the type definition. * @param tagName the required tag name. * @param formatPattern regexp for the tag value. - * @param format pattern for the tag value. */ private void checkTag(int lineNo, List tags, String tagName, - Pattern formatPattern, String format) { - if (formatPattern == null) { - return; - } - - int tagCount = 0; - final String tagPrefix = "@"; - for (int i = tags.size() - 1; i >= 0; i--) { - final JavadocTag tag = tags.get(i); - if (tag.getTagName().equals(tagName)) { - tagCount++; - if (!formatPattern.matcher(tag.getFirstArg()).find()) { - log(lineNo, MSG_TAG_FORMAT, tagPrefix + tagName, format); + Pattern formatPattern) { + if (formatPattern != null) { + int tagCount = 0; + final String tagPrefix = "@"; + for (int i = tags.size() - 1; i >= 0; i--) { + final JavadocTag tag = tags.get(i); + if (tag.getTagName().equals(tagName)) { + tagCount++; + if (!formatPattern.matcher(tag.getFirstArg()).find()) { + log(lineNo, MSG_TAG_FORMAT, tagPrefix + tagName, formatPattern.pattern()); + } } } - } - if (tagCount == 0) { - log(lineNo, MSG_MISSING_TAG, tagPrefix + tagName); + if (tagCount == 0) { + log(lineNo, MSG_MISSING_TAG, tagPrefix + tagName); + } } } @@ -306,6 +304,7 @@ && tag.getFirstArg().indexOf(OPEN_ANGLE_BRACKET + typeParamName + CLOSE_ANGLE_BRACKET) == 0) { found = true; + break; } } if (!found) { @@ -322,22 +321,37 @@ private void checkUnusedTypeParamTags( final List tags, final List typeParamNames) { - final Pattern pattern = Pattern.compile("\\s*<([^>]+)>.*"); for (int i = tags.size() - 1; i >= 0; i--) { final JavadocTag tag = tags.get(i); if (tag.isParamTag()) { + final String typeParamName = extractTypeParamNameFromTag(tag); - final Matcher matcher = pattern.matcher(tag.getFirstArg()); - if (matcher.find()) { - final String typeParamName = matcher.group(1).trim(); - if (!typeParamNames.contains(typeParamName)) { - log(tag.getLineNo(), tag.getColumnNo(), + if (!typeParamNames.contains(typeParamName)) { + log(tag.getLineNo(), tag.getColumnNo(), MSG_UNUSED_TAG, JavadocTagInfo.PARAM.getText(), OPEN_ANGLE_BRACKET + typeParamName + CLOSE_ANGLE_BRACKET); - } } } } } + + /** + * Extracts type parameter name from tag. + * @param tag javadoc tag to extract parameter name + * @return extracts type parameter name from tag + */ + private static String extractTypeParamNameFromTag(JavadocTag tag) { + final String typeParamName; + final Matcher matchInAngleBrackets = + TYPE_NAME_IN_JAVADOC_TAG.matcher(tag.getFirstArg()); + if (matchInAngleBrackets.find()) { + typeParamName = matchInAngleBrackets.group(1).trim(); + } + else { + typeParamName = TYPE_NAME_IN_JAVADOC_TAG_SPLITTER.split(tag.getFirstArg())[0]; + } + return typeParamName; + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocVariableCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocVariableCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocVariableCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/JavadocVariableCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,22 +21,23 @@ import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.Scope; import com.puppycrawl.tools.checkstyle.api.TextBlock; import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; /** - * Checks that a variable has Javadoc comment. Ignores serialVersionUID fields. + * Checks that a variable has Javadoc comment. Ignores {@code serialVersionUID} fields. * * @author Oliver Burn */ +@StatelessCheck public class JavadocVariableCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -55,27 +56,26 @@ /** * Sets the scope to check. - * @param from string to get the scope from + * @param scope a scope. */ - public void setScope(String from) { - scope = Scope.getInstance(from); + public void setScope(Scope scope) { + this.scope = scope; } /** * Set the excludeScope. - * @param excludeScope a {@code String} value + * @param excludeScope a scope. */ - public void setExcludeScope(String excludeScope) { - this.excludeScope = Scope.getInstance(excludeScope); + public void setExcludeScope(Scope excludeScope) { + this.excludeScope = excludeScope; } /** * Sets the variable names to ignore in the check. - * @param regexp regular expression to define variable names to ignore. - * @throws org.apache.commons.beanutils.ConversionException if unable to create Pattern object. + * @param pattern a pattern. */ - public void setIgnoreNamePattern(String regexp) { - ignoreNamePattern = CommonUtils.createPattern(regexp); + public void setIgnoreNamePattern(Pattern pattern) { + ignoreNamePattern = pattern; } @Override @@ -132,31 +132,22 @@ * @return whether we should check a given node. */ private boolean shouldCheck(final DetailAST ast) { - if (ScopeUtils.isInCodeBlock(ast) || isIgnored(ast)) { - return false; - } - - final Scope customScope; - if (ast.getType() == TokenTypes.ENUM_CONSTANT_DEF) { - customScope = Scope.PUBLIC; - } - else { - final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS); - final Scope declaredScope = ScopeUtils.getScopeFromMods(mods); - - if (ScopeUtils.isInInterfaceOrAnnotationBlock(ast)) { - customScope = Scope.PUBLIC; - } - else { - customScope = declaredScope; + boolean result = false; + if (!ScopeUtils.isInCodeBlock(ast) && !isIgnored(ast)) { + Scope customScope = Scope.PUBLIC; + if (ast.getType() != TokenTypes.ENUM_CONSTANT_DEF + && !ScopeUtils.isInInterfaceOrAnnotationBlock(ast)) { + final DetailAST mods = ast.findFirstToken(TokenTypes.MODIFIERS); + customScope = ScopeUtils.getScopeFromMods(mods); } - } - - final Scope surroundingScope = ScopeUtils.getSurroundingScope(ast); - return customScope.isIn(scope) && surroundingScope.isIn(scope) - && (excludeScope == null - || !customScope.isIn(excludeScope) - || !surroundingScope.isIn(excludeScope)); + final Scope surroundingScope = ScopeUtils.getSurroundingScope(ast); + result = customScope.isIn(scope) && surroundingScope.isIn(scope) + && (excludeScope == null + || !customScope.isIn(excludeScope) + || !surroundingScope.isIn(excludeScope)); + } + return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/NonEmptyAtclauseDescriptionCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/NonEmptyAtclauseDescriptionCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/NonEmptyAtclauseDescriptionCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/NonEmptyAtclauseDescriptionCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,7 +21,6 @@ import com.puppycrawl.tools.checkstyle.api.DetailNode; import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; /** @@ -49,21 +48,12 @@ JavadocTokenTypes.PARAM_LITERAL, JavadocTokenTypes.RETURN_LITERAL, JavadocTokenTypes.THROWS_LITERAL, + JavadocTokenTypes.EXCEPTION_LITERAL, JavadocTokenTypes.DEPRECATED_LITERAL, }; } @Override - public int[] getAcceptableTokens() { - return new int[] {TokenTypes.BLOCK_COMMENT_BEGIN }; - } - - @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); - } - - @Override public void visitJavadocToken(DetailNode ast) { if (isEmptyTag(ast.getParent())) { log(ast.getLineNumber(), MSG_KEY, ast.getText()); @@ -80,4 +70,5 @@ JavadocUtils.findFirstToken(tagNode, JavadocTokenTypes.DESCRIPTION); return tagDescription == null; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SingleLineJavadocCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SingleLineJavadocCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SingleLineJavadocCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SingleLineJavadocCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,14 +20,13 @@ package com.puppycrawl.tools.checkstyle.checks.javadoc; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; -import com.google.common.base.Splitter; -import com.google.common.collect.Lists; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.DetailNode; import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; /** @@ -80,9 +79,8 @@ * * @param tags to be ignored by check. */ - public void setIgnoredTags(String tags) { - ignoredTags = - Lists.newArrayList(Splitter.on(",").omitEmptyStrings().trimResults().split(tags)); + public void setIgnoredTags(String... tags) { + ignoredTags = Arrays.stream(tags).collect(Collectors.toList()); } /** @@ -102,13 +100,8 @@ } @Override - public int[] getAcceptableTokens() { - return new int[] {TokenTypes.BLOCK_COMMENT_BEGIN }; - } - - @Override - public int[] getRequiredTokens() { - return getAcceptableTokens(); + public int[] getRequiredJavadocTokens() { + return getAcceptableJavadocTokens(); } @Override @@ -138,7 +131,7 @@ * @param javadocRoot javadoc root node. * @return true, if comment has javadoc tags which are not ignored. * @see + * https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#blockandinlinetags> * Block and inline tags */ private boolean hasJavadocTags(DetailNode javadocRoot) { @@ -153,7 +146,7 @@ * @param javadocRoot javadoc root node. * @return true, if comment has in-line tags which are not ignored. * @see + * https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javadoc.html#javadoctags> * JavadocTags */ private boolean hasJavadocInlineTags(DetailNode javadocRoot) { @@ -180,4 +173,5 @@ private boolean isTagIgnored(DetailNode javadocTagSection) { return ignoredTags.contains(JavadocUtils.getTagName(javadocTagSection)); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SummaryJavadocCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SummaryJavadocCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SummaryJavadocCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/SummaryJavadocCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,12 +19,15 @@ package com.puppycrawl.tools.checkstyle.checks.javadoc; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; import java.util.regex.Pattern; import com.google.common.base.CharMatcher; import com.puppycrawl.tools.checkstyle.api.DetailNode; import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; @@ -33,6 +36,7 @@ * Checks that * Javadoc summary sentence does not contain phrases that are not recommended to use. + * Check also violate javadoc that does not contain first sentence. * By default Check validate that first sentence is not empty:


    *
      * <module name="SummaryJavadocCheck"/>
    @@ -75,6 +79,11 @@
          */
         public static final String MSG_SUMMARY_JAVADOC = "summary.javaDoc";
         /**
    +     * A key is pointing to the warning message text in "messages.properties"
    +     * file.
    +     */
    +    public static final String MSG_SUMMARY_JAVADOC_MISSING = "summary.javaDoc.missing";
    +    /**
          * This regexp is used to convert multiline javadoc to single line without stars.
          */
         private static final Pattern JAVADOC_MULTILINE_TO_SINGLELINE_PATTERN =
    @@ -83,22 +92,24 @@
         /** Period literal. */
         private static final String PERIOD = ".";
     
    -    /**
    -     * Regular expression for forbidden summary fragments.
    -     */
    +    /** Set of allowed Tokens tags in summary java doc. */
    +    private static final Set ALLOWED_TYPES = Collections.unmodifiableSet(
    +            new HashSet<>(Arrays.asList(JavadocTokenTypes.TEXT,
    +                    JavadocTokenTypes.WS))
    +    );
    +
    +    /** Regular expression for forbidden summary fragments. */
         private Pattern forbiddenSummaryFragments = CommonUtils.createPattern("^$");
     
    -    /**
    -     * Period symbol at the end of first javadoc sentence.
    -     */
    +    /** Period symbol at the end of first javadoc sentence. */
         private String period = PERIOD;
     
         /**
          * Sets custom value of regular expression for forbidden summary fragments.
    -     * @param pattern user's value.
    +     * @param pattern a pattern.
          */
    -    public void setForbiddenSummaryFragments(String pattern) {
    -        forbiddenSummaryFragments = CommonUtils.createPattern(pattern);
    +    public void setForbiddenSummaryFragments(Pattern pattern) {
    +        forbiddenSummaryFragments = pattern;
         }
     
         /**
    @@ -117,30 +128,98 @@
         }
     
         @Override
    -    public int[] getAcceptableTokens() {
    -        return new int[] {TokenTypes.BLOCK_COMMENT_BEGIN };
    +    public int[] getRequiredJavadocTokens() {
    +        return getAcceptableJavadocTokens();
         }
     
         @Override
    -    public int[] getRequiredTokens() {
    -        return getAcceptableTokens();
    +    public void visitJavadocToken(DetailNode ast) {
    +        if (!startsWithInheritDoc(ast)) {
    +            final String summaryDoc = getSummarySentence(ast);
    +            if (summaryDoc.isEmpty()) {
    +                log(ast.getLineNumber(), MSG_SUMMARY_JAVADOC_MISSING);
    +            }
    +            else if (!period.isEmpty()) {
    +                final String firstSentence = getFirstSentence(ast);
    +                final int endOfSentence = firstSentence.lastIndexOf(period);
    +                if (!summaryDoc.contains(period)) {
    +                    log(ast.getLineNumber(), MSG_SUMMARY_FIRST_SENTENCE);
    +                }
    +                if (endOfSentence != -1
    +                        && containsForbiddenFragment(firstSentence.substring(0, endOfSentence))) {
    +                    log(ast.getLineNumber(), MSG_SUMMARY_JAVADOC);
    +                }
    +            }
    +        }
         }
     
    -    @Override
    -    public void visitJavadocToken(DetailNode ast) {
    -        String firstSentence = getFirstSentence(ast);
    -        final int endOfSentence = firstSentence.lastIndexOf(period);
    -        if (endOfSentence == -1) {
    -            if (!firstSentence.trim().startsWith("{@inheritDoc}")) {
    -                log(ast.getLineNumber(), MSG_SUMMARY_FIRST_SENTENCE);
    +    /**
    +     * Checks if the node starts with an {@inheritDoc}.
    +     * @param root The root node to examine.
    +     * @return {@code true} if the javadoc starts with an {@inheritDoc}.
    +     */
    +    private static boolean startsWithInheritDoc(DetailNode root) {
    +        boolean found = false;
    +        final DetailNode[] children = root.getChildren();
    +
    +        for (int i = 0; !found && i < children.length - 1; i++) {
    +            final DetailNode child = children[i];
    +            if (child.getType() == JavadocTokenTypes.JAVADOC_INLINE_TAG
    +                    && child.getChildren()[1].getType() == JavadocTokenTypes.INHERIT_DOC_LITERAL) {
    +                found = true;
    +            }
    +            else if (child.getType() != JavadocTokenTypes.LEADING_ASTERISK
    +                    && !CommonUtils.isBlank(child.getText())) {
    +                break;
    +            }
    +        }
    +
    +        return found;
    +    }
    +
    +    /**
    +     * Checks if period is at the end of sentence.
    +     * @param ast Javadoc root node.
    +     * @return error string
    +     */
    +    private static String getSummarySentence(DetailNode ast) {
    +        boolean flag = true;
    +        final StringBuilder result = new StringBuilder(256);
    +        for (DetailNode child : ast.getChildren()) {
    +            if (ALLOWED_TYPES.contains(child.getType())) {
    +                result.append(child.getText());
    +            }
    +            else if (child.getType() == JavadocTokenTypes.HTML_ELEMENT
    +                    && CommonUtils.isBlank(result.toString().trim())) {
    +                result.append(getStringInsideTag(result.toString(),
    +                        child.getChildren()[0].getChildren()[0]));
    +            }
    +            else if (child.getType() == JavadocTokenTypes.JAVADOC_TAG) {
    +                flag = false;
    +            }
    +            if (!flag) {
    +                break;
                 }
             }
    -        else {
    -            firstSentence = firstSentence.substring(0, endOfSentence);
    -            if (containsForbiddenFragment(firstSentence)) {
    -                log(ast.getLineNumber(), MSG_SUMMARY_JAVADOC);
    +        return result.toString().trim();
    +    }
    +
    +    /**
    +     * Concatenates string within text of html tags.
    +     * @param result javadoc string
    +     * @param detailNode javadoc tag node
    +     * @return java doc tag content appended in result
    +     */
    +    private static String getStringInsideTag(String result, DetailNode detailNode) {
    +        final StringBuilder contents = new StringBuilder(result);
    +        DetailNode tempNode = detailNode;
    +        while (tempNode != null) {
    +            if (tempNode.getType() == JavadocTokenTypes.TEXT) {
    +                contents.append(tempNode.getText());
                 }
    +            tempNode = JavadocUtils.getNextSibling(tempNode);
             }
    +        return contents.toString();
         }
     
         /**
    @@ -149,34 +228,25 @@
          * @return first sentence.
          */
         private static String getFirstSentence(DetailNode ast) {
    -        final StringBuilder result = new StringBuilder();
    +        final StringBuilder result = new StringBuilder(256);
             final String periodSuffix = PERIOD + ' ';
             for (DetailNode child : ast.getChildren()) {
    -            if (child.getType() != JavadocTokenTypes.JAVADOC_INLINE_TAG
    -                && child.getText().contains(periodSuffix)) {
    -                result.append(getCharsTillDot(child));
    -                break;
    +            final String text;
    +            if (child.getChildren().length == 0) {
    +                text = child.getText();
                 }
                 else {
    -                result.append(child.getText());
    +                text = getFirstSentence(child);
                 }
    -        }
    -        return result.toString();
    -    }
     
    -    /**
    -     * Finds and returns chars till first dot.
    -     * @param textNode node with javadoc text.
    -     * @return String with chars till first dot.
    -     */
    -    private static String getCharsTillDot(DetailNode textNode) {
    -        final StringBuilder result = new StringBuilder();
    -        for (DetailNode child : textNode.getChildren()) {
    -            result.append(child.getText());
    -            if (PERIOD.equals(child.getText())
    -                && JavadocUtils.getNextSibling(child).getType() == JavadocTokenTypes.WS) {
    +            if (child.getType() != JavadocTokenTypes.JAVADOC_INLINE_TAG
    +                && text.contains(periodSuffix)) {
    +                result.append(text.substring(0, text.indexOf(periodSuffix) + 1));
                     break;
                 }
    +            else {
    +                result.append(text);
    +            }
             }
             return result.toString();
         }
    @@ -189,7 +259,8 @@
         private boolean containsForbiddenFragment(String firstSentence) {
             String javadocText = JAVADOC_MULTILINE_TO_SINGLELINE_PATTERN
                     .matcher(firstSentence).replaceAll(" ");
    -        javadocText = CharMatcher.WHITESPACE.trimAndCollapseFrom(javadocText, ' ');
    +        javadocText = CharMatcher.whitespace().trimAndCollapseFrom(javadocText, ' ');
             return forbiddenSummaryFragments.matcher(javadocText).find();
         }
    +
     }
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/TagParser.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/TagParser.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/TagParser.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/TagParser.java	2018-01-14 13:38:20.000000000 +0000
    @@ -1,6 +1,6 @@
     ////////////////////////////////////////////////////////////////////////////////
     // checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    +// Copyright (C) 2001-2018 the original author or authors.
     //
     // This library is free software; you can redistribute it and/or
     // modify it under the terms of the GNU Lesser General Public
    @@ -19,10 +19,9 @@
     
     package com.puppycrawl.tools.checkstyle.checks.javadoc;
     
    +import java.util.LinkedList;
     import java.util.List;
     
    -import com.google.common.collect.Lists;
    -
     /**
      * 

    * Helper class used to parse HTML tags or generic type identifiers @@ -46,8 +45,9 @@ * @author Chris Stillwell */ class TagParser { + /** List of HtmlTags found on the input line of text. */ - private final List tags = Lists.newLinkedList(); + private final List tags = new LinkedList<>(); /** * Constructs a TagParser and finds the first tag if any. @@ -93,9 +93,7 @@ */ private void parseTags(String[] text, int lineNo) { final int nLines = text.length; - Point position = new Point(0, 0); - - position = findChar(text, '<', position); + Point position = findChar(text, '<', new Point(0, 0)); while (position.getLineNo() < nLines) { // if this is html comment then skip it if (isCommentTag(text, position)) { @@ -112,7 +110,7 @@ } /** - * Parses the tag and return position after it + * Parses the tag and return position after it. * @param text the source line to parse. * @param lineNo the source line number. * @param nLines line length @@ -172,28 +170,28 @@ * @return id for given tag */ private static String getTagId(String[] javadocText, Point tagStart) { + String tagId = ""; int column = tagStart.getColumnNo() + 1; String text = javadocText[tagStart.getLineNo()]; - if (column >= text.length()) { - return ""; - } + if (column < text.length()) { + if (text.charAt(column) == '/') { + column++; + } - if (text.charAt(column) == '/') { - column++; - } + text = text.substring(column).trim(); + int position = 0; - text = text.substring(column).trim(); - int position = 0; + //Character.isJavaIdentifier... may not be a valid HTML + //identifier but is valid for generics + while (position < text.length() + && (Character.isJavaIdentifierStart(text.charAt(position)) + || Character.isJavaIdentifierPart(text.charAt(position)))) { + position++; + } - //Character.isJavaIdentifier... may not be a valid HTML - //identifier but is valid for generics - while (position < text.length() - && (Character.isJavaIdentifierStart(text.charAt(position)) - || Character.isJavaIdentifierPart(text.charAt(position)))) { - position++; + tagId = text.substring(0, position); } - - return text.substring(0, position); + return tagId; } /** @@ -279,6 +277,7 @@ * @author o_sukholsky */ private static final class Point { + /** Line number. */ private final int lineNo; /** Column number.*/ @@ -309,5 +308,7 @@ public int getColumnNo() { return columnNo; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/BlockTagUtils.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/BlockTagUtils.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/BlockTagUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/BlockTagUtils.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,97 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.javadoc.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.puppycrawl.tools.checkstyle.api.LineColumn; + +/** + * Tools for parsing block tags from a Javadoc comment. + * + * @author Nathan Naze + */ +public final class BlockTagUtils { + + /** Block tag pattern for a first line. */ + private static final Pattern BLOCK_TAG_PATTERN_FIRST_LINE = Pattern.compile( + "/\\*{2,}\\s*@(\\p{Alpha}+)\\s"); + + /** Block tag pattern. */ + private static final Pattern BLOCK_TAG_PATTERN = Pattern.compile( + "^\\s*\\**\\s*@(\\p{Alpha}+)\\s"); + + /** Closing tag. */ + private static final String JAVADOC_CLOSING_TAG = "*/"; + + /** Prevent instantiation. */ + private BlockTagUtils() { + } + + /** + * Extract the block tags from a Javadoc comment. + * @param lines The text of the comment, as separate lines. + * @return The tags extracted from the block. + */ + public static List extractBlockTags(String... lines) { + final List tags = new ArrayList<>(); + + for (int i = 0; i < lines.length; i++) { + // Starting lines of a comment have a different first line pattern. + final boolean isFirstLine = i == 0; + final Pattern pattern; + if (isFirstLine) { + pattern = BLOCK_TAG_PATTERN_FIRST_LINE; + } + else { + pattern = BLOCK_TAG_PATTERN; + } + + final String line = lines[i]; + final Matcher tagMatcher = pattern.matcher(line); + + if (tagMatcher.find()) { + final String tagName = tagMatcher.group(1); + + // offset of one for the @ character + final int colNum = tagMatcher.start(1) - 1; + final int lineNum = i + 1; + + final String remainder = line.substring(tagMatcher.end(1)); + String tagValue = remainder.trim(); + + // Handle the case where we're on the last line of a Javadoc comment. + if (tagValue.endsWith(JAVADOC_CLOSING_TAG)) { + final int endIndex = tagValue.length() - JAVADOC_CLOSING_TAG.length(); + tagValue = tagValue.substring(0, endIndex).trim(); + } + + final LineColumn position = new LineColumn(lineNum, colNum); + tags.add(new TagInfo(tagName, tagValue, position)); + } + } + + return tags; + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/InlineTagUtils.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/InlineTagUtils.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/InlineTagUtils.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/InlineTagUtils.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,148 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.javadoc.utils; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.puppycrawl.tools.checkstyle.api.LineColumn; + +/** + * Tools for extracting inline tags from Javadoc comments. + * + * @author Nathan Naze + */ +public final class InlineTagUtils { + + /** + * Inline tag pattern. + */ + private static final Pattern INLINE_TAG_PATTERN = Pattern.compile( + ".*?\\{@(\\p{Alpha}+)\\b(.*?)}", Pattern.DOTALL); + + /** Pattern to recognize leading "*" characters in Javadoc. */ + private static final Pattern JAVADOC_PREFIX_PATTERN = Pattern.compile( + "^\\s*\\*", Pattern.MULTILINE); + + /** Pattern matching whitespace, used by {@link InlineTagUtils#collapseWhitespace(String)}. */ + private static final Pattern WHITESPACE_PATTERN = Pattern.compile("\\s+"); + + /** Pattern matching a newline. */ + private static final Pattern NEWLINE_PATTERN = Pattern.compile("\\n"); + + /** Line feed character. */ + private static final String LINE_FEED = "\n"; + + /** Carriage return character. */ + private static final String CARRIAGE_RETURN = "\r"; + + /** Prevent instantiation. */ + private InlineTagUtils() { + } + + /** + * Extract inline Javadoc tags from the given comment. + * @param lines The Javadoc comment (as lines). + * @return The extracted inline Javadoc tags. + */ + public static List extractInlineTags(String... lines) { + for (String line : lines) { + if (line.contains(LINE_FEED) || line.contains(CARRIAGE_RETURN)) { + throw new IllegalArgumentException("comment lines cannot contain newlines"); + } + } + + final String commentText = convertLinesToString(lines); + final Matcher inlineTagMatcher = INLINE_TAG_PATTERN.matcher(commentText); + + final List tags = new ArrayList<>(); + + while (inlineTagMatcher.find()) { + final String tagName = inlineTagMatcher.group(1); + + // Remove the leading asterisks (in case the tag spans a line) and collapse + // the whitespace. + String matchedTagValue = inlineTagMatcher.group(2); + matchedTagValue = removeLeadingJavaDoc(matchedTagValue); + matchedTagValue = collapseWhitespace(matchedTagValue); + + final String tagValue = matchedTagValue; + + final int startIndex = inlineTagMatcher.start(1); + final LineColumn position = getLineColumnOfIndex(commentText, + // correct start index offset + startIndex - 1); + + tags.add(new TagInfo(tagName, tagValue, position)); + } + + return tags; + } + + /** + * Convert array of string to single String. + * @param lines A number of lines, in order. + * @return The lines, joined together with newlines, as a single string. + */ + private static String convertLinesToString(String... lines) { + final StringBuilder builder = new StringBuilder(1024); + for (String line : lines) { + builder.append(line); + builder.append(LINE_FEED); + } + return builder.toString(); + } + + /** + * Get LineColumn from string till index. + * @param source Source string. + * @param index An index into the string. + * @return A position in the source representing what line and column that index appears on. + */ + private static LineColumn getLineColumnOfIndex(String source, int index) { + final String precedingText = source.subSequence(0, index).toString(); + final String[] precedingLines = NEWLINE_PATTERN.split(precedingText); + final String lastLine = precedingLines[precedingLines.length - 1]; + return new LineColumn(precedingLines.length, lastLine.length()); + } + + /** + * Collapse whitespaces. + * @param str Source string. + * @return The given string with all whitespace collapsed. + */ + private static String collapseWhitespace(String str) { + final Matcher matcher = WHITESPACE_PATTERN.matcher(str); + return matcher.replaceAll(" ").trim(); + } + + /** + * Remove leading JavaDoc. + * @param source A string to remove leading Javadoc from. + * @return The given string with leading Javadoc "*" characters from each line removed. + */ + private static String removeLeadingJavaDoc(String source) { + final Matcher matcher = JAVADOC_PREFIX_PATTERN.matcher(source); + return matcher.replaceAll(""); + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +/** + * Contains utils classes for the Javadoc checks that are bundled with the main distribution. + */ +package com.puppycrawl.tools.checkstyle.checks.javadoc.utils; diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/TagInfo.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/TagInfo.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/TagInfo.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/utils/TagInfo.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,84 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.javadoc.utils; + +import com.puppycrawl.tools.checkstyle.api.LineColumn; + +/** + * Value object for storing data about a parsed tag. + * + * @author Nathan Naze + */ +public final class TagInfo { + + /** + * Name of the tag ("link", "see", etc). + */ + private final String name; + + /** + * Value of the tag. + */ + private final String value; + + /** + * Position of the tag in the given comment. + */ + private final LineColumn position; + + /** + * Constructor. + * + * @param name The name of the tag. + * @param value The value of the tag. + * @param position The position of the tag in the comment. + */ + public TagInfo(String name, String value, LineColumn position) { + this.name = name; + this.value = value; + this.position = position; + } + + /** + * Return name of tag. + * @return Name of the tag. + */ + public String getName() { + return name; + } + + /** + * Return value of tag. + * @return Value of the tag. + */ + public String getValue() { + return value; + } + + /** + * Return position of tag. + * @return Value of the tag. + */ + public LineColumn getPosition() { + return position; + } + +} + diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/WriteTagCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/WriteTagCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/WriteTagCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/javadoc/WriteTagCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,9 +22,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.SeverityLevel; @@ -65,8 +64,9 @@ * * @author Daniel Grenner */ +@StatelessCheck public class WriteTagCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -89,14 +89,12 @@ /** Compiled regexp to match tag. **/ private Pattern tagRegExp; /** Compiled regexp to match tag content. **/ - private Pattern tagFormatRegExp; + private Pattern tagFormat; /** Regexp to match tag. */ private String tag; - /** Regexp to match tag content. */ - private String tagFormat; /** The severity level of found tag reports. */ - private SeverityLevel tagSeverityLevel = SeverityLevel.INFO; + private SeverityLevel tagSeverity = SeverityLevel.INFO; /** * Sets the tag to check. @@ -109,22 +107,20 @@ /** * Set the tag format. - * @param format a {@code String} value + * @param pattern a {@code String} value */ - public void setTagFormat(String format) { - tagFormat = format; - tagFormatRegExp = CommonUtils.createPattern(format); + public void setTagFormat(Pattern pattern) { + tagFormat = pattern; } /** - * Sets the tag severity level. The string should be one of the names - * defined in the {@code SeverityLevel} class. + * Sets the tag severity level. * * @param severity The new severity level * @see SeverityLevel */ - public final void setTagSeverity(String severity) { - tagSeverityLevel = SeverityLevel.getInstance(severity); + public final void setTagSeverity(SeverityLevel severity) { + tagSeverity = severity; } @Override @@ -151,7 +147,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -174,30 +170,27 @@ * @param comment the Javadoc comment for the type definition. */ private void checkTag(int lineNo, String... comment) { - if (tagRegExp == null) { - return; - } - - int tagCount = 0; - for (int i = 0; i < comment.length; i++) { - final String commentValue = comment[i]; - final Matcher matcher = tagRegExp.matcher(commentValue); - if (matcher.find()) { - tagCount += 1; - final int contentStart = matcher.start(1); - final String content = commentValue.substring(contentStart); - if (tagFormatRegExp == null || tagFormatRegExp.matcher(content).find()) { - logTag(lineNo + i - comment.length, tag, content); - } - else { - log(lineNo + i - comment.length, MSG_TAG_FORMAT, tag, tagFormat); + if (tagRegExp != null) { + int tagCount = 0; + for (int i = 0; i < comment.length; i++) { + final String commentValue = comment[i]; + final Matcher matcher = tagRegExp.matcher(commentValue); + if (matcher.find()) { + tagCount += 1; + final int contentStart = matcher.start(1); + final String content = commentValue.substring(contentStart); + if (tagFormat == null || tagFormat.matcher(content).find()) { + logTag(lineNo + i - comment.length, tag, content); + } + else { + log(lineNo + i - comment.length, MSG_TAG_FORMAT, tag, tagFormat.pattern()); + } } } + if (tagCount == 0) { + log(lineNo, MSG_MISSING_TAG, tag); + } } - if (tagCount == 0) { - log(lineNo, MSG_MISSING_TAG, tag); - } - } /** @@ -209,12 +202,13 @@ * * @see java.text.MessageFormat */ - protected final void logTag(int line, String tagName, String tagValue) { + private void logTag(int line, String tagName, String tagValue) { final String originalSeverity = getSeverity(); - setSeverity(tagSeverityLevel.getName()); + setSeverity(tagSeverity.getName()); log(line, MSG_WRITE_TAG, tagName, tagValue); setSeverity(originalSeverity); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/LineSeparatorOption.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/LineSeparatorOption.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/LineSeparatorOption.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/LineSeparatorOption.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -29,6 +29,7 @@ * @see NewlineAtEndOfFileCheck */ public enum LineSeparatorOption { + /** Windows-style line separators. **/ CRLF("\r\n"), @@ -65,23 +66,27 @@ * of this line separator */ public boolean matches(byte... bytes) { + final boolean result; if (this == LF_CR_CRLF) { // this silently assumes CRLF and ANY have the same length // and LF and CR are of length 1 - return CRLF.matches(bytes) + result = CRLF.matches(bytes) || LF.matches(Arrays.copyOfRange(bytes, 1, 2)) || CR.matches(Arrays.copyOfRange(bytes, 1, 2)); } else { - return Arrays.equals(bytes, lineSeparator); + result = Arrays.equals(bytes, lineSeparator); } + return result; } /** + * Returns length of file separator in bytes. * @return the length of the file separator in bytes, * e.g. 1 for CR, 2 for CRLF, ... */ public int length() { return lineSeparator.length; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/AbstractClassCouplingCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/AbstractClassCouplingCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/AbstractClassCouplingCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/AbstractClassCouplingCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,16 +20,26 @@ package com.puppycrawl.tools.checkstyle.checks.metrics; import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.Deque; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Pattern; +import java.util.stream.Collectors; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CheckUtils; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * Base class for coupling calculation. @@ -37,43 +47,51 @@ * @author Simon Harris * @author o_sukhodolsky */ -public abstract class AbstractClassCouplingCheck extends Check { +@FileStatefulCheck +public abstract class AbstractClassCouplingCheck extends AbstractCheck { + + /** A package separator - "." */ + private static final String DOT = "."; + /** Class names to ignore. */ - private static final Set DEFAULT_EXCLUDED_CLASSES = - ImmutableSet.builder() - // primitives - .add("boolean", "byte", "char", "double", "float", "int") - .add("long", "short", "void") - // wrappers - .add("Boolean", "Byte", "Character", "Double", "Float") - .add("Integer", "Long", "Short", "Void") - // java.lang.* - .add("Object", "Class") - .add("String", "StringBuffer", "StringBuilder") - // Exceptions - .add("ArrayIndexOutOfBoundsException", "Exception") - .add("RuntimeException", "IllegalArgumentException") - .add("IllegalStateException", "IndexOutOfBoundsException") - .add("NullPointerException", "Throwable", "SecurityException") - .add("UnsupportedOperationException") - // java.util.* - .add("List", "ArrayList", "Deque", "Queue", "LinkedList") - .add("Set", "HashSet", "SortedSet", "TreeSet") - .add("Map", "HashMap", "SortedMap", "TreeMap") - .build(); + private static final Set DEFAULT_EXCLUDED_CLASSES = Collections.unmodifiableSet( + Arrays.stream(new String[] { + // primitives + "boolean", "byte", "char", "double", "float", "int", + "long", "short", "void", + // wrappers + "Boolean", "Byte", "Character", "Double", "Float", + "Integer", "Long", "Short", "Void", + // java.lang.* + "Object", "Class", + "String", "StringBuffer", "StringBuilder", + // Exceptions + "ArrayIndexOutOfBoundsException", "Exception", + "RuntimeException", "IllegalArgumentException", + "IllegalStateException", "IndexOutOfBoundsException", + "NullPointerException", "Throwable", "SecurityException", + "UnsupportedOperationException", + // java.util.* + "List", "ArrayList", "Deque", "Queue", "LinkedList", + "Set", "HashSet", "SortedSet", "TreeSet", + "Map", "HashMap", "SortedMap", "TreeMap", + }).collect(Collectors.toSet())); + + /** Package names to ignore. */ + private static final Set DEFAULT_EXCLUDED_PACKAGES = Collections.emptySet(); - /** Stack of contexts. */ - private final Deque contextStack = new ArrayDeque<>(); + /** User-configured regular expressions to ignore classes. */ + private final List excludeClassesRegexps = new ArrayList<>(); /** User-configured class names to ignore. */ private Set excludedClasses = DEFAULT_EXCLUDED_CLASSES; + /** User-configured package names to ignore. */ + private Set excludedPackages = DEFAULT_EXCLUDED_PACKAGES; /** Allowed complexity. */ private int max; - /** Package of the file we check. */ - private String packageName; - /** Current context. */ - private Context context = new Context("", 0, 0); + /** Current file context. */ + private FileContext fileContext; /** * Creates new instance of the check. @@ -81,9 +99,11 @@ */ protected AbstractClassCouplingCheck(int defaultMax) { max = defaultMax; + excludeClassesRegexps.add(CommonUtils.createPattern("^$")); } /** + * Returns message key we use for log violations. * @return message key we use for log violations. */ protected abstract String getLogMessageId(); @@ -94,13 +114,6 @@ } /** - * @return allowed complexity. - */ - public final int getMax() { - return max; - } - - /** * Sets maximum allowed complexity. * @param max allowed complexity. */ @@ -113,12 +126,42 @@ * @param excludedClasses the list of classes to ignore. */ public final void setExcludedClasses(String... excludedClasses) { - this.excludedClasses = ImmutableSet.copyOf(excludedClasses); + this.excludedClasses = + Collections.unmodifiableSet(Arrays.stream(excludedClasses).collect(Collectors.toSet())); + } + + /** + * Sets user-excluded regular expression of classes to ignore. + * @param from array representing regular expressions of classes to ignore. + */ + public void setExcludeClassesRegexps(String... from) { + excludeClassesRegexps.addAll(Arrays.stream(from.clone()) + .map(CommonUtils::createPattern) + .collect(Collectors.toSet())); + } + + /** + * Sets user-excluded packages to ignore. All excluded packages should end with a period, + * so it also appends a dot to a package name. + * @param excludedPackages the list of packages to ignore. + */ + public final void setExcludedPackages(String... excludedPackages) { + final List invalidIdentifiers = Arrays.stream(excludedPackages) + .filter(x -> !CommonUtils.isName(x)) + .collect(Collectors.toList()); + if (!invalidIdentifiers.isEmpty()) { + throw new IllegalArgumentException( + "the following values are not valid identifiers: " + + invalidIdentifiers.stream().collect(Collectors.joining(", ", "[", "]"))); + } + + this.excludedPackages = Collections.unmodifiableSet( + Arrays.stream(excludedPackages).collect(Collectors.toSet())); } @Override public final void beginTree(DetailAST ast) { - packageName = ""; + fileContext = new FileContext(); } @Override @@ -127,6 +170,9 @@ case TokenTypes.PACKAGE_DEF: visitPackageDef(ast); break; + case TokenTypes.IMPORT: + fileContext.registerImport(ast); + break; case TokenTypes.CLASS_DEF: case TokenTypes.INTERFACE_DEF: case TokenTypes.ANNOTATION_DEF: @@ -134,13 +180,13 @@ visitClassDef(ast); break; case TokenTypes.TYPE: - context.visitType(ast); + fileContext.visitType(ast); break; case TokenTypes.LITERAL_NEW: - context.visitLiteralNew(ast); + fileContext.visitLiteralNew(ast); break; case TokenTypes.LITERAL_THROWS: - context.visitLiteralThrows(ast); + fileContext.visitLiteralThrows(ast); break; default: throw new IllegalArgumentException("Unknown type: " + ast); @@ -166,9 +212,8 @@ * @param pkg package definition. */ private void visitPackageDef(DetailAST pkg) { - final FullIdent ident = FullIdent.createFullIdent(pkg.getLastChild() - .getPreviousSibling()); - packageName = ident.getText(); + final FullIdent ident = FullIdent.createFullIdent(pkg.getLastChild().getPreviousSibling()); + fileContext.setPackageName(ident.getText()); } /** @@ -176,18 +221,114 @@ * @param classDef class definition node. */ private void visitClassDef(DetailAST classDef) { - contextStack.push(context); - final String className = - classDef.findFirstToken(TokenTypes.IDENT).getText(); - context = new Context(className, - classDef.getLineNo(), - classDef.getColumnNo()); + final String className = classDef.findFirstToken(TokenTypes.IDENT).getText(); + fileContext.createNewClassContext(className, classDef.getLineNo(), classDef.getColumnNo()); } /** Restores previous context. */ private void leaveClassDef() { - context.checkCoupling(); - context = contextStack.pop(); + fileContext.checkCurrentClassAndRestorePrevious(); + } + + /** + * Encapsulates information about classes coupling inside single file. + * @noinspection ThisEscapedInObjectConstruction + */ + private class FileContext { + + /** A map of (imported class name -> class name with package) pairs. */ + private final Map importedClassPackage = new HashMap<>(); + + /** Stack of class contexts. */ + private final Deque classesContexts = new ArrayDeque<>(); + + /** Current file package. */ + private String packageName = ""; + + /** Current context. */ + private ClassContext classContext = new ClassContext(this, "", 0, 0); + + /** + * Retrieves current file package name. + * @return Package name. + */ + public String getPackageName() { + return packageName; + } + + /** + * Sets current context package name. + * @param packageName Package name to be set. + */ + public void setPackageName(String packageName) { + this.packageName = packageName; + } + + /** + * Registers given import. This allows us to track imported classes. + * @param imp import definition. + */ + public void registerImport(DetailAST imp) { + final FullIdent ident = FullIdent.createFullIdent( + imp.getLastChild().getPreviousSibling()); + final String fullName = ident.getText(); + if (fullName.charAt(fullName.length() - 1) != '*') { + final int lastDot = fullName.lastIndexOf(DOT); + importedClassPackage.put(fullName.substring(lastDot + 1), fullName); + } + } + + /** + * Retrieves class name with packages. Uses previously registered imports to + * get the full class name. + * @param className Class name to be retrieved. + * @return Class name with package name, if found, {@link Optional#empty()} otherwise. + */ + public Optional getClassNameWithPackage(String className) { + return Optional.ofNullable(importedClassPackage.get(className)); + } + + /** + * Creates new inner class context with given name and location. + * @param className The class name. + * @param lineNo The class line number. + * @param columnNo The class column number. + */ + public void createNewClassContext(String className, int lineNo, int columnNo) { + classesContexts.push(classContext); + classContext = new ClassContext(this, className, lineNo, columnNo); + } + + /** Restores previous context. */ + public void checkCurrentClassAndRestorePrevious() { + classContext.checkCoupling(); + classContext = classesContexts.pop(); + } + + /** + * Visits type token for the current class context. + * @param ast TYPE token. + */ + public void visitType(DetailAST ast) { + classContext.visitType(ast); + } + + /** + * Visits NEW token for the current class context. + * @param ast NEW token. + */ + public void visitLiteralNew(DetailAST ast) { + classContext.visitLiteralNew(ast); + } + + /** + * Visits THROWS token for the current class context. + * @param ast THROWS token. + */ + public void visitLiteralThrows(DetailAST ast) { + classContext.visitLiteralThrows(ast); + } + } /** @@ -196,12 +337,15 @@ * @author Simon Harris * @author o_sukhodolsky */ - private class Context { + private class ClassContext { + + /** Parent file context. */ + private final FileContext parentContext; /** * Set of referenced classes. * Sorted by name for predictable error messages in unit tests. */ - private final Set referencedClassNames = Sets.newTreeSet(); + private final Set referencedClassNames = new TreeSet<>(); /** Own class name. */ private final String className; /* Location of own class. (Used to log violations) */ @@ -212,11 +356,13 @@ /** * Create new context associated with given class. + * @param parentContext Parent file context. * @param className name of the given class. * @param lineNo line of class definition. * @param columnNo column of class definition. */ - Context(String className, int lineNo, int columnNo) { + ClassContext(FileContext parentContext, String className, int lineNo, int columnNo) { + this.parentContext = parentContext; this.className = className; this.lineNo = lineNo; this.columnNo = columnNo; @@ -242,7 +388,7 @@ */ public void visitType(DetailAST ast) { final String fullTypeName = CheckUtils.createFullType(ast).getText(); - context.addReferencedClassName(fullTypeName); + addReferencedClassName(fullTypeName); } /** @@ -250,7 +396,7 @@ * @param ast NEW to process. */ public void visitLiteralNew(DetailAST ast) { - context.addReferencedClassName(ast.getFirstChild()); + addReferencedClassName(ast.getFirstChild()); } /** @@ -275,11 +421,11 @@ /** Checks if coupling less than allowed or not. */ public void checkCoupling() { referencedClassNames.remove(className); - referencedClassNames.remove(packageName + "." + className); + referencedClassNames.remove(parentContext.getPackageName() + DOT + className); if (referencedClassNames.size() > max) { log(lineNo, columnNo, getLogMessageId(), - referencedClassNames.size(), getMax(), + referencedClassNames.size(), max, referencedClassNames.toString()); } } @@ -290,8 +436,40 @@ * @return true if we should count this class. */ private boolean isSignificant(String candidateClassName) { - return !excludedClasses.contains(candidateClassName) - && !candidateClassName.startsWith("java.lang."); + boolean result = !excludedClasses.contains(candidateClassName) + && !isFromExcludedPackage(candidateClassName); + if (result) { + for (Pattern pattern : excludeClassesRegexps) { + if (pattern.matcher(candidateClassName).matches()) { + result = false; + break; + } + } + } + return result; } + + /** + * Checks if given class should be ignored as it belongs to excluded package. + * @param candidateClassName class to check + * @return true if we should not count this class. + */ + private boolean isFromExcludedPackage(String candidateClassName) { + String classNameWithPackage = candidateClassName; + if (!candidateClassName.contains(DOT)) { + classNameWithPackage = parentContext.getClassNameWithPackage(candidateClassName) + .orElse(""); + } + boolean isFromExcludedPackage = false; + if (classNameWithPackage.contains(DOT)) { + final int lastDotIndex = classNameWithPackage.lastIndexOf(DOT); + final String packageName = classNameWithPackage.substring(0, lastDotIndex); + isFromExcludedPackage = packageName.startsWith("java.lang") + || excludedPackages.contains(packageName); + } + return isFromExcludedPackage; + } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/AbstractComplexityCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/AbstractComplexityCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/AbstractComplexityCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/AbstractComplexityCheck.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,186 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.checks.metrics; - -import java.math.BigInteger; -import java.util.ArrayDeque; -import java.util.Deque; - -import com.puppycrawl.tools.checkstyle.api.Check; -import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; - -/** - * Base class for checks the calculate complexity based around methods. - * @deprecated Checkstyle will not support abstract checks anymore. Use {@link Check} instead. - * @author Simon Harris - * @author Oliver Burn - * @noinspection AbstractClassNeverImplemented - */ -@Deprecated -public abstract class AbstractComplexityCheck - extends Check { - /** The initial current value. */ - private static final BigInteger INITIAL_VALUE = BigInteger.ONE; - - /** Stack of values - all but the current value. */ - private final Deque valueStack = new ArrayDeque<>(); - - /** The current value. */ - private BigInteger currentValue = BigInteger.ZERO; - - /** Threshold to report error for. */ - private int max; - - /** - * Creates an instance. - * @param max the threshold of when to report an error - */ - protected AbstractComplexityCheck(int max) { - this.max = max; - } - - /** - * Gets the message ID to log violations with. - * @return the message ID to log violations with - */ - protected abstract String getMessageID(); - - /** - * Hook called when visiting a token. Will not be called the method - * definition tokens. - * - * @param ast the token being visited - */ - protected abstract void visitTokenHook(DetailAST ast); - - /** - * Hook called when leaving a token. Will not be called the method - * definition tokens. - * - * @param ast the token being left - */ - protected abstract void leaveTokenHook(DetailAST ast); - - @Override - public final int[] getRequiredTokens() { - return new int[] { - TokenTypes.CTOR_DEF, - TokenTypes.METHOD_DEF, - TokenTypes.INSTANCE_INIT, - TokenTypes.STATIC_INIT, - }; - } - - /** - * Set the maximum threshold allowed. - * - * @param max the maximum threshold - */ - public final void setMax(int max) { - this.max = max; - } - - @Override - public void visitToken(DetailAST ast) { - switch (ast.getType()) { - case TokenTypes.CTOR_DEF: - case TokenTypes.METHOD_DEF: - case TokenTypes.INSTANCE_INIT: - case TokenTypes.STATIC_INIT: - visitMethodDef(); - break; - default: - visitTokenHook(ast); - } - } - - @Override - public void leaveToken(DetailAST ast) { - switch (ast.getType()) { - case TokenTypes.CTOR_DEF: - case TokenTypes.METHOD_DEF: - case TokenTypes.INSTANCE_INIT: - case TokenTypes.STATIC_INIT: - leaveMethodDef(ast); - break; - default: - leaveTokenHook(ast); - } - } - - /** - * Gets the current value. - * @return the current value - */ - protected final BigInteger getCurrentValue() { - return currentValue; - } - - /** - * Set the current value. - * @param value the new value - */ - protected final void setCurrentValue(BigInteger value) { - currentValue = value; - } - - /** - * Increments the current value by a specified amount. - * - * @param amount the amount to increment by - */ - protected final void incrementCurrentValue(BigInteger amount) { - currentValue = currentValue.add(amount); - } - - /** Push the current value on the stack. */ - protected final void pushValue() { - valueStack.push(currentValue); - currentValue = INITIAL_VALUE; - } - - /** - * Pops a value off the stack and makes it the current value. - * @return pop a value off the stack and make it the current value - */ - protected final BigInteger popValue() { - currentValue = valueStack.pop(); - return currentValue; - } - - /** Process the start of the method definition. */ - private void visitMethodDef() { - pushValue(); - } - - /** - * Process the end of a method definition. - * - * @param ast the token representing the method definition - */ - private void leaveMethodDef(DetailAST ast) { - final BigInteger bigIntegerMax = BigInteger.valueOf(max); - if (currentValue.compareTo(bigIntegerMax) > 0) { - log(ast, getMessageID(), currentValue, bigIntegerMax); - } - popValue(); - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/BooleanExpressionComplexityCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,8 @@ import java.util.ArrayDeque; import java.util.Deque; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CheckUtils; @@ -37,7 +38,8 @@ * @author Simon Harris * @author o_sukhodolsky */ -public final class BooleanExpressionComplexityCheck extends Check { +@FileStatefulCheck +public final class BooleanExpressionComplexityCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -98,14 +100,6 @@ } /** - * Getter for maximum allowed complexity. - * @return value of maximum allowed complexity. - */ - public int getMax() { - return max; - } - - /** * Setter for maximum allowed complexity. * @param max new maximum allowed complexity. */ @@ -156,7 +150,7 @@ /** * Checks if {@link TokenTypes#BOR binary OR} is applied to exceptions * in - * + * * multi-catch (pipe-syntax). * @param binaryOr {@link TokenTypes#BOR binary or} * @return true if binary or is applied to exceptions in multi-catch. @@ -217,6 +211,7 @@ * @author o_sukhodolsky */ private class Context { + /** * Should we perform check in current context or not. * Usually false if we are inside equals() method. @@ -252,12 +247,14 @@ * @param ast a node we check now. */ public void checkCount(DetailAST ast) { - if (checking && count > getMax()) { + if (checking && count > max) { final DetailAST parentAST = ast.getParent(); log(parentAST.getLineNo(), parentAST.getColumnNo(), - MSG_KEY, count, getMax()); + MSG_KEY, count, max); } } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassDataAbstractionCouplingCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassDataAbstractionCouplingCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassDataAbstractionCouplingCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassDataAbstractionCouplingCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -43,13 +43,13 @@ /** Creates bew instance of the check. */ public ClassDataAbstractionCouplingCheck() { super(DEFAULT_MAX); - setTokens("LITERAL_NEW"); } @Override public int[] getRequiredTokens() { return new int[] { TokenTypes.PACKAGE_DEF, + TokenTypes.IMPORT, TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, TokenTypes.ENUM_DEF, @@ -59,17 +59,14 @@ @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.PACKAGE_DEF, - TokenTypes.CLASS_DEF, - TokenTypes.INTERFACE_DEF, - TokenTypes.ENUM_DEF, - TokenTypes.LITERAL_NEW, - }; + return getRequiredTokens(); } + // -@cs[SimpleAccessorNameNotation] Overrides method from the base class. + // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166 @Override protected String getLogMessageId() { return MSG_KEY; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassFanOutComplexityCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassFanOutComplexityCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassFanOutComplexityCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/ClassFanOutComplexityCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -49,6 +49,7 @@ public int[] getRequiredTokens() { return new int[] { TokenTypes.PACKAGE_DEF, + TokenTypes.IMPORT, TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, TokenTypes.ENUM_DEF, @@ -61,20 +62,14 @@ @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.PACKAGE_DEF, - TokenTypes.CLASS_DEF, - TokenTypes.INTERFACE_DEF, - TokenTypes.ENUM_DEF, - TokenTypes.TYPE, - TokenTypes.LITERAL_NEW, - TokenTypes.LITERAL_THROWS, - TokenTypes.ANNOTATION_DEF, - }; + return getRequiredTokens(); } + // -@cs[SimpleAccessorNameNotation] Override methods from base class. + // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166 @Override protected String getLogMessageId() { return MSG_KEY; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/CyclomaticComplexityCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/CyclomaticComplexityCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/CyclomaticComplexityCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/CyclomaticComplexityCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,7 +23,8 @@ import java.util.ArrayDeque; import java.util.Deque; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -45,8 +46,9 @@ * @author Oliver Burn * @author Andrei Selkin */ +@FileStatefulCheck public class CyclomaticComplexityCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -174,7 +176,7 @@ * * @param ast the token being visited */ - protected final void visitTokenHook(DetailAST ast) { + private void visitTokenHook(DetailAST ast) { if (switchBlockAsSingleDecisionPoint) { if (ast.getType() != TokenTypes.LITERAL_CASE) { incrementCurrentValue(BigInteger.ONE); @@ -203,27 +205,26 @@ * * @param amount the amount to increment by */ - protected final void incrementCurrentValue(BigInteger amount) { + private void incrementCurrentValue(BigInteger amount) { currentValue = currentValue.add(amount); } /** Push the current value on the stack. */ - protected final void pushValue() { + private void pushValue() { valueStack.push(currentValue); currentValue = INITIAL_VALUE; } /** * Pops a value off the stack and makes it the current value. - * @return pop a value off the stack and make it the current value */ - protected final BigInteger popValue() { + private void popValue() { currentValue = valueStack.pop(); - return currentValue; } /** Process the start of the method definition. */ private void visitMethodDef() { pushValue(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/JavaNCSSCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/JavaNCSSCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/JavaNCSSCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/JavaNCSSCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,8 @@ import java.util.ArrayDeque; import java.util.Deque; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -38,7 +39,10 @@ * * @author Lars Ködderitzsch */ -public class JavaNCSSCheck extends Check { +// -@cs[AbbreviationAsWordInName] We can not change it as, +// check's name is a part of API (used in configurations). +@FileStatefulCheck +public class JavaNCSSCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -81,36 +85,7 @@ @Override public int[] getDefaultTokens() { - return new int[] { - TokenTypes.CLASS_DEF, - TokenTypes.INTERFACE_DEF, - TokenTypes.METHOD_DEF, - TokenTypes.CTOR_DEF, - TokenTypes.INSTANCE_INIT, - TokenTypes.STATIC_INIT, - TokenTypes.PACKAGE_DEF, - TokenTypes.IMPORT, - TokenTypes.VARIABLE_DEF, - TokenTypes.CTOR_CALL, - TokenTypes.SUPER_CTOR_CALL, - TokenTypes.LITERAL_IF, - TokenTypes.LITERAL_ELSE, - TokenTypes.LITERAL_WHILE, - TokenTypes.LITERAL_DO, - TokenTypes.LITERAL_FOR, - TokenTypes.LITERAL_SWITCH, - TokenTypes.LITERAL_BREAK, - TokenTypes.LITERAL_CONTINUE, - TokenTypes.LITERAL_RETURN, - TokenTypes.LITERAL_THROW, - TokenTypes.LITERAL_SYNCHRONIZED, - TokenTypes.LITERAL_CATCH, - TokenTypes.LITERAL_FINALLY, - TokenTypes.EXPR, - TokenTypes.LABELED_STAT, - TokenTypes.LITERAL_CASE, - TokenTypes.LITERAL_DEFAULT, - }; + return getRequiredTokens(); } @Override @@ -149,36 +124,7 @@ @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.CLASS_DEF, - TokenTypes.INTERFACE_DEF, - TokenTypes.METHOD_DEF, - TokenTypes.CTOR_DEF, - TokenTypes.INSTANCE_INIT, - TokenTypes.STATIC_INIT, - TokenTypes.PACKAGE_DEF, - TokenTypes.IMPORT, - TokenTypes.VARIABLE_DEF, - TokenTypes.CTOR_CALL, - TokenTypes.SUPER_CTOR_CALL, - TokenTypes.LITERAL_IF, - TokenTypes.LITERAL_ELSE, - TokenTypes.LITERAL_WHILE, - TokenTypes.LITERAL_DO, - TokenTypes.LITERAL_FOR, - TokenTypes.LITERAL_SWITCH, - TokenTypes.LITERAL_BREAK, - TokenTypes.LITERAL_CONTINUE, - TokenTypes.LITERAL_RETURN, - TokenTypes.LITERAL_THROW, - TokenTypes.LITERAL_SYNCHRONIZED, - TokenTypes.LITERAL_CATCH, - TokenTypes.LITERAL_FINALLY, - TokenTypes.EXPR, - TokenTypes.LABELED_STAT, - TokenTypes.LITERAL_CASE, - TokenTypes.LITERAL_DEFAULT, - }; + return getRequiredTokens(); } @Override @@ -205,9 +151,7 @@ //check if token is countable if (isCountable(ast)) { //increment the stacked counters - for (final Counter counter : counters) { - counter.increment(); - } + counters.forEach(Counter::increment); } } @@ -371,6 +315,7 @@ * @author Lars Ködderitzsch */ private static class Counter { + /** The counters internal integer. */ private int count; @@ -389,5 +334,7 @@ public int getCount() { return count; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/NPathComplexityCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,7 +23,8 @@ import java.util.ArrayDeque; import java.util.Deque; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -37,7 +38,9 @@ * @author Simon Harris * @author o_sukhodolsky */ -public final class NPathComplexityCheck extends Check { +// -@cs[AbbreviationAsWordInName] Can't change check name +@FileStatefulCheck +public final class NPathComplexityCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -49,20 +52,36 @@ private static final int DEFAULT_MAX = 200; /** The initial current value. */ - private static final BigInteger INITIAL_VALUE = BigInteger.ONE; + private static final BigInteger INITIAL_VALUE = BigInteger.ZERO; - /** Stack of values - all but the current value. */ - private final Deque valueStack = new ArrayDeque<>(); + /** + * Stack of NP values for ranges. + */ + private final Deque rangeValues = new ArrayDeque<>(); + + /** Stack of NP values for expressions. */ + private final Deque expressionValues = new ArrayDeque<>(); + + /** Stack of belongs to range values for question operator. */ + private final Deque isAfterValues = new ArrayDeque<>(); - /** The current value. */ - private BigInteger currentValue = INITIAL_VALUE; + /** + * Range of the last processed expression. Used for checking that ternary operation + * which is a part of expression won't be processed for second time. + */ + private final TokenEnd processingTokenEnd = new TokenEnd(); + + /** NP value for current range. */ + private BigInteger currentRangeValue = INITIAL_VALUE; /** Threshold to report error for. */ private int max = DEFAULT_MAX; + /** True, when branch is visited, but not leaved. */ + private boolean branchVisited; + /** * Set the maximum threshold allowed. - * * @param max the maximum threshold */ public void setMax(int max) { @@ -71,26 +90,16 @@ @Override public int[] getDefaultTokens() { - return new int[] { - TokenTypes.CTOR_DEF, - TokenTypes.METHOD_DEF, - TokenTypes.STATIC_INIT, - TokenTypes.INSTANCE_INIT, - TokenTypes.LITERAL_WHILE, - TokenTypes.LITERAL_DO, - TokenTypes.LITERAL_FOR, - TokenTypes.LITERAL_IF, - TokenTypes.LITERAL_ELSE, - TokenTypes.LITERAL_SWITCH, - TokenTypes.LITERAL_CASE, - TokenTypes.LITERAL_TRY, - TokenTypes.LITERAL_CATCH, - TokenTypes.QUESTION, - }; + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { return new int[] { TokenTypes.CTOR_DEF, TokenTypes.METHOD_DEF, @@ -102,45 +111,63 @@ TokenTypes.LITERAL_IF, TokenTypes.LITERAL_ELSE, TokenTypes.LITERAL_SWITCH, - TokenTypes.LITERAL_CASE, + TokenTypes.CASE_GROUP, TokenTypes.LITERAL_TRY, TokenTypes.LITERAL_CATCH, TokenTypes.QUESTION, + TokenTypes.LITERAL_RETURN, + TokenTypes.LITERAL_DEFAULT, }; } @Override - public int[] getRequiredTokens() { - return new int[] { - TokenTypes.CTOR_DEF, - TokenTypes.METHOD_DEF, - TokenTypes.INSTANCE_INIT, - TokenTypes.STATIC_INIT, - }; + public void beginTree(DetailAST rootAST) { + rangeValues.clear(); + expressionValues.clear(); + isAfterValues.clear(); + processingTokenEnd.reset(); + currentRangeValue = INITIAL_VALUE; + branchVisited = false; } @Override public void visitToken(DetailAST ast) { switch (ast.getType()) { + case TokenTypes.LITERAL_IF: + case TokenTypes.LITERAL_SWITCH: case TokenTypes.LITERAL_WHILE: case TokenTypes.LITERAL_DO: case TokenTypes.LITERAL_FOR: - case TokenTypes.LITERAL_IF: + visitConditional(ast, 1); + break; case TokenTypes.QUESTION: - case TokenTypes.LITERAL_TRY: - case TokenTypes.LITERAL_SWITCH: - visitMultiplyingConditional(); + visitUnitaryOperator(ast, 2); + break; + case TokenTypes.LITERAL_RETURN: + visitUnitaryOperator(ast, 0); + break; + case TokenTypes.CASE_GROUP: + final int caseNumber = countCaseTokens(ast); + branchVisited = true; + pushValue(caseNumber); break; case TokenTypes.LITERAL_ELSE: + branchVisited = true; + if (currentRangeValue.equals(BigInteger.ZERO)) { + currentRangeValue = BigInteger.ONE; + } + pushValue(0); + break; + case TokenTypes.LITERAL_TRY: case TokenTypes.LITERAL_CATCH: - case TokenTypes.LITERAL_CASE: - visitAddingConditional(); + case TokenTypes.LITERAL_DEFAULT: + pushValue(1); break; case TokenTypes.CTOR_DEF: case TokenTypes.METHOD_DEF: case TokenTypes.INSTANCE_INIT: case TokenTypes.STATIC_INIT: - visitMethodDef(); + pushValue(0); break; default: break; @@ -154,16 +181,27 @@ case TokenTypes.LITERAL_DO: case TokenTypes.LITERAL_FOR: case TokenTypes.LITERAL_IF: - case TokenTypes.QUESTION: - case TokenTypes.LITERAL_TRY: case TokenTypes.LITERAL_SWITCH: + leaveConditional(); + break; + case TokenTypes.LITERAL_TRY: leaveMultiplyingConditional(); break; - case TokenTypes.LITERAL_ELSE: + case TokenTypes.LITERAL_RETURN: + case TokenTypes.QUESTION: + leaveUnitaryOperator(); + break; case TokenTypes.LITERAL_CATCH: - case TokenTypes.LITERAL_CASE: leaveAddingConditional(); break; + case TokenTypes.LITERAL_DEFAULT: + leaveBranch(); + break; + case TokenTypes.LITERAL_ELSE: + case TokenTypes.CASE_GROUP: + leaveBranch(); + branchVisited = false; + break; case TokenTypes.CTOR_DEF: case TokenTypes.METHOD_DEF: case TokenTypes.INSTANCE_INIT: @@ -175,56 +213,274 @@ } } - /** Visits else, catch or case. */ - private void visitAddingConditional() { - pushValue(); + /** + * Visits if, while, do-while, for and switch tokens - all of them have expression in + * parentheses which is used for calculation. + * @param ast visited token. + * @param basicBranchingFactor default number of branches added. + */ + private void visitConditional(DetailAST ast, int basicBranchingFactor) { + int expressionValue = basicBranchingFactor; + DetailAST bracketed; + for (bracketed = ast.findFirstToken(TokenTypes.LPAREN).getNextSibling(); + bracketed.getType() != TokenTypes.RPAREN; + bracketed = bracketed.getNextSibling()) { + expressionValue += countConditionalOperators(bracketed); + } + processingTokenEnd.setToken(bracketed); + pushValue(expressionValue); + } + + /** + * Visits ternary operator (?:) and return tokens. They differ from those processed by + * visitConditional method in that their expression isn't bracketed. + * @param ast visited token. + * @param basicBranchingFactor number of branches inherently added by this token. + */ + private void visitUnitaryOperator(DetailAST ast, int basicBranchingFactor) { + final boolean isAfter = processingTokenEnd.isAfter(ast); + isAfterValues.push(isAfter); + if (!isAfter) { + processingTokenEnd.setToken(getLastToken(ast)); + final int expressionValue = basicBranchingFactor + countConditionalOperators(ast); + pushValue(expressionValue); + } } - /** Leaves else, catch or case. */ + /** + * Leaves ternary operator (?:) and return tokens. + */ + private void leaveUnitaryOperator() { + if (!isAfterValues.pop()) { + final Values valuePair = popValue(); + BigInteger basicRangeValue = valuePair.getRangeValue(); + BigInteger expressionValue = valuePair.getExpressionValue(); + if (expressionValue.equals(BigInteger.ZERO)) { + expressionValue = BigInteger.ONE; + } + if (basicRangeValue.equals(BigInteger.ZERO)) { + basicRangeValue = BigInteger.ONE; + } + currentRangeValue = currentRangeValue.add(expressionValue).multiply(basicRangeValue); + } + } + + /** Leaves while, do, for, if, ternary (?::), return or switch. */ + private void leaveConditional() { + final Values valuePair = popValue(); + final BigInteger expressionValue = valuePair.getExpressionValue(); + BigInteger basicRangeValue = valuePair.getRangeValue(); + if (currentRangeValue.equals(BigInteger.ZERO)) { + currentRangeValue = BigInteger.ONE; + } + if (basicRangeValue.equals(BigInteger.ZERO)) { + basicRangeValue = BigInteger.ONE; + } + currentRangeValue = currentRangeValue.add(expressionValue).multiply(basicRangeValue); + } + + /** Leaves else, default or case group tokens. */ + private void leaveBranch() { + final Values valuePair = popValue(); + final BigInteger basicRangeValue = valuePair.getRangeValue(); + final BigInteger expressionValue = valuePair.getExpressionValue(); + if (branchVisited && currentRangeValue.equals(BigInteger.ZERO)) { + currentRangeValue = BigInteger.ONE; + } + currentRangeValue = currentRangeValue.subtract(BigInteger.ONE) + .add(basicRangeValue) + .add(expressionValue); + } + + /** + * Process the end of a method definition. + * @param ast the token type representing the method definition + */ + private void leaveMethodDef(DetailAST ast) { + final BigInteger bigIntegerMax = BigInteger.valueOf(max); + if (currentRangeValue.compareTo(bigIntegerMax) > 0) { + log(ast, MSG_KEY, currentRangeValue, bigIntegerMax); + } + popValue(); + currentRangeValue = INITIAL_VALUE; + } + + /** Leaves catch. */ private void leaveAddingConditional() { - currentValue = currentValue.subtract(BigInteger.ONE).add(popValue()); + currentRangeValue = currentRangeValue.add(popValue().getRangeValue().add(BigInteger.ONE)); } - /** Visits while, do, for, if, try, ? (in ?::) or switch. */ - private void visitMultiplyingConditional() { - pushValue(); + /** + * Pushes the current range value on the range value stack. Pushes this token expression value + * on the expression value stack. + * @param expressionValue value of expression calculated for current token. + */ + private void pushValue(Integer expressionValue) { + rangeValues.push(currentRangeValue); + expressionValues.push(expressionValue); + currentRangeValue = INITIAL_VALUE; } - /** Leaves while, do, for, if, try, ? (in ?::) or switch. */ + /** + * Pops values from both stack of expression values and stack of range values. + * @return pair of head values from both of the stacks. + */ + private Values popValue() { + final int expressionValue = expressionValues.pop(); + return new Values(rangeValues.pop(), BigInteger.valueOf(expressionValue)); + } + + /** Leaves try. */ private void leaveMultiplyingConditional() { - currentValue = currentValue.add(BigInteger.ONE).multiply(popValue()); + currentRangeValue = currentRangeValue.add(BigInteger.ONE) + .multiply(popValue().getRangeValue().add(BigInteger.ONE)); } - /** Push the current value on the stack. */ - private void pushValue() { - valueStack.push(currentValue); - currentValue = INITIAL_VALUE; + /** + * Calculates number of conditional operators, including inline ternary operator, for a token. + * @param ast inspected token. + * @return number of conditional operators. + * @see + * Java Language Specification, §15.23 + * @see + * Java Language Specification, §15.24 + * @see + * Java Language Specification, §15.25 + */ + private static int countConditionalOperators(DetailAST ast) { + int number = 0; + for (DetailAST child = ast.getFirstChild(); child != null; + child = child.getNextSibling()) { + final int type = child.getType(); + if (type == TokenTypes.LOR || type == TokenTypes.LAND) { + number++; + } + else if (type == TokenTypes.QUESTION) { + number += 2; + } + number += countConditionalOperators(child); + } + return number; } /** - * Pops a value off the stack and makes it the current value. - * @return pop a value off the stack and make it the current value + * Finds a leaf, which is the most distant from the root. + * @param ast the root of tree. + * @return the leaf. */ - private BigInteger popValue() { - currentValue = valueStack.pop(); - return currentValue; + private static DetailAST getLastToken(DetailAST ast) { + final DetailAST lastChild = ast.getLastChild(); + final DetailAST result; + if (lastChild.getFirstChild() == null) { + result = lastChild; + } + else { + result = getLastToken(lastChild); + } + return result; } - /** Process the start of the method definition. */ - private void visitMethodDef() { - pushValue(); + /** + * Counts number of case tokens subject to a case group token. + * @param ast case group token. + * @return number of case tokens. + */ + private static int countCaseTokens(DetailAST ast) { + int counter = 0; + for (DetailAST iterator = ast.getFirstChild(); iterator != null; + iterator = iterator.getNextSibling()) { + if (iterator.getType() == TokenTypes.LITERAL_CASE) { + counter++; + } + } + return counter; } /** - * Process the end of a method definition. - * - * @param ast the token representing the method definition + * Coordinates of token end. Used to prevent inline ternary + * operator from being processed twice. */ - private void leaveMethodDef(DetailAST ast) { - final BigInteger bigIntegerMax = BigInteger.valueOf(max); - if (currentValue.compareTo(bigIntegerMax) > 0) { - log(ast, MSG_KEY, currentValue, bigIntegerMax); + private static class TokenEnd { + + /** End line of token. */ + private int endLineNo; + + /** End column of token. */ + private int endColumnNo; + + /** + * Sets end coordinates from given token. + * @param endToken token. + */ + public void setToken(DetailAST endToken) { + if (!isAfter(endToken)) { + endLineNo = endToken.getLineNo(); + endColumnNo = endToken.getColumnNo(); + } } - popValue(); + + /** Sets end token coordinates to the start of the file. */ + public void reset() { + endLineNo = 0; + endColumnNo = 0; + } + + /** + * Checks if saved coordinates located after given token. + * @param ast given token. + * @return true, if saved coordinates located after given token. + */ + public boolean isAfter(DetailAST ast) { + final int lineNo = ast.getLineNo(); + final int columnNo = ast.getColumnNo(); + boolean isAfter = true; + if (lineNo > endLineNo + || lineNo == endLineNo + && columnNo > endColumnNo) { + isAfter = false; + } + return isAfter; + } + } + + /** + * Class that store range value and expression value. + */ + private static class Values { + + /** NP value for range. */ + private final BigInteger rangeValue; + + /** NP value for expression. */ + private final BigInteger expressionValue; + + /** + * Constructor that assigns all of class fields. + * @param valueOfRange NP value for range + * @param valueOfExpression NP value for expression + */ + Values(BigInteger valueOfRange, BigInteger valueOfExpression) { + rangeValue = valueOfRange; + expressionValue = valueOfExpression; + } + + /** + * Returns NP value for range. + * @return NP value for range + */ + public BigInteger getRangeValue() { + return rangeValue; + } + + /** + * Returns NP value for expression. + * @return NP value for expression + */ + public BigInteger getExpressionValue() { + return expressionValue; + } + + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/metrics/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/ModifierOrderCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/ModifierOrderCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/ModifierOrderCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/ModifierOrderCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,11 +19,12 @@ package com.puppycrawl.tools.checkstyle.checks.modifier; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import com.google.common.collect.Lists; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -31,7 +32,7 @@ *

    * Checks that the order of modifiers conforms to the suggestions in the * + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html"> * Java Language specification, sections 8.1.1, 8.3.1 and 8.4.3. * The correct order is:

    @@ -41,6 +42,7 @@
  • private
  • abstract
  • +
  • default
  • static
  • final
  • transient
  • @@ -64,8 +66,9 @@ *
    * @author Lars Kühne */ +@StatelessCheck public class ModifierOrderCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -84,28 +87,28 @@ * 8.3.1 and 8.4.3 of the JLS. */ private static final String[] JLS_ORDER = { - "public", "protected", "private", "abstract", "static", "final", - "transient", "volatile", "synchronized", "native", "strictfp", "default", + "public", "protected", "private", "abstract", "default", "static", + "final", "transient", "volatile", "synchronized", "native", "strictfp", }; @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.MODIFIERS}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.MODIFIERS}; } @Override public void visitToken(DetailAST ast) { - final List mods = Lists.newArrayList(); + final List mods = new ArrayList<>(); DetailAST modifier = ast.getFirstChild(); while (modifier != null) { mods.add(modifier); @@ -152,10 +155,11 @@ while (modifier != null && offendingModifier == null) { - if (modifier.getType() == TokenTypes.ANNOTATION) { - //Annotation not at start of modifiers, bad - offendingModifier = modifier; + if (!isAnnotationOnType(modifier)) { + //Annotation not at start of modifiers, bad + offendingModifier = modifier; + } break; } @@ -189,8 +193,33 @@ DetailAST modifier; do { modifier = modifierIterator.next(); - } - while (modifierIterator.hasNext() && modifier.getType() == TokenTypes.ANNOTATION); + } while (modifierIterator.hasNext() && modifier.getType() == TokenTypes.ANNOTATION); return modifier; } + + /** + * Checks whether annotation on type takes place. + * @param modifier modifier token. + * @return true if annotation on type takes place. + */ + private static boolean isAnnotationOnType(DetailAST modifier) { + boolean annotationOnType = false; + final DetailAST modifiers = modifier.getParent(); + final DetailAST definition = modifiers.getParent(); + final int definitionType = definition.getType(); + if (definitionType == TokenTypes.VARIABLE_DEF + || definitionType == TokenTypes.PARAMETER_DEF + || definitionType == TokenTypes.CTOR_DEF) { + annotationOnType = true; + } + else if (definitionType == TokenTypes.METHOD_DEF) { + final DetailAST typeToken = definition.findFirstToken(TokenTypes.TYPE); + final int methodReturnType = typeToken.getLastChild().getType(); + if (methodReturnType != TokenTypes.LITERAL_VOID) { + annotationOnType = true; + } + } + return annotationOnType; + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/RedundantModifierCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/RedundantModifierCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/RedundantModifierCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/modifier/RedundantModifierCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,27 +22,27 @@ import java.util.ArrayList; import java.util.List; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * Checks for redundant modifiers in interface and annotation definitions, - * final modifier on methods of final classes, inner interface - * declarations that are declared as static, non public class + * final modifier on methods of final classes, inner {@code interface} + * declarations that are declared as {@code static}, non public class * constructors and enum constructors, nested enum definitions that are declared - * as static. + * as {@code static}. * - *

    Interfaces by definition are abstract so the abstract + *

    Interfaces by definition are abstract so the {@code abstract} * modifier on the interface is redundant. * *

    Classes inside of interfaces by definition are public and static, - * so the public and static modifiers + * so the {@code public} and {@code static} modifiers * on the inner classes are redundant. On the other hand, classes * inside of interfaces can be abstract or non abstract. - * So, abstract modifier is allowed. + * So, {@code abstract} modifier is allowed. * *

    Fields in interfaces and annotations are automatically * public, static and final, so these modifiers are redundant as @@ -53,10 +53,29 @@ * annotation fields are automatically public and abstract.

    * *

    Enums by definition are static implicit subclasses of java.lang.Enum<E>. - * So, the static modifier on the enums is redundant. In addition, - * if enum is inside of interface, public modifier is also redundant. + * So, the {@code static} modifier on the enums is redundant. In addition, + * if enum is inside of interface, {@code public} modifier is also redundant.

    + * + *

    Enums can also contain abstract methods and methods which can be overridden by the declared + * enumeration fields. + * See the following example:

    + *
    + * public enum EnumClass {
    + *    FIELD_1,
    + *    FIELD_2 {
    + *        @Override
    + *        public final void method1() {} // violation expected
    + *    };
    + *
    + *    public void method1() {}
    + *    public final void method2() {} // no violation expected
    + * }
    + * 
    + * + *

    Since these methods can be overridden in these situations, the final methods are not + * marked as redundant even though they can't be extended by other classes/enums.

    * - *

    Final classes by definition cannot be extended so the final + *

    Final classes by definition cannot be extended so the {@code final} * modifier on the method of a final class is redundant. * *

    Public modifier for constructors in non-public non-protected classes @@ -96,8 +115,9 @@ * @author Andrei Selkin * @author Vladislav Lisetskiy */ +@StatelessCheck public class RedundantModifierCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -120,7 +140,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -133,6 +153,7 @@ TokenTypes.CTOR_DEF, TokenTypes.CLASS_DEF, TokenTypes.ENUM_DEF, + TokenTypes.RESOURCE, }; } @@ -141,22 +162,28 @@ if (ast.getType() == TokenTypes.INTERFACE_DEF) { checkInterfaceModifiers(ast); } - else if (ast.getType() == TokenTypes.CTOR_DEF) { - if (isEnumMember(ast)) { - checkEnumConstructorModifiers(ast); - } - else { - checkClassConstructorModifiers(ast); - } - } else if (ast.getType() == TokenTypes.ENUM_DEF) { checkEnumDef(ast); } - else if (isInterfaceOrAnnotationMember(ast)) { - processInterfaceOrAnnotation(ast); - } - else if (ast.getType() == TokenTypes.METHOD_DEF) { - processMethods(ast); + else { + if (ast.getType() == TokenTypes.CTOR_DEF) { + if (isEnumMember(ast)) { + checkEnumConstructorModifiers(ast); + } + else { + checkClassConstructorModifiers(ast); + } + } + else if (ast.getType() == TokenTypes.METHOD_DEF) { + processMethods(ast); + } + else if (ast.getType() == TokenTypes.RESOURCE) { + processResources(ast); + } + + if (isInterfaceOrAnnotationMember(ast)) { + processInterfaceOrAnnotation(ast); + } } } @@ -184,7 +211,8 @@ */ private void checkEnumConstructorModifiers(DetailAST ast) { final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); - final DetailAST modifier = modifiers.getFirstChild(); + final DetailAST modifier = getFirstModifierAst(modifiers); + if (modifier != null) { log(modifier.getLineNo(), modifier.getColumnNo(), MSG_KEY, modifier.getText()); @@ -192,6 +220,21 @@ } /** + * Retrieves the first modifier that is not an annotation. + * @param modifiers The ast to examine. + * @return The first modifier or {@code null} if none found. + */ + private static DetailAST getFirstModifierAst(DetailAST modifiers) { + DetailAST modifier = modifiers.getFirstChild(); + + while (modifier != null && modifier.getType() == TokenTypes.ANNOTATION) { + modifier = modifier.getNextSibling(); + } + + return modifier; + } + + /** * Checks whether enum has proper modifiers. * @param ast enum definition. */ @@ -200,12 +243,7 @@ processInterfaceOrAnnotation(ast); } else if (ast.getParent() != null) { - final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); - final DetailAST staticModifier = modifiers.findFirstToken(TokenTypes.LITERAL_STATIC); - if (staticModifier != null) { - log(staticModifier.getLineNo(), staticModifier.getColumnNo(), - MSG_KEY, staticModifier.getText()); - } + checkForRedundantModifier(ast, TokenTypes.LITERAL_STATIC); } } @@ -217,7 +255,6 @@ final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); DetailAST modifier = modifiers.getFirstChild(); while (modifier != null) { - // javac does not allow final or static in interface methods // order annotation fields hence no need to check that this // is not a method or annotation field @@ -240,7 +277,7 @@ } /** - * Process validation ofMethods. + * Process validation of Methods. * @param ast method AST */ private void processMethods(DetailAST ast) { @@ -248,34 +285,49 @@ ast.findFirstToken(TokenTypes.MODIFIERS); // private method? boolean checkFinal = - modifiers.branchContains(TokenTypes.LITERAL_PRIVATE); + modifiers.findFirstToken(TokenTypes.LITERAL_PRIVATE) != null; // declared in a final class? DetailAST parent = ast.getParent(); - while (parent != null) { + while (parent != null && !checkFinal) { if (parent.getType() == TokenTypes.CLASS_DEF) { final DetailAST classModifiers = parent.findFirstToken(TokenTypes.MODIFIERS); - checkFinal = checkFinal || classModifiers.branchContains(TokenTypes.FINAL); + checkFinal = classModifiers.findFirstToken(TokenTypes.FINAL) != null; parent = null; } - else if (parent.getType() == TokenTypes.LITERAL_NEW) { + else if (parent.getType() == TokenTypes.LITERAL_NEW + || parent.getType() == TokenTypes.ENUM_CONSTANT_DEF) { checkFinal = true; parent = null; } + else if (parent.getType() == TokenTypes.ENUM_DEF) { + checkFinal = modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null; + parent = null; + } else { parent = parent.getParent(); } } if (checkFinal && !isAnnotatedWithSafeVarargs(ast)) { - DetailAST modifier = modifiers.getFirstChild(); - while (modifier != null) { - final int type = modifier.getType(); - if (type == TokenTypes.FINAL) { - log(modifier.getLineNo(), modifier.getColumnNo(), - MSG_KEY, modifier.getText()); - break; - } - modifier = modifier.getNextSibling(); + checkForRedundantModifier(ast, TokenTypes.FINAL); + } + + if (ast.findFirstToken(TokenTypes.SLIST) == null) { + processAbstractMethodParameters(ast); + } + } + + /** + * Process validation of parameters for Methods with no definition. + * @param ast method AST + */ + private void processAbstractMethodParameters(DetailAST ast) { + final DetailAST parameters = ast.findFirstToken(TokenTypes.PARAMETERS); + + for (DetailAST child = parameters.getFirstChild(); child != null; child = child + .getNextSibling()) { + if (child.getType() == TokenTypes.PARAMETER_DEF) { + checkForRedundantModifier(child, TokenTypes.FINAL); } } } @@ -287,19 +339,28 @@ private void checkClassConstructorModifiers(DetailAST classCtorAst) { final DetailAST classDef = classCtorAst.getParent().getParent(); if (!isClassPublic(classDef) && !isClassProtected(classDef)) { - checkForRedundantPublicModifier(classCtorAst); + checkForRedundantModifier(classCtorAst, TokenTypes.LITERAL_PUBLIC); } } /** - * Checks if given ast has redundant public modifier. + * Checks if given resource has redundant modifiers. * @param ast ast */ - private void checkForRedundantPublicModifier(DetailAST ast) { + private void processResources(DetailAST ast) { + checkForRedundantModifier(ast, TokenTypes.FINAL); + } + + /** + * Checks if given ast has a redundant modifier. + * @param ast ast + * @param modifierType The modifier to check for. + */ + private void checkForRedundantModifier(DetailAST ast, int modifierType) { final DetailAST astModifiers = ast.findFirstToken(TokenTypes.MODIFIERS); DetailAST astModifier = astModifiers.getFirstChild(); while (astModifier != null) { - if (astModifier.getType() == TokenTypes.LITERAL_PUBLIC) { + if (astModifier.getType() == modifierType) { log(astModifier.getLineNo(), astModifier.getColumnNo(), MSG_KEY, astModifier.getText()); } @@ -316,7 +377,7 @@ private static boolean isClassProtected(DetailAST classDef) { final DetailAST classModifiers = classDef.findFirstToken(TokenTypes.MODIFIERS); - return classModifiers.branchContains(TokenTypes.LITERAL_PROTECTED); + return classModifiers.findFirstToken(TokenTypes.LITERAL_PROTECTED) != null; } /** @@ -328,7 +389,8 @@ boolean isAccessibleFromPublic = false; final boolean isMostOuterScope = ast.getParent() == null; final DetailAST modifiersAst = ast.findFirstToken(TokenTypes.MODIFIERS); - final boolean hasPublicModifier = modifiersAst.branchContains(TokenTypes.LITERAL_PUBLIC); + final boolean hasPublicModifier = + modifiersAst.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null; if (isMostOuterScope) { isAccessibleFromPublic = hasPublicModifier; @@ -371,7 +433,7 @@ } /** - * Checks if method definition is annotated with + * Checks if method definition is annotated with. * * SafeVarargs annotation * @param methodDef method definition node @@ -406,4 +468,5 @@ } return annotationsList; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbbreviationAsWordInNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbbreviationAsWordInNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbbreviationAsWordInNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbbreviationAsWordInNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,21 +24,34 @@ import java.util.LinkedList; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CheckUtils; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    * The Check validate abbreviations(consecutive capital letters) length in * identifier name, it also allows to enforce camel case naming. Please read more at - * + * * Google Style Guide to get to know how to avoid long abbreviations in names. *

    *

    + * {@code allowedAbbreviationLength} specifies how many consecutive capital letters are + * allowed in the identifier. + * A value of 3 indicates that up to 4 consecutive capital letters are allowed, + * one after the other, before a violation is printed. The identifier 'MyTEST' would be + * allowed, but 'MyTESTS' would not be. + * A value of 0 indicates that only 1 consecutive capital letter is allowed. This + * is what should be used to enforce strict camel casing. The identifier 'MyTest' would + * be allowed, but 'MyTEst' would not be. + *

    + *

    * Option {@code allowedAbbreviationLength} indicates on the allowed amount of capital * letters in abbreviations in the classes, interfaces, * variables and methods names. Default value is '3'. @@ -81,7 +94,8 @@ * * @author Roman Ivanov, Daniil Yaroslvtsev, Baratali Izmailov */ -public class AbbreviationAsWordInNameCheck extends Check { +@StatelessCheck +public class AbbreviationAsWordInNameCheck extends AbstractCheck { /** * Warning message key. @@ -157,10 +171,10 @@ * an string of abbreviations that must be skipped from checking, * each abbreviation separated by comma. */ - public void setAllowedAbbreviations(String allowedAbbreviations) { + public void setAllowedAbbreviations(String... allowedAbbreviations) { if (allowedAbbreviations != null) { - this.allowedAbbreviations = new HashSet<>( - Arrays.asList(allowedAbbreviations.split(","))); + this.allowedAbbreviations = + Arrays.stream(allowedAbbreviations).collect(Collectors.toSet()); } } @@ -195,20 +209,18 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override public void visitToken(DetailAST ast) { - if (!isIgnoreSituation(ast)) { - final DetailAST nameAst = ast.findFirstToken(TokenTypes.IDENT); final String typeName = nameAst.getText(); final String abbr = getDisallowedAbbreviation(typeName); if (abbr != null) { - log(nameAst.getLineNo(), MSG_KEY, typeName, allowedAbbreviationLength); + log(nameAst.getLineNo(), MSG_KEY, typeName, allowedAbbreviationLength + 1); } } } @@ -218,11 +230,12 @@ * @param ast input DetailAST node. * @return true if it is an ignore situation found for given input DetailAST * node. + * @noinspection SimplifiableIfStatement */ private boolean isIgnoreSituation(DetailAST ast) { final DetailAST modifiers = ast.getFirstChild(); - boolean result = false; + final boolean result; if (ast.getType() == TokenTypes.VARIABLE_DEF) { if ((ignoreFinal || ignoreStatic) && isInterfaceDeclaration(ast)) { @@ -231,14 +244,16 @@ } else { result = ignoreFinal - && modifiers.branchContains(TokenTypes.FINAL) + && modifiers.findFirstToken(TokenTypes.FINAL) != null || ignoreStatic - && modifiers.branchContains(TokenTypes.LITERAL_STATIC); + && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null; } } else if (ast.getType() == TokenTypes.METHOD_DEF) { - result = ignoreOverriddenMethods - && hasOverrideAnnotation(modifiers); + result = ignoreOverriddenMethods && hasOverrideAnnotation(modifiers); + } + else { + result = CheckUtils.isReceiverParameter(ast); } return result; } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractAccessControlNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractAccessControlNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractAccessControlNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractAccessControlNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -46,6 +46,7 @@ */ public abstract class AbstractAccessControlNameCheck extends AbstractNameCheck { + /** If true, applies the check be public members. */ private boolean applyToPublic = true; @@ -70,7 +71,7 @@ @Override protected boolean mustCheckName(DetailAST ast) { - return shouldCheckInScope(ast); + return shouldCheckInScope(ast.findFirstToken(TokenTypes.MODIFIERS)); } /** @@ -82,11 +83,11 @@ */ protected boolean shouldCheckInScope(DetailAST modifiers) { final boolean isPublic = modifiers - .branchContains(TokenTypes.LITERAL_PUBLIC); + .findFirstToken(TokenTypes.LITERAL_PUBLIC) != null; final boolean isProtected = modifiers - .branchContains(TokenTypes.LITERAL_PROTECTED); + .findFirstToken(TokenTypes.LITERAL_PROTECTED) != null; final boolean isPrivate = modifiers - .branchContains(TokenTypes.LITERAL_PRIVATE); + .findFirstToken(TokenTypes.LITERAL_PRIVATE) != null; final boolean isPackage = !(isPublic || isProtected || isPrivate); return applyToPublic && isPublic @@ -130,4 +131,5 @@ public void setApplyToPrivate(boolean applyTo) { applyToPrivate = applyTo; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractClassNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractClassNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractClassNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractClassNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,10 +21,10 @@ import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    @@ -42,7 +42,8 @@ * @author Simon Harris * @author Danil Lopatin */ -public final class AbstractClassNameCheck extends Check { +@StatelessCheck +public final class AbstractClassNameCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -62,11 +63,8 @@ /** Whether to ignore checking the name. */ private boolean ignoreName; - /** The format string of the regexp. */ - private String format = "^Abstract.+$"; - /** The regexp to match against. */ - private Pattern regexp = Pattern.compile(format); + private Pattern format = Pattern.compile("^Abstract.+$"); /** * Whether to ignore checking for the {@code abstract} modifier. @@ -85,18 +83,16 @@ } /** - * Set the format to the specified regular expression. - * @param format a {@code String} value - * @throws org.apache.commons.beanutils.ConversionException unable to parse format - */ - public void setFormat(String format) { - this.format = format; - regexp = CommonUtils.createPattern(format); + * Set the format for the specified regular expression. + * @param pattern the new pattern + */ + public void setFormat(Pattern pattern) { + format = pattern; } @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.CLASS_DEF}; + return getRequiredTokens(); } @Override @@ -106,7 +102,7 @@ @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.CLASS_DEF}; + return getRequiredTokens(); } @Override @@ -125,7 +121,7 @@ // if class has abstract modifier if (!ignoreName && !isMatchingClassName(className)) { log(ast.getLineNo(), ast.getColumnNo(), - MSG_ILLEGAL_ABSTRACT_CLASS_NAME, className, format); + MSG_ILLEGAL_ABSTRACT_CLASS_NAME, className, format.pattern()); } } else if (!ignoreModifier && isMatchingClassName(className)) { @@ -135,6 +131,7 @@ } /** + * Checks if declared class is abstract or not. * @param ast class definition for check. * @return true if a given class declared as abstract. */ @@ -146,10 +143,12 @@ } /** + * Returns true if class name matches format of abstract class names. * @param className class name for check. * @return true if class name matches format of abstract class names. */ private boolean isMatchingClassName(String className) { - return regexp.matcher(className).find(); + return format.matcher(className).find(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,7 +21,8 @@ import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -31,25 +32,24 @@ * * @author Rick Giles */ +@StatelessCheck public abstract class AbstractNameCheck - extends Check { + extends AbstractCheck { + /** * Message key for invalid pattern error. */ public static final String MSG_INVALID_PATTERN = "name.invalidPattern"; - /** The format string of the regexp. */ - private String format; - /** The regexp to match against. */ - private Pattern regexp; + private Pattern format; /** * Creates a new {@code AbstractNameCheck} instance. * @param format format to check with */ protected AbstractNameCheck(String format) { - setFormat(format); + this.format = CommonUtils.createPattern(format); } /** @@ -62,26 +62,25 @@ protected abstract boolean mustCheckName(DetailAST ast); /** - * Set the format to the specified regular expression. - * @param format a {@code String} value - * @throws org.apache.commons.beanutils.ConversionException unable to parse format + * Set the format for the specified regular expression. + * @param pattern the new pattern */ - public final void setFormat(String format) { - this.format = format; - regexp = CommonUtils.createPattern(format); + public final void setFormat(Pattern pattern) { + format = pattern; } @Override public void visitToken(DetailAST ast) { if (mustCheckName(ast)) { final DetailAST nameAST = ast.findFirstToken(TokenTypes.IDENT); - if (!regexp.matcher(nameAST.getText()).find()) { + if (!format.matcher(nameAST.getText()).find()) { log(nameAST.getLineNo(), nameAST.getColumnNo(), MSG_INVALID_PATTERN, nameAST.getText(), - format); + format.pattern()); } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractTypeParameterNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractTypeParameterNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractTypeParameterNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AbstractTypeParameterNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -75,4 +75,5 @@ ast.getParent().getParent(); return location.getType() == getLocation(); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AccessModifier.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AccessModifier.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AccessModifier.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/AccessModifier.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,65 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.naming; + +import java.util.Locale; + +/** + * This enum represents access modifiers. + * Access modifiers names are taken from JLS: + * https://docs.oracle.com/javase/specs/jls/se8/html/jls-6.html#jls-6.6 + * + * @author Andrei Selkin + */ +public enum AccessModifier { + + /** Public access modifier. */ + PUBLIC, + /** Protected access modifier. */ + PROTECTED, + /** Package access modifier. */ + PACKAGE, + /** Private access modifier. */ + PRIVATE; + + @Override + public String toString() { + return getName(); + } + + private String getName() { + return name().toLowerCase(Locale.ENGLISH); + } + + /** + * Factory method which returns an AccessModifier instance that corresponds to the + * given access modifier name represented as a {@link String}. + * The access modifier name can be formatted both as lower case or upper case string. + * For example, passing PACKAGE or package as a modifier name + * will return {@link AccessModifier#PACKAGE}. + * + * @param modifierName access modifier name represented as a {@link String}. + * @return the AccessModifier associated with given access modifier name. + */ + public static AccessModifier getInstance(String modifierName) { + return valueOf(AccessModifier.class, modifierName.trim().toUpperCase(Locale.ENGLISH)); + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/CatchParameterNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/CatchParameterNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/CatchParameterNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/CatchParameterNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -71,21 +71,22 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.PARAMETER_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.PARAMETER_DEF}; } @Override protected boolean mustCheckName(DetailAST ast) { return ast.getParent().getType() == TokenTypes.LITERAL_CATCH; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ClassTypeParameterNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ClassTypeParameterNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ClassTypeParameterNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ClassTypeParameterNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -49,6 +49,7 @@ */ public class ClassTypeParameterNameCheck extends AbstractNameCheck { + /** Creates a new {@code ClassTypeParameterNameCheck} instance. */ public ClassTypeParameterNameCheck() { super("^[A-Z]$"); @@ -56,19 +57,19 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public final int[] getAcceptableTokens() { - return new int[] { - TokenTypes.TYPE_PARAMETER, - }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] { + TokenTypes.TYPE_PARAMETER, + }; } @Override @@ -77,4 +78,5 @@ ast.getParent().getParent(); return location.getType() == TokenTypes.CLASS_DEF; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ConstantNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ConstantNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ConstantNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ConstantNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -55,6 +55,7 @@ */ public class ConstantNameCheck extends AbstractAccessControlNameCheck { + /** Creates a new {@code ConstantNameCheck} instance. */ public ConstantNameCheck() { super("^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$"); @@ -62,17 +63,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.VARIABLE_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.VARIABLE_DEF}; } @Override @@ -81,8 +82,8 @@ final DetailAST modifiersAST = ast.findFirstToken(TokenTypes.MODIFIERS); - final boolean isStatic = modifiersAST.branchContains(TokenTypes.LITERAL_STATIC); - final boolean isFinal = modifiersAST.branchContains(TokenTypes.FINAL); + final boolean isStatic = modifiersAST.findFirstToken(TokenTypes.LITERAL_STATIC) != null; + final boolean isFinal = modifiersAST.findFirstToken(TokenTypes.FINAL) != null; if (isStatic && isFinal && shouldCheckInScope(modifiersAST) || ScopeUtils.isInAnnotationBlock(ast) @@ -99,4 +100,5 @@ return returnValue; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/InterfaceTypeParameterNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/InterfaceTypeParameterNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/InterfaceTypeParameterNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/InterfaceTypeParameterNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -49,6 +49,7 @@ */ public class InterfaceTypeParameterNameCheck extends AbstractNameCheck { + /** Creates a new {@code InterfaceTypeParameterNameCheck} instance. */ public InterfaceTypeParameterNameCheck() { super("^[A-Z]$"); @@ -56,19 +57,19 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.TYPE_PARAMETER, - }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] { + TokenTypes.TYPE_PARAMETER, + }; } @Override @@ -77,4 +78,5 @@ ast.getParent().getParent(); return location.getType() == TokenTypes.INTERFACE_DEF; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/LocalFinalVariableNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/LocalFinalVariableNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/LocalFinalVariableNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/LocalFinalVariableNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,17 +19,16 @@ package com.puppycrawl.tools.checkstyle.checks.naming; -import org.apache.commons.lang3.ArrayUtils; - import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; /** *

    * Checks that local final variable names conform to a format specified - * by the format property. A catch parameter is considered to be - * a local variable.The format is a + * by the format property. A catch parameter and resources in try statements + * are considered to be a local variables.The format is a * {@link java.util.regex.Pattern regular expression} and defaults to * ^[a-z][a-zA-Z0-9]*$. *

    @@ -53,6 +52,7 @@ */ public class LocalFinalVariableNameCheck extends AbstractNameCheck { + /** Creates a new {@code LocalFinalVariableNameCheck} instance. */ public LocalFinalVariableNameCheck() { super("^[a-z][a-zA-Z0-9]*$"); @@ -68,19 +68,22 @@ return new int[] { TokenTypes.VARIABLE_DEF, TokenTypes.PARAMETER_DEF, + TokenTypes.RESOURCE, }; } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override protected final boolean mustCheckName(DetailAST ast) { final DetailAST modifiersAST = ast.findFirstToken(TokenTypes.MODIFIERS); - final boolean isFinal = modifiersAST.branchContains(TokenTypes.FINAL); + final boolean isFinal = ast.getType() == TokenTypes.RESOURCE + || modifiersAST.findFirstToken(TokenTypes.FINAL) != null; return isFinal && ScopeUtils.isLocalVariableDef(ast); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/LocalVariableNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/LocalVariableNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/LocalVariableNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/LocalVariableNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -58,7 +58,7 @@ *
    *

    * An example of how to configure the check to allow one char variable name in - * + * * initialization expressions in FOR loop: *

    *
    @@ -72,6 +72,7 @@
      */
     public class LocalVariableNameCheck
         extends AbstractNameCheck {
    +
         /** Regexp for one-char loop variables. */
         private static final Pattern SINGLE_CHAR = Pattern.compile("^[a-z]$");
     
    @@ -96,32 +97,34 @@
     
         @Override
         public int[] getDefaultTokens() {
    -        return getAcceptableTokens();
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getAcceptableTokens() {
    -        return new int[] {
    -            TokenTypes.VARIABLE_DEF,
    -        };
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getRequiredTokens() {
    -        return getAcceptableTokens();
    +        return new int[] {
    +            TokenTypes.VARIABLE_DEF,
    +        };
         }
     
         @Override
         protected final boolean mustCheckName(DetailAST ast) {
    +        final boolean result;
             if (allowOneCharVarInForLoop && isForLoopVariable(ast)) {
    -            final String variableName =
    -                    ast.findFirstToken(TokenTypes.IDENT).getText();
    -            return !SINGLE_CHAR.matcher(variableName).find();
    +            final String variableName = ast.findFirstToken(TokenTypes.IDENT).getText();
    +            result = !SINGLE_CHAR.matcher(variableName).find();
             }
    -        final DetailAST modifiersAST =
    -            ast.findFirstToken(TokenTypes.MODIFIERS);
    -        final boolean isFinal = modifiersAST.branchContains(TokenTypes.FINAL);
    -        return !isFinal && ScopeUtils.isLocalVariableDef(ast);
    +        else {
    +            final DetailAST modifiersAST = ast.findFirstToken(TokenTypes.MODIFIERS);
    +            final boolean isFinal = modifiersAST.findFirstToken(TokenTypes.FINAL) != null;
    +            result = !isFinal && ScopeUtils.isLocalVariableDef(ast);
    +        }
    +        return result;
         }
     
         /**
    @@ -134,4 +137,5 @@
             return parentType == TokenTypes.FOR_INIT
                     || parentType == TokenTypes.FOR_EACH_CLAUSE;
         }
    +
     }
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MemberNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MemberNameCheck.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MemberNameCheck.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MemberNameCheck.java	2018-01-14 13:38:20.000000000 +0000
    @@ -1,6 +1,6 @@
     ////////////////////////////////////////////////////////////////////////////////
     // checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    +// Copyright (C) 2001-2018 the original author or authors.
     //
     // This library is free software; you can redistribute it and/or
     // modify it under the terms of the GNU Lesser General Public
    @@ -51,6 +51,7 @@
      */
     public class MemberNameCheck
         extends AbstractAccessControlNameCheck {
    +
         /** Creates a new {@code MemberNameCheck} instance. */
         public MemberNameCheck() {
             super("^[a-z][a-zA-Z0-9]*$");
    @@ -58,27 +59,28 @@
     
         @Override
         public int[] getDefaultTokens() {
    -        return getAcceptableTokens();
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getAcceptableTokens() {
    -        return new int[] {TokenTypes.VARIABLE_DEF};
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getRequiredTokens() {
    -        return getAcceptableTokens();
    +        return new int[] {TokenTypes.VARIABLE_DEF};
         }
     
         @Override
         protected final boolean mustCheckName(DetailAST ast) {
             final DetailAST modifiersAST =
                 ast.findFirstToken(TokenTypes.MODIFIERS);
    -        final boolean isStatic = modifiersAST.branchContains(TokenTypes.LITERAL_STATIC);
    +        final boolean isStatic = modifiersAST.findFirstToken(TokenTypes.LITERAL_STATIC) != null;
     
             return !isStatic && !ScopeUtils.isInInterfaceOrAnnotationBlock(ast)
                 && !ScopeUtils.isLocalVariableDef(ast)
                     && shouldCheckInScope(modifiersAST);
         }
    +
     }
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MethodNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MethodNameCheck.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MethodNameCheck.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MethodNameCheck.java	2018-01-14 13:38:20.000000000 +0000
    @@ -1,6 +1,6 @@
     ////////////////////////////////////////////////////////////////////////////////
     // checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    +// Copyright (C) 2001-2018 the original author or authors.
     //
     // This library is free software; you can redistribute it and/or
     // modify it under the terms of the GNU Lesser General Public
    @@ -99,17 +99,17 @@
     
         @Override
         public int[] getDefaultTokens() {
    -        return getAcceptableTokens();
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getAcceptableTokens() {
    -        return new int[] {TokenTypes.METHOD_DEF, };
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getRequiredTokens() {
    -        return getAcceptableTokens();
    +        return new int[] {TokenTypes.METHOD_DEF, };
         }
     
         @Override
    @@ -149,4 +149,5 @@
         public void setAllowClassName(boolean allowClassName) {
             this.allowClassName = allowClassName;
         }
    +
     }
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MethodTypeParameterNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MethodTypeParameterNameCheck.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MethodTypeParameterNameCheck.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/MethodTypeParameterNameCheck.java	2018-01-14 13:38:20.000000000 +0000
    @@ -1,6 +1,6 @@
     ////////////////////////////////////////////////////////////////////////////////
     // checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    +// Copyright (C) 2001-2018 the original author or authors.
     //
     // This library is free software; you can redistribute it and/or
     // modify it under the terms of the GNU Lesser General Public
    @@ -49,6 +49,7 @@
      */
     public class MethodTypeParameterNameCheck
         extends AbstractNameCheck {
    +
         /** Creates a new {@code MethodTypeParameterNameCheck} instance. */
         public MethodTypeParameterNameCheck() {
             super("^[A-Z]$");
    @@ -56,19 +57,19 @@
     
         @Override
         public int[] getDefaultTokens() {
    -        return getAcceptableTokens();
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getAcceptableTokens() {
    -        return new int[] {
    -            TokenTypes.TYPE_PARAMETER,
    -        };
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getRequiredTokens() {
    -        return getAcceptableTokens();
    +        return new int[] {
    +            TokenTypes.TYPE_PARAMETER,
    +        };
         }
     
         @Override
    @@ -77,4 +78,5 @@
                 ast.getParent().getParent();
             return location.getType() == TokenTypes.METHOD_DEF;
         }
    +
     }
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/package-info.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/package-info.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/package-info.java	2018-01-14 13:38:20.000000000 +0000
    @@ -1,6 +1,6 @@
     ////////////////////////////////////////////////////////////////////////////////
     // checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    +// Copyright (C) 2001-2018 the original author or authors.
     //
     // This library is free software; you can redistribute it and/or
     // modify it under the terms of the GNU Lesser General Public
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/PackageNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/PackageNameCheck.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/PackageNameCheck.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/PackageNameCheck.java	2018-01-14 13:38:20.000000000 +0000
    @@ -1,6 +1,6 @@
     ////////////////////////////////////////////////////////////////////////////////
     // checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    +// Copyright (C) 2001-2018 the original author or authors.
     //
     // This library is free software; you can redistribute it and/or
     // modify it under the terms of the GNU Lesser General Public
    @@ -21,11 +21,11 @@
     
     import java.util.regex.Pattern;
     
    -import com.puppycrawl.tools.checkstyle.api.Check;
    +import com.puppycrawl.tools.checkstyle.StatelessCheck;
    +import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
     import com.puppycrawl.tools.checkstyle.api.DetailAST;
     import com.puppycrawl.tools.checkstyle.api.FullIdent;
     import com.puppycrawl.tools.checkstyle.api.TokenTypes;
    -import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
     
     /**
      * 

    @@ -38,7 +38,7 @@ *

    * The default format has been chosen to match the requirements in the * + * href="https://docs.oracle.com/javase/specs/jls/se8/html/jls-7.html"> * Java Language specification and the Sun coding conventions. * However both underscores and uppercase letters are rather uncommon, * so most projects should probably use @@ -63,57 +63,56 @@ * * @author Oliver Burn */ +@StatelessCheck public class PackageNameCheck - extends Check { + extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. */ public static final String MSG_KEY = "name.invalidPattern"; - /** The format string of the regexp. */ + /** The regexp to match against. */ // Uppercase letters seem rather uncommon, but they're allowed in - // http://docs.oracle.com/javase/specs/ + // https://docs.oracle.com/javase/specs/ // second_edition/html/packages.doc.html#40169 - private String format = "^[a-z]+(\\.[a-zA-Z_][a-zA-Z0-9_]*)*$"; - /** The regexp to match against. */ - private Pattern regexp = Pattern.compile(format); + private Pattern format = Pattern.compile("^[a-z]+(\\.[a-zA-Z_][a-zA-Z0-9_]*)*$"); /** - * Set the format to the specified regular expression. - * @param format a {@code String} value - * @throws org.apache.commons.beanutils.ConversionException unable to parse format + * Set the format for the specified regular expression. + * @param pattern the new pattern */ - public final void setFormat(String format) { - this.format = format; - regexp = CommonUtils.createPattern(format); + public void setFormat(Pattern pattern) { + format = pattern; } @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.PACKAGE_DEF}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.PACKAGE_DEF}; } @Override public void visitToken(DetailAST ast) { final DetailAST nameAST = ast.getLastChild().getPreviousSibling(); final FullIdent full = FullIdent.createFullIdent(nameAST); - if (!regexp.matcher(full.getText()).find()) { + if (!format.matcher(full.getText()).find()) { log(full.getLineNo(), full.getColumnNo(), MSG_KEY, full.getText(), - format); + format.pattern()); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ParameterNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ParameterNameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ParameterNameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/ParameterNameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,30 +19,34 @@ package com.puppycrawl.tools.checkstyle.checks.naming; -import com.google.common.base.Optional; +import java.util.Arrays; +import java.util.Optional; + import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CheckUtils; +import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; /** -*

    - * Checks that method and catch parameter names conform to a format specified + *

    + * Checks that method and {@code catch} parameter names conform to a format specified * by the format property. The format is a * {@link java.util.regex.Pattern regular expression} * and defaults to * ^[a-z][a-zA-Z0-9]*$. *

    - *

    The check has the following option:

    + *

    The check has the following options:

    *

    ignoreOverridden - allows to skip methods with Override annotation from * validation. Default values is false .

    - *

    - * An example of how to configure the check is: - *

    + *

    accessModifiers - access modifiers of methods which should to be checked. + * Default value is public, protected, package, private .

    + * An example of how to configure the check: *
      * <module name="ParameterName"/>
      * 
    *

    - * An example of how to configure the check for names that begin with - * a lower case letter, followed by letters, digits, and underscores is: + * An example of how to configure the check for names that begin with + * a lower case letter, followed by letters, digits, and underscores: *

    *
      * <module name="ParameterName">
    @@ -62,14 +66,21 @@
      * @author Oliver Burn
      * @author Andrei Selkin
      */
    -public class ParameterNameCheck
    -    extends AbstractNameCheck {
    +public class ParameterNameCheck extends AbstractNameCheck {
     
         /**
          * Allows to skip methods with Override annotation from validation.
          */
         private boolean ignoreOverridden;
     
    +    /** Access modifiers of methods which should be checked. */
    +    private AccessModifier[] accessModifiers = {
    +        AccessModifier.PUBLIC,
    +        AccessModifier.PROTECTED,
    +        AccessModifier.PACKAGE,
    +        AccessModifier.PRIVATE,
    +    };
    +
         /**
          * Creates a new {@code ParameterNameCheck} instance.
          */
    @@ -79,39 +90,85 @@
     
         /**
          * Sets whether to skip methods with Override annotation from validation.
    -     *
          * @param ignoreOverridden Flag for skipping methods with Override annotation.
          */
         public void setIgnoreOverridden(boolean ignoreOverridden) {
             this.ignoreOverridden = ignoreOverridden;
         }
     
    +    /**
    +     * Sets access modifiers of methods which should be checked.
    +     * @param accessModifiers access modifiers of methods which should be checked.
    +     */
    +    public void setAccessModifiers(AccessModifier... accessModifiers) {
    +        this.accessModifiers =
    +            Arrays.copyOf(accessModifiers, accessModifiers.length);
    +    }
    +
         @Override
         public int[] getDefaultTokens() {
    -        return getAcceptableTokens();
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getAcceptableTokens() {
    -        return new int[] {TokenTypes.PARAMETER_DEF};
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getRequiredTokens() {
    -        return getAcceptableTokens();
    +        return new int[] {TokenTypes.PARAMETER_DEF};
         }
     
         @Override
         protected boolean mustCheckName(DetailAST ast) {
             boolean checkName = true;
             if (ignoreOverridden && isOverriddenMethod(ast)
    -                || ast.getParent().getType() == TokenTypes.LITERAL_CATCH) {
    +                || ast.getParent().getType() == TokenTypes.LITERAL_CATCH
    +                || CheckUtils.isReceiverParameter(ast)
    +                || !matchAccessModifiers(getAccessModifier(ast))) {
                 checkName = false;
             }
             return checkName;
         }
     
         /**
    +     * Returns the access modifier of the method/constructor at the specified AST. If
    +     * the method is in an interface or annotation block, the access modifier is assumed
    +     * to be public.
    +     *
    +     * @param ast the token of the method/constructor.
    +     * @return the access modifier of the method/constructor.
    +     */
    +    private static AccessModifier getAccessModifier(final DetailAST ast) {
    +        final DetailAST params = ast.getParent();
    +        final DetailAST meth = params.getParent();
    +        AccessModifier accessModifier = AccessModifier.PRIVATE;
    +
    +        if (meth.getType() == TokenTypes.METHOD_DEF
    +                || meth.getType() == TokenTypes.CTOR_DEF) {
    +            if (ScopeUtils.isInInterfaceOrAnnotationBlock(ast)) {
    +                accessModifier = AccessModifier.PUBLIC;
    +            }
    +            else {
    +                final DetailAST modsToken = meth.findFirstToken(TokenTypes.MODIFIERS);
    +                accessModifier = CheckUtils.getAccessModifierFromModifiersToken(modsToken);
    +            }
    +        }
    +
    +        return accessModifier;
    +    }
    +
    +    /**
    +     * Checks whether a method has the correct access modifier to be checked.
    +     * @param accessModifier the access modifier of the method.
    +     * @return whether the method matches the expected access modifier.
    +     */
    +    private boolean matchAccessModifiers(final AccessModifier accessModifier) {
    +        return Arrays.stream(accessModifiers).anyMatch(el -> el == accessModifier);
    +    }
    +
    +    /**
          * Checks whether a method is annotated with Override annotation.
          * @param ast method parameter definition token.
          * @return true if a method is annotated with Override annotation.
    @@ -121,15 +178,17 @@
     
             final DetailAST parent = ast.getParent().getParent();
             final Optional annotation =
    -            Optional.fromNullable(parent.getFirstChild().getFirstChild());
    +            Optional.ofNullable(parent.getFirstChild().getFirstChild());
     
    -        if (annotation.isPresent() && annotation.get().getType() == TokenTypes.ANNOTATION) {
    +        if (annotation.isPresent()
    +                && annotation.get().getType() == TokenTypes.ANNOTATION) {
                 final Optional overrideToken =
    -                Optional.fromNullable(annotation.get().findFirstToken(TokenTypes.IDENT));
    +                Optional.ofNullable(annotation.get().findFirstToken(TokenTypes.IDENT));
                 if (overrideToken.isPresent() && "Override".equals(overrideToken.get().getText())) {
                     overridden = true;
                 }
             }
             return overridden;
         }
    +
     }
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/StaticVariableNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/StaticVariableNameCheck.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/StaticVariableNameCheck.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/StaticVariableNameCheck.java	2018-01-14 13:38:20.000000000 +0000
    @@ -1,6 +1,6 @@
     ////////////////////////////////////////////////////////////////////////////////
     // checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    +// Copyright (C) 2001-2018 the original author or authors.
     //
     // This library is free software; you can redistribute it and/or
     // modify it under the terms of the GNU Lesser General Public
    @@ -49,6 +49,7 @@
      */
     public class StaticVariableNameCheck
         extends AbstractAccessControlNameCheck {
    +
         /** Creates a new {@code StaticVariableNameCheck} instance. */
         public StaticVariableNameCheck() {
             super("^[a-z][a-zA-Z0-9]*$");
    @@ -56,29 +57,30 @@
     
         @Override
         public int[] getDefaultTokens() {
    -        return getAcceptableTokens();
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getAcceptableTokens() {
    -        return new int[] {TokenTypes.VARIABLE_DEF};
    +        return getRequiredTokens();
         }
     
         @Override
         public int[] getRequiredTokens() {
    -        return getAcceptableTokens();
    +        return new int[] {TokenTypes.VARIABLE_DEF};
         }
     
         @Override
         protected final boolean mustCheckName(DetailAST ast) {
             final DetailAST modifiersAST =
                 ast.findFirstToken(TokenTypes.MODIFIERS);
    -        final boolean isStatic = modifiersAST.branchContains(TokenTypes.LITERAL_STATIC);
    -        final boolean isFinal = modifiersAST.branchContains(TokenTypes.FINAL);
    +        final boolean isStatic = modifiersAST.findFirstToken(TokenTypes.LITERAL_STATIC) != null;
    +        final boolean isFinal = modifiersAST.findFirstToken(TokenTypes.FINAL) != null;
     
             return isStatic
                     && !isFinal
                     && shouldCheckInScope(modifiersAST)
                     && !ScopeUtils.isInInterfaceOrAnnotationBlock(ast);
         }
    +
     }
    diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/TypeNameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/TypeNameCheck.java
    --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/TypeNameCheck.java	2016-01-30 23:19:28.000000000 +0000
    +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/naming/TypeNameCheck.java	2018-01-14 13:38:20.000000000 +0000
    @@ -1,6 +1,6 @@
     ////////////////////////////////////////////////////////////////////////////////
     // checkstyle: Checks Java source code for adherence to a set of rules.
    -// Copyright (C) 2001-2016 the original author or authors.
    +// Copyright (C) 2001-2018 the original author or authors.
     //
     // This library is free software; you can redistribute it and/or
     // modify it under the terms of the GNU Lesser General Public
    @@ -19,9 +19,8 @@
     
     package com.puppycrawl.tools.checkstyle.checks.naming;
     
    -import org.apache.commons.lang3.ArrayUtils;
    -
     import com.puppycrawl.tools.checkstyle.api.TokenTypes;
    +import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
     
     /**
      * 

    @@ -78,6 +77,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/NewlineAtEndOfFileCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/NewlineAtEndOfFileCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/NewlineAtEndOfFileCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/NewlineAtEndOfFileCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,13 +22,12 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; -import java.util.List; import java.util.Locale; -import org.apache.commons.beanutils.ConversionException; - import com.google.common.io.Closeables; +import com.puppycrawl.tools.checkstyle.StatelessCheck; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; +import com.puppycrawl.tools.checkstyle.api.FileText; /** *

    @@ -58,6 +57,7 @@ * @author Christopher Lenz * @author lkuehne */ +@StatelessCheck public class NewlineAtEndOfFileCheck extends AbstractFileSetCheck { @@ -77,20 +77,9 @@ private LineSeparatorOption lineSeparator = LineSeparatorOption.SYSTEM; @Override - protected void processFiltered(File file, List lines) { - // Cannot use lines as the line separators have been removed! + protected void processFiltered(File file, FileText fileText) { try { - final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); - boolean threw = true; - try { - if (!endsWithNewline(randomAccessFile)) { - log(0, MSG_KEY_NO_NEWLINE_EOF, file.getPath()); - } - threw = false; - } - finally { - Closeables.close(randomAccessFile, threw); - } + readAndCheckFile(file); } catch (final IOException ignored) { log(0, MSG_KEY_UNABLE_OPEN, file.getPath()); @@ -111,8 +100,28 @@ .toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + lineSeparatorParam, - iae); + throw new IllegalArgumentException("unable to parse " + lineSeparatorParam, iae); + } + } + + /** + * Reads the file provided and checks line separators. + * @param file the file to be processed + * @throws IOException When an IO error occurred while reading from the + * file provided + */ + private void readAndCheckFile(File file) throws IOException { + // Cannot use lines as the line separators have been removed! + final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r"); + boolean threw = true; + try { + if (!endsWithNewline(randomAccessFile)) { + log(0, MSG_KEY_NO_NEWLINE_EOF, file.getPath()); + } + threw = false; + } + finally { + Closeables.close(randomAccessFile, threw); } } @@ -125,18 +134,23 @@ * provided reader */ private boolean endsWithNewline(RandomAccessFile randomAccessFile) - throws IOException { + throws IOException { + final boolean result; final int len = lineSeparator.length(); if (randomAccessFile.length() < len) { - return false; + result = false; } - randomAccessFile.seek(randomAccessFile.length() - len); - final byte[] lastBytes = new byte[len]; - final int readBytes = randomAccessFile.read(lastBytes); - if (readBytes != len) { - throw new IOException("Unable to read " + len + " bytes, got " - + readBytes); + else { + randomAccessFile.seek(randomAccessFile.length() - len); + final byte[] lastBytes = new byte[len]; + final int readBytes = randomAccessFile.read(lastBytes); + if (readBytes != len) { + throw new IOException("Unable to read " + len + " bytes, got " + + readBytes); + } + result = lineSeparator.matches(lastBytes); } - return lineSeparator.matches(lastBytes); + return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/OuterTypeFilenameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/OuterTypeFilenameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/OuterTypeFilenameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/OuterTypeFilenameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,8 @@ import java.io.File; import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -31,7 +32,9 @@ * @author Oliver Burn * @author maxvetrenko */ -public class OuterTypeFilenameCheck extends Check { +@FileStatefulCheck +public class OuterTypeFilenameCheck extends AbstractCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -39,7 +42,7 @@ public static final String MSG_KEY = "type.file.mismatch"; /** Pattern matching any file extension with dot included. */ - private static final Pattern FILE_EXTENSION_PATTERN = Pattern.compile("\\.[^\\.]*$"); + private static final Pattern FILE_EXTENSION_PATTERN = Pattern.compile("\\.[^.]*$"); /** Indicates whether the first token has been seen in the file. */ private boolean seenFirstToken; @@ -58,20 +61,22 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, - TokenTypes.ENUM_DEF, TokenTypes.ANNOTATION_DEF, - }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] { + TokenTypes.CLASS_DEF, + TokenTypes.INTERFACE_DEF, + TokenTypes.ENUM_DEF, + TokenTypes.ANNOTATION_DEF, + }; } @Override @@ -85,7 +90,6 @@ @Override public void visitToken(DetailAST ast) { - final String outerTypeName = ast.findFirstToken(TokenTypes.IDENT).getText(); if (seenFirstToken) { final DetailAST modifiers = ast.findFirstToken(TokenTypes.MODIFIERS); if (modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null @@ -94,6 +98,7 @@ } } else { + final String outerTypeName = ast.findFirstToken(TokenTypes.IDENT).getText(); if (fileName.equals(outerTypeName)) { validFirst = true; @@ -122,4 +127,5 @@ name = FILE_EXTENSION_PATTERN.matcher(name).replaceAll(""); return name; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/CommentSuppressor.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/CommentSuppressor.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/CommentSuppressor.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/CommentSuppressor.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -27,6 +27,7 @@ * @author Oliver Burn */ class CommentSuppressor implements MatchSuppressor { + /** File contents to check for comments. */ private final FileContents currentContents; diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/DetectorOptions.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/DetectorOptions.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/DetectorOptions.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/DetectorOptions.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,17 +19,17 @@ package com.puppycrawl.tools.checkstyle.checks.regexp; +import java.util.Optional; import java.util.regex.Pattern; -import org.apache.commons.lang3.ObjectUtils; - import com.puppycrawl.tools.checkstyle.api.AbstractViolationReporter; /** * Options for a detector. * @author Oliver Burn */ -final class DetectorOptions { +public final class DetectorOptions { + /** * Flags to compile a regular expression with. * See {@link Pattern#flags()}. @@ -58,6 +58,14 @@ private DetectorOptions() { } /** + * Returns new Builder object. + * @return Builder object. + */ + public static Builder newBuilder() { + return new DetectorOptions().new Builder(); + } + + /** * Format of the regular expression. * @return format of the regular expression. */ @@ -110,26 +118,17 @@ * @return the pattern to use when matching. */ public Pattern getPattern() { - if (pattern != null) { - return pattern; - } - int options = compileFlags; + if (pattern == null) { + int options = compileFlags; - if (ignoreCase) { - options |= Pattern.CASE_INSENSITIVE; + if (ignoreCase) { + options |= Pattern.CASE_INSENSITIVE; + } + pattern = Pattern.compile(format, options); } - pattern = Pattern.compile(format, options); return pattern; } - /** - * Returns new Builder object. - * @return Builder object. - */ - static Builder newBuilder() { - return new DetectorOptions().new Builder(); - } - /** Class which implements Builder pattern to build DetectorOptions instance. */ public final class Builder { @@ -137,8 +136,9 @@ * Specifies the violation reporter and returns Builder object. * @param val for reporting violations. * @return Builder object. + * @noinspection ReturnOfInnerClass */ - Builder reporter(AbstractViolationReporter val) { + public Builder reporter(AbstractViolationReporter val) { reporter = val; return this; } @@ -148,8 +148,9 @@ * and returns Builder object. * @param val the format to use when matching lines. * @return Builder object. + * @noinspection ReturnOfInnerClass */ - Builder compileFlags(int val) { + public Builder compileFlags(int val) { compileFlags = val; return this; } @@ -158,8 +159,9 @@ * Specifies the format to use when matching lines and returns Builder object. * @param val the format to use when matching lines. * @return Builder object. + * @noinspection ReturnOfInnerClass */ - Builder format(String val) { + public Builder format(String val) { format = val; return this; } @@ -168,8 +170,9 @@ * Specifies message to use when reporting a match and returns Builder object. * @param val message to use when reporting a match. * @return Builder object. + * @noinspection ReturnOfInnerClass */ - Builder message(String val) { + public Builder message(String val) { message = val; return this; } @@ -178,8 +181,9 @@ * Specifies the minimum allowed number of detections and returns Builder object. * @param val the minimum allowed number of detections. * @return Builder object. + * @noinspection ReturnOfInnerClass */ - Builder minimum(int val) { + public Builder minimum(int val) { minimum = val; return this; } @@ -188,8 +192,9 @@ * Specifies the maximum allowed number of detections and returns Builder object. * @param val the maximum allowed number of detections. * @return Builder object. + * @noinspection ReturnOfInnerClass */ - Builder maximum(int val) { + public Builder maximum(int val) { maximum = val; return this; } @@ -198,8 +203,9 @@ * Specifies whether to ignore case when matching and returns Builder object. * @param val whether to ignore case when matching. * @return Builder object. + * @noinspection ReturnOfInnerClass, BooleanParameter */ - Builder ignoreCase(boolean val) { + public Builder ignoreCase(boolean val) { ignoreCase = val; return this; } @@ -208,8 +214,9 @@ * Specifies the suppressor to use and returns Builder object. * @param val the suppressor to use. * @return current instance + * @noinspection ReturnOfInnerClass */ - Builder suppressor(MatchSuppressor val) { + public Builder suppressor(MatchSuppressor val) { suppressor = val; return this; } @@ -218,10 +225,12 @@ * Returns new DetectorOptions instance. * @return DetectorOptions instance. */ - DetectorOptions build() { - message = ObjectUtils.defaultIfNull(message, ""); - suppressor = ObjectUtils.defaultIfNull(suppressor, NeverSuppress.INSTANCE); + public DetectorOptions build() { + message = Optional.ofNullable(message).orElse(""); + suppressor = Optional.ofNullable(suppressor).orElse(NeverSuppress.INSTANCE); return DetectorOptions.this; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/MatchSuppressor.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/MatchSuppressor.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/MatchSuppressor.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/MatchSuppressor.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,7 +23,9 @@ * Represents a suppressor for matches. * @author oliver */ -interface MatchSuppressor { +@FunctionalInterface +public interface MatchSuppressor { + /** * Checks if the specified selection should be suppressed. * @param startLineNo the starting line number @@ -34,4 +36,5 @@ **/ boolean shouldSuppress(int startLineNo, int startColNo, int endLineNo, int endColNo); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/MultilineDetector.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/MultilineDetector.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/MultilineDetector.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/MultilineDetector.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,7 +21,6 @@ import java.util.regex.Matcher; -import com.google.common.base.Strings; import com.puppycrawl.tools.checkstyle.api.FileText; import com.puppycrawl.tools.checkstyle.api.LineColumn; @@ -79,7 +78,8 @@ text = new FileText(fileText); resetState(); - if (Strings.isNullOrEmpty(options.getFormat())) { + final String format = options.getFormat(); + if (format == null || format.isEmpty()) { options.getReporter().log(0, MSG_EMPTY); } else { @@ -95,9 +95,9 @@ boolean foundMatch = matcher.find(); while (foundMatch) { - final LineColumn start = text.lineColumn(matcher.start()); currentMatches++; if (currentMatches > options.getMaximum()) { + final LineColumn start = text.lineColumn(matcher.start()); if (options.getMessage().isEmpty()) { options.getReporter().log(start.getLine(), MSG_REGEXP_EXCEEDED, matcher.pattern().toString()); @@ -117,7 +117,6 @@ // 209099/is-it-ever-okay-to-catch-stackoverflowerror-in-java options.getReporter().log(0, MSG_STACKOVERFLOW, matcher.pattern().toString()); } - } /** Perform processing at the end of a set of lines. */ @@ -139,4 +138,5 @@ private void resetState() { currentMatches = 0; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/NeverSuppress.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/NeverSuppress.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/NeverSuppress.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/NeverSuppress.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,8 +25,9 @@ * @author oliver */ public final class NeverSuppress implements MatchSuppressor { + /** The shared instance. */ - static final MatchSuppressor INSTANCE = new NeverSuppress(); + public static final MatchSuppressor INSTANCE = new NeverSuppress(); /** Stop creation of instances. */ private NeverSuppress() { @@ -37,4 +38,5 @@ int endLineNo, int endColNo) { return false; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,9 +22,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.FileText; @@ -55,7 +54,8 @@ *

    * @author Stan Quinn */ -public class RegexpCheck extends Check { +@FileStatefulCheck +public class RegexpCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -87,7 +87,7 @@ + "the check is aborting, there may be more unreported errors."; /** Custom message for report. */ - private String message = ""; + private String message; /** Ignore matches within comments?. **/ private boolean ignoreComments; @@ -110,11 +110,8 @@ /** Tracks number of errors. */ private int errorCount; - /** The format string of the regexp. */ - private String format = "$^"; - /** The regexp to match against. */ - private Pattern regexp = Pattern.compile(format, Pattern.MULTILINE); + private Pattern format = Pattern.compile("$^", Pattern.MULTILINE); /** The matcher. */ private Matcher matcher; @@ -168,32 +165,31 @@ /** * Set the format to the specified regular expression. - * @param format a {@code String} value + * @param pattern the new pattern * @throws org.apache.commons.beanutils.ConversionException unable to parse format */ - public final void setFormat(String format) { - this.format = format; - regexp = CommonUtils.createPattern(format, Pattern.MULTILINE); + public final void setFormat(Pattern pattern) { + format = CommonUtils.createPattern(pattern.pattern(), Pattern.MULTILINE); } @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return CommonUtils.EMPTY_INT_ARRAY; } @Override public void beginTree(DetailAST rootAST) { - matcher = regexp.matcher(getFileContents().getText().getFullText()); + matcher = format.matcher(getFileContents().getText().getFullText()); matchCount = 0; errorCount = 0; findMatch(); @@ -201,7 +197,6 @@ /** Recursive method that finds the matches. */ private void findMatch() { - final boolean foundMatch = matcher.find(); if (foundMatch) { final FileText text = getFileContents().getText(); @@ -225,7 +220,6 @@ else if (!illegalPattern && matchCount == 0) { logMessage(0); } - } /** @@ -234,7 +228,7 @@ * @return true is we can continue */ private boolean canContinueValidation(boolean ignore) { - return errorCount < errorLimit + return errorCount <= errorLimit - 1 && (ignore || illegalPattern || checkForDuplicates); } @@ -253,12 +247,12 @@ else { end = text.lineColumn(matcher.end() - 1); } - final int startColumn = start.getColumn(); - final int endLine = end.getLine(); - final int endColumn = end.getColumn(); boolean ignore = false; if (ignoreComments) { final FileContents theFileContents = getFileContents(); + final int startColumn = start.getColumn(); + final int endLine = end.getLine(); + final int endColumn = end.getColumn(); ignore = theFileContents.hasIntersectionWithComment(startLine, startColumn, endLine, endColumn); } @@ -272,8 +266,8 @@ private void logMessage(int lineNumber) { String msg; - if (message.isEmpty()) { - msg = format; + if (message == null || message.isEmpty()) { + msg = format.pattern(); } else { msg = message; @@ -295,4 +289,5 @@ } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpMultilineCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpMultilineCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpMultilineCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpMultilineCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,7 +20,6 @@ package com.puppycrawl.tools.checkstyle.checks.regexp; import java.io.File; -import java.util.List; import java.util.regex.Pattern; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; @@ -49,7 +48,6 @@ @Override public void beginProcessing(String charset) { - super.beginProcessing(charset); final DetectorOptions options = DetectorOptions.newBuilder() .reporter(this) .compileFlags(Pattern.MULTILINE) @@ -63,8 +61,8 @@ } @Override - protected void processFiltered(File file, List lines) { - detector.processLines(FileText.fromLines(file, lines)); + protected void processFiltered(File file, FileText fileText) { + detector.processLines(fileText); } /** @@ -106,4 +104,5 @@ public void setIgnoreCase(boolean ignoreCase) { this.ignoreCase = ignoreCase; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpOnFilenameCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpOnFilenameCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpOnFilenameCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpOnFilenameCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,12 +21,12 @@ import java.io.File; import java.io.IOException; -import java.util.List; import java.util.regex.Pattern; -import com.google.common.io.Files; +import com.puppycrawl.tools.checkstyle.StatelessCheck; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.FileText; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** @@ -41,7 +41,7 @@ * When customizing the check, the properties are applied in a specific order. * The fileExtensions property first picks only files that match any of the * specific extensions supplied. Once files are matched against the - * fileExtensions, the match property is then used in conjuction with the + * fileExtensions, the match property is then used in conjunction with the * patterns to determine if the check is looking for a match or mis-match on * those files. If the fileNamePattern is supplied, the matching is only applied * to the fileNamePattern and not the folderPattern. If no fileNamePattern is @@ -184,7 +184,9 @@ * * @author Richard Veach */ +@StatelessCheck public class RegexpOnFilenameCheck extends AbstractFileSetCheck { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -209,22 +211,18 @@ * Setter for folder format. * * @param folderPattern format of folder. - * @throws org.apache.commons.beanutils.ConversionException if unable to - * create Pattern object. */ - public void setFolderPattern(String folderPattern) { - this.folderPattern = CommonUtils.createPattern(folderPattern); + public void setFolderPattern(Pattern folderPattern) { + this.folderPattern = folderPattern; } /** * Setter for file name format. * * @param fileNamePattern format of file. - * @throws org.apache.commons.beanutils.ConversionException if unable to - * create Pattern object. */ - public void setFileNamePattern(String fileNamePattern) { - this.fileNamePattern = CommonUtils.createPattern(fileNamePattern); + public void setFileNamePattern(Pattern fileNamePattern) { + this.fileNamePattern = fileNamePattern; } /** @@ -253,7 +251,7 @@ } @Override - protected void processFiltered(File file, List lines) throws CheckstyleException { + protected void processFiltered(File file, FileText fileText) throws CheckstyleException { final String fileName = getFileName(file); final String folderPath = getFolderPath(file); @@ -272,7 +270,7 @@ String fileName = file.getName(); if (ignoreFileNameExtensions) { - fileName = Files.getNameWithoutExtension(fileName); + fileName = CommonUtils.getFileNameWithoutExtension(fileName); } return fileName; @@ -288,7 +286,7 @@ */ private static String getFolderPath(File file) throws CheckstyleException { try { - return file.getParentFile().getCanonicalPath(); + return file.getCanonicalFile().getParent(); } catch (IOException ex) { throw new CheckstyleException("unable to create canonical path names for " @@ -311,16 +309,8 @@ result = true; } else { - final boolean useMatch; - // null pattern means 'match' applies to the folderPattern matching - if (fileNamePattern == null) { - useMatch = match; - } - else { - useMatch = true; - } - + final boolean useMatch = fileNamePattern != null || match; result = folderPattern.matcher(folderPath).find() == useMatch; } @@ -335,17 +325,8 @@ * @return true if they do match. */ private boolean isMatchFile(String fileName) { - final boolean result; - // null pattern always matches, regardless of value of 'match' - if (fileNamePattern == null) { - result = true; - } - else { - result = fileNamePattern.matcher(fileName).find() == match; - } - - return result; + return fileNamePattern == null || fileNamePattern.matcher(fileName).find() == match; } /** Logs the errors for the check. */ @@ -381,4 +362,5 @@ return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpSinglelineCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpSinglelineCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpSinglelineCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpSinglelineCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,9 @@ package com.puppycrawl.tools.checkstyle.checks.regexp; import java.io.File; -import java.util.List; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; +import com.puppycrawl.tools.checkstyle.api.FileText; /** * Implementation of a check that looks for a single line in any file type. @@ -46,7 +46,6 @@ @Override public void beginProcessing(String charset) { - super.beginProcessing(charset); final DetectorOptions options = DetectorOptions.newBuilder() .reporter(this) .compileFlags(0) @@ -60,8 +59,8 @@ } @Override - protected void processFiltered(File file, List lines) { - detector.processLines(lines); + protected void processFiltered(File file, FileText fileText) { + detector.processLines(fileText); } /** @@ -103,4 +102,5 @@ public void setIgnoreCase(boolean ignoreCase) { this.ignoreCase = ignoreCase; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpSinglelineJavaCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpSinglelineJavaCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpSinglelineJavaCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/RegexpSinglelineJavaCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,19 +19,18 @@ package com.puppycrawl.tools.checkstyle.checks.regexp; -import java.util.Arrays; - -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * Implementation of a check that looks for a single line in Java files. * Supports ignoring comments for matches. * @author Oliver Burn */ -public class RegexpSinglelineJavaCheck extends Check { +@StatelessCheck +public class RegexpSinglelineJavaCheck extends AbstractCheck { /** The format of the regular expression to match. */ private String format = "$."; @@ -48,30 +47,30 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return CommonUtils.EMPTY_INT_ARRAY; } @Override public void beginTree(DetailAST rootAST) { - MatchSuppressor supressor = null; + MatchSuppressor suppressor = null; if (ignoreComments) { - supressor = new CommentSuppressor(getFileContents()); + suppressor = new CommentSuppressor(getFileContents()); } final DetectorOptions options = DetectorOptions.newBuilder() .reporter(this) .compileFlags(0) - .suppressor(supressor) + .suppressor(suppressor) .format(format) .message(message) .minimum(minimum) @@ -79,7 +78,7 @@ .ignoreCase(ignoreCase) .build(); final SinglelineDetector detector = new SinglelineDetector(options); - detector.processLines(Arrays.asList(getLines())); + detector.processLines(getFileContents().getText()); } /** @@ -129,4 +128,5 @@ public void setIgnoreComments(boolean ignore) { ignoreComments = ignore; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/SinglelineDetector.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/SinglelineDetector.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/SinglelineDetector.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/regexp/SinglelineDetector.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,14 +19,16 @@ package com.puppycrawl.tools.checkstyle.checks.regexp; -import java.util.List; import java.util.regex.Matcher; +import com.puppycrawl.tools.checkstyle.api.FileText; + /** * A detector that matches individual lines. * @author oliver */ class SinglelineDetector { + /** * A key is pointing to the warning message text in "messages.properties" * file. @@ -54,12 +56,13 @@ /** * Processes a set of lines looking for matches. - * @param lines the lines to process. + * @param fileText {@link FileText} object contains the lines to process. */ - public void processLines(List lines) { + public void processLines(FileText fileText) { resetState(); int lineNo = 0; - for (String line : lines) { + for (int index = 0; index < fileText.size(); index++) { + final String line = fileText.get(index); lineNo++; checkLine(lineNo, line, options.getPattern().matcher(line), 0); } @@ -96,35 +99,31 @@ private void checkLine(int lineNo, String line, Matcher matcher, int startPosition) { final boolean foundMatch = matcher.find(startPosition); - if (!foundMatch) { - return; - } - - // match is found, check for intersection with comment - final int startCol = matcher.start(0); - final int endCol = matcher.end(0); - // Note that Matcher.end(int) returns the offset AFTER the - // last matched character, but shouldSuppress() - // needs column number of the last character. - // So we need to use (endCol - 1) here. - if (options.getSuppressor() - .shouldSuppress(lineNo, startCol, lineNo, endCol - 1)) { - if (endCol < line.length()) { - // check if the expression is on the rest of the line + if (foundMatch) { + // match is found, check for intersection with comment + final int startCol = matcher.start(0); + final int endCol = matcher.end(0); + // Note that Matcher.end(int) returns the offset AFTER the + // last matched character, but shouldSuppress() + // needs column number of the last character. + // So we need to use (endCol - 1) here. + if (options.getSuppressor() + .shouldSuppress(lineNo, startCol, lineNo, endCol - 1)) { checkLine(lineNo, line, matcher, endCol); } - return; - } - - currentMatches++; - if (currentMatches > options.getMaximum()) { - if (options.getMessage().isEmpty()) { - options.getReporter().log(lineNo, MSG_REGEXP_EXCEEDED, - matcher.pattern().toString()); - } else { - options.getReporter().log(lineNo, options.getMessage()); + currentMatches++; + if (currentMatches > options.getMaximum()) { + if (options.getMessage().isEmpty()) { + options.getReporter().log(lineNo, MSG_REGEXP_EXCEEDED, + matcher.pattern().toString()); + } + else { + options.getReporter().log(lineNo, options.getMessage()); + } + } } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/AnonInnerLengthCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/AnonInnerLengthCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/AnonInnerLengthCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/AnonInnerLengthCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.sizes; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -56,7 +57,8 @@ * * @author Rob Worth */ -public class AnonInnerLengthCheck extends Check { +@StatelessCheck +public class AnonInnerLengthCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -72,17 +74,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.LITERAL_NEW}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.LITERAL_NEW}; } @Override @@ -101,9 +103,11 @@ } /** + * Sets maximum length of an anonymous inner class. * @param length the maximum length of an anonymous inner class. */ public void setMax(int length) { max = length; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/ExecutableStatementCountCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,8 @@ import java.util.ArrayDeque; import java.util.Deque; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -31,8 +32,9 @@ * (default = 30). * @author Simon Harris */ +@FileStatefulCheck public final class ExecutableStatementCountCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -170,7 +172,6 @@ && type != TokenTypes.METHOD_DEF && type != TokenTypes.INSTANCE_INIT && type != TokenTypes.STATIC_INIT) { - parent = parent.getParent(); type = parent.getType(); } @@ -185,6 +186,7 @@ * @author Simon Harris */ private static class Context { + /** Member AST node. */ private final DetailAST ast; @@ -223,5 +225,7 @@ public int getCount() { return count; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/FileLengthCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/FileLengthCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/FileLengthCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/FileLengthCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,9 +20,10 @@ package com.puppycrawl.tools.checkstyle.checks.sizes; import java.io.File; -import java.util.List; +import com.puppycrawl.tools.checkstyle.StatelessCheck; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; +import com.puppycrawl.tools.checkstyle.api.FileText; /** *

    @@ -54,6 +55,7 @@ *

    * @author Lars Kühne */ +@StatelessCheck public class FileLengthCheck extends AbstractFileSetCheck { /** @@ -69,9 +71,9 @@ private int max = DEFAULT_MAX_LINES; @Override - protected void processFiltered(File file, List lines) { - if (lines.size() > max) { - log(1, MSG_KEY, lines.size(), max); + protected void processFiltered(File file, FileText fileText) { + if (fileText.size() > max) { + log(1, MSG_KEY, fileText.size(), max); } } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/LineLengthCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/LineLengthCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/LineLengthCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/LineLengthCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,9 +21,8 @@ import java.util.regex.Pattern; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -74,7 +73,8 @@ * * @author Lars Kühne */ -public class LineLengthCheck extends Check { +@StatelessCheck +public class LineLengthCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -92,35 +92,27 @@ private int max = DEFAULT_MAX_COLUMNS; /** The regexp when long lines are ignored. */ - private Pattern ignorePattern; - - /** - * Creates a new {@code LineLengthCheck} instance. - */ - public LineLengthCheck() { - setIgnorePattern("^$"); - } + private Pattern ignorePattern = Pattern.compile("^$"); @Override public int[] getDefaultTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override public void beginTree(DetailAST rootAST) { final String[] lines = getLines(); for (int i = 0; i < lines.length; i++) { - final String line = lines[i]; final int realLength = CommonUtils.lengthExpandedTabs( line, line.length(), getTabWidth()); @@ -142,9 +134,10 @@ /** * Set the ignore pattern. - * @param format a {@code String} value + * @param pattern a pattern. */ - public final void setIgnorePattern(String format) { - ignorePattern = CommonUtils.createPattern(format); + public final void setIgnorePattern(Pattern pattern) { + ignorePattern = pattern; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/MethodCountCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/MethodCountCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/MethodCountCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/MethodCountCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,19 +24,21 @@ import java.util.EnumMap; import java.util.Map; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.Scope; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.ScopeUtils; /** - * Counts the methods of the type-definition and checks whether this - * count is higher than the configured limit. + * Checks the number of methods declared in each type declaration by access + * modifier or total count. * @author Alexander Jesse * @author Oliver Burn */ -public final class MethodCountCheck extends Check { +@FileStatefulCheck +public final class MethodCountCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -97,6 +99,7 @@ TokenTypes.ENUM_CONSTANT_DEF, TokenTypes.ENUM_DEF, TokenTypes.INTERFACE_DEF, + TokenTypes.ANNOTATION_DEF, TokenTypes.METHOD_DEF, }; } @@ -109,26 +112,45 @@ @Override public void visitToken(DetailAST ast) { if (ast.getType() == TokenTypes.METHOD_DEF) { - raiseCounter(ast); + if (isInLatestScopeDefinition(ast)) { + raiseCounter(ast); + } } else { - final boolean inInterface = ast.getType() == TokenTypes.INTERFACE_DEF; - counters.push(new MethodCounter(inInterface)); + counters.push(new MethodCounter(ast)); } } @Override public void leaveToken(DetailAST ast) { - if (ast.getType() == TokenTypes.CLASS_DEF - || ast.getType() == TokenTypes.INTERFACE_DEF - || ast.getType() == TokenTypes.ENUM_CONSTANT_DEF - || ast.getType() == TokenTypes.ENUM_DEF) { + if (ast.getType() != TokenTypes.METHOD_DEF) { final MethodCounter counter = counters.pop(); + checkCounters(counter, ast); } } /** + * Checks if there is a scope definition to check and that the method is found inside that scope + * (class, enum, etc.). + * @param methodDef + * The method to analyze. + * @return {@code true} if the method is part of the latest scope definition and should be + * counted. + */ + private boolean isInLatestScopeDefinition(DetailAST methodDef) { + boolean result = false; + + if (!counters.isEmpty()) { + final DetailAST latestDefinition = counters.peek().getScopeDefinition(); + + result = latestDefinition == methodDef.getParent().getParent(); + } + + return result; + } + + /** * Determine the visibility modifier and raise the corresponding counter. * @param method * The method-subtree from the AbstractSyntaxTree. @@ -216,20 +238,28 @@ * methods for each class and layer. */ private static class MethodCounter { + /** Maintains the counts. */ private final Map counts = new EnumMap<>(Scope.class); /** Indicated is an interface, in which case all methods are public. */ private final boolean inInterface; + /** + * The surrounding scope definition (class, enum, etc.) which the method counts are connect + * to. + */ + private final DetailAST scopeDefinition; /** Tracks the total. */ private int total; /** * Creates an interface. - * @param inInterface indicated if counter for an interface. In which - * case, add all counts as public methods. + * @param scopeDefinition + * The surrounding scope definition (class, enum, etc.) which to count all methods + * for. */ - MethodCounter(boolean inInterface) { - this.inInterface = inInterface; + MethodCounter(DetailAST scopeDefinition) { + this.scopeDefinition = scopeDefinition; + inInterface = scopeDefinition.getType() == TokenTypes.INTERFACE_DEF; } /** @@ -252,21 +282,25 @@ * @return the value of a scope counter */ private int value(Scope scope) { - final Integer value = counts.get(scope); - + Integer value = counts.get(scope); if (value == null) { - return 0; - } - else { - return value; + value = 0; } + return value; + } + + private DetailAST getScopeDefinition() { + return scopeDefinition; } /** + * Fetches total number of methods. * @return the total number of methods. */ private int getTotal() { return total; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/MethodLengthCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/MethodLengthCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/MethodLengthCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/MethodLengthCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,12 +19,12 @@ package com.puppycrawl.tools.checkstyle.checks.sizes; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    @@ -56,7 +56,8 @@ * * @author Lars Kühne */ -public class MethodLengthCheck extends Check { +@StatelessCheck +public class MethodLengthCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -85,7 +86,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -114,7 +115,10 @@ if (!countEmpty) { final FileContents contents = getFileContents(); final int lastLine = closingBrace.getLineNo(); - for (int i = openingBrace.getLineNo() - 1; i < lastLine; i++) { + // lastLine - 1 is actual last line index. Last line is line with curly brace, + // which is always not empty. So, we make it lastLine - 2 to cover last line that + // actually may be empty. + for (int i = openingBrace.getLineNo() - 1; i <= lastLine - 2; i++) { if (contents.lineIsBlank(i) || contents.lineIsComment(i)) { length--; } @@ -124,6 +128,7 @@ } /** + * Sets maximum length of a method. * @param length the maximum length of a method. */ public void setMax(int length) { @@ -131,10 +136,12 @@ } /** + * Sets countEmpty. * @param countEmpty whether to count empty and single line comments * of the form //. */ public void setCountEmpty(boolean countEmpty) { this.countEmpty = countEmpty; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/OuterTypeNumberCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/OuterTypeNumberCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/OuterTypeNumberCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/OuterTypeNumberCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.sizes; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -27,7 +28,8 @@ * Checks for the number of defined types at the "outer" level. * @author oliverb */ -public class OuterTypeNumberCheck extends Check { +@FileStatefulCheck +public class OuterTypeNumberCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -44,18 +46,18 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, - TokenTypes.ENUM_DEF, TokenTypes.ANNOTATION_DEF, }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.CLASS_DEF, TokenTypes.INTERFACE_DEF, + TokenTypes.ENUM_DEF, TokenTypes.ANNOTATION_DEF, }; } @Override @@ -91,4 +93,5 @@ public void setMax(int max) { this.max = max; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/ParameterNumberCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/ParameterNumberCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/ParameterNumberCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/sizes/ParameterNumberCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,12 +19,12 @@ package com.puppycrawl.tools.checkstyle.checks.sizes; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.AnnotationUtility; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    @@ -64,8 +64,9 @@ * * @author Oliver Burn */ +@StatelessCheck public class ParameterNumberCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -117,7 +118,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -142,4 +143,5 @@ && (AnnotationUtility.containsAnnotation(ast, OVERRIDE) || AnnotationUtility.containsAnnotation(ast, CANONICAL_OVERRIDE)); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/SuppressWarningsHolder.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,18 +19,16 @@ package com.puppycrawl.tools.checkstyle.checks; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; -import org.apache.commons.beanutils.ConversionException; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.AuditEvent; -import com.puppycrawl.tools.checkstyle.api.Check; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -40,8 +38,9 @@ * @author Trevor Robinson * @author Stéphane Galland */ +@StatelessCheck public class SuppressWarningsHolder - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -56,7 +55,7 @@ * suppression {@code "checkstyle:fallthrough"} or {@code "checkstyle:FallThrough"}. * To suppress the warning in both tools, just use {@code "fallthrough"}. */ - public static final String CHECKSTYLE_PREFIX = "checkstyle:"; + private static final String CHECKSTYLE_PREFIX = "checkstyle:"; /** Java.lang namespace prefix, which is stripped from SuppressWarnings */ private static final String JAVA_LANG_PREFIX = "java.lang."; @@ -74,7 +73,8 @@ * A thread-local holder for the list of suppression entries for the last * file parsed. */ - private static final ThreadLocal> ENTRIES = new ThreadLocal<>(); + private static final ThreadLocal> ENTRIES = + ThreadLocal.withInitial(LinkedList::new); /** * Returns the default alias for the source name of a check, which is the @@ -85,11 +85,11 @@ * @return the default alias for the given check */ public static String getDefaultAlias(String sourceName) { - final int startIndex = sourceName.lastIndexOf('.') + 1; int endIndex = sourceName.length(); if (sourceName.endsWith(CHECK_SUFFIX)) { endIndex -= CHECK_SUFFIX.length(); } + final int startIndex = sourceName.lastIndexOf('.') + 1; return sourceName.substring(startIndex, endIndex).toLowerCase(Locale.ENGLISH); } @@ -115,7 +115,7 @@ * name) * @param checkAlias the alias used in {@link SuppressWarnings} annotations */ - public static void registerAlias(String sourceName, String checkAlias) { + private static void registerAlias(String sourceName, String checkAlias) { CHECK_ALIAS_MAP.put(sourceName, checkAlias); } @@ -126,15 +126,15 @@ * paramnum}. * @param aliasList the list of comma-separated alias assignments */ - public void setAliasList(String aliasList) { - for (String sourceAlias : aliasList.split(",")) { + public void setAliasList(String... aliasList) { + for (String sourceAlias : aliasList) { final int index = sourceAlias.indexOf('='); if (index > 0) { registerAlias(sourceAlias.substring(0, index), sourceAlias .substring(index + 1)); } else if (!sourceAlias.isEmpty()) { - throw new ConversionException( + throw new IllegalArgumentException( "'=' expected in alias list item: " + sourceAlias); } } @@ -155,14 +155,8 @@ final int column = event.getColumn(); boolean suppressed = false; for (Entry entry : entries) { - final boolean afterStart = - entry.getFirstLine() < line - || entry.getFirstLine() == line - && (column == 0 || entry.getFirstColumn() <= column); - final boolean beforeEnd = - entry.getLastLine() > line - || entry.getLastLine() == line && entry - .getLastColumn() >= column; + final boolean afterStart = isSuppressedAfterEventStart(line, column, entry); + final boolean beforeEnd = isSuppressedBeforeEventEnd(line, column, entry); final boolean nameMatches = ALL_WARNING_MATCHING_ID.equals(entry.getCheckName()) || entry.getCheckName().equalsIgnoreCase(checkAlias); @@ -170,29 +164,60 @@ && event.getModuleId().equals(entry.getCheckName()); if (afterStart && beforeEnd && (nameMatches || idMatches)) { suppressed = true; + break; } } return suppressed; } + /** + * Checks whether suppression entry position is after the audit event occurrence position + * in the source file. + * @param line the line number in the source file where the event occurred. + * @param column the column number in the source file where the event occurred. + * @param entry suppression entry. + * @return true if suppression entry position is after the audit event occurrence position + * in the source file. + */ + private static boolean isSuppressedAfterEventStart(int line, int column, Entry entry) { + return entry.getFirstLine() < line + || entry.getFirstLine() == line + && (column == 0 || entry.getFirstColumn() <= column); + } + + /** + * Checks whether suppression entry position is before the audit event occurrence position + * in the source file. + * @param line the line number in the source file where the event occurred. + * @param column the column number in the source file where the event occurred. + * @param entry suppression entry. + * @return true if suppression entry position is before the audit event occurrence position + * in the source file. + */ + private static boolean isSuppressedBeforeEventEnd(int line, int column, Entry entry) { + return entry.getLastLine() > line + || entry.getLastLine() == line && entry + .getLastColumn() >= column; + } + @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.ANNOTATION}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.ANNOTATION}; } @Override public void beginTree(DetailAST rootAST) { - ENTRIES.set(new LinkedList()); + ENTRIES.get().clear(); } @Override @@ -204,42 +229,39 @@ identifier = identifier.substring(JAVA_LANG_PREFIX.length()); } if ("SuppressWarnings".equals(identifier)) { - final List values = getAllAnnotationValues(ast); - if (isAnnotationEmpty(values)) { - return; - } - - final DetailAST targetAST = getAnnotationTarget(ast); + if (!isAnnotationEmpty(values)) { + final DetailAST targetAST = getAnnotationTarget(ast); - if (targetAST == null) { - log(ast.getLineNo(), MSG_KEY); - return; - } - - // get text range of target - final int firstLine = targetAST.getLineNo(); - final int firstColumn = targetAST.getColumnNo(); - final DetailAST nextAST = targetAST.getNextSibling(); - final int lastLine; - final int lastColumn; - if (nextAST == null) { - lastLine = Integer.MAX_VALUE; - lastColumn = Integer.MAX_VALUE; - } - else { - lastLine = nextAST.getLineNo(); - lastColumn = nextAST.getColumnNo() - 1; - } - - // add suppression entries for listed checks - final List entries = ENTRIES.get(); - for (String value : values) { - String checkName = value; - // strip off the checkstyle-only prefix if present - checkName = removeCheckstylePrefixIfExists(checkName); - entries.add(new Entry(checkName, firstLine, firstColumn, - lastLine, lastColumn)); + if (targetAST == null) { + log(ast.getLineNo(), MSG_KEY); + } + else { + // get text range of target + final int firstLine = targetAST.getLineNo(); + final int firstColumn = targetAST.getColumnNo(); + final DetailAST nextAST = targetAST.getNextSibling(); + final int lastLine; + final int lastColumn; + if (nextAST == null) { + lastLine = Integer.MAX_VALUE; + lastColumn = Integer.MAX_VALUE; + } + else { + lastLine = nextAST.getLineNo(); + lastColumn = nextAST.getColumnNo() - 1; + } + + // add suppression entries for listed checks + final List entries = ENTRIES.get(); + for (String value : values) { + String checkName = value; + // strip off the checkstyle-only prefix if present + checkName = removeCheckstylePrefixIfExists(checkName); + entries.add(new Entry(checkName, firstLine, firstColumn, + lastLine, lastColumn)); + } + } } } } @@ -383,16 +405,18 @@ * @throws IllegalArgumentException if the AST is invalid */ private static String getIdentifier(DetailAST ast) { - if (ast != null) { - if (ast.getType() == TokenTypes.IDENT) { - return ast.getText(); - } - else { - return getIdentifier(ast.getFirstChild()) + "." - + getIdentifier(ast.getLastChild()); - } + if (ast == null) { + throw new IllegalArgumentException("Identifier AST expected, but get null."); + } + final String identifier; + if (ast.getType() == TokenTypes.IDENT) { + identifier = ast.getText(); + } + else { + identifier = getIdentifier(ast.getFirstChild()) + "." + + getIdentifier(ast.getLastChild()); } - throw new IllegalArgumentException("Identifier AST expected, but get null."); + return identifier; } /** @@ -432,17 +456,19 @@ * @throws IllegalArgumentException if the AST is invalid */ private static List getAnnotationValues(DetailAST ast) { + final List annotationValues; switch (ast.getType()) { case TokenTypes.EXPR: - return ImmutableList.of(getStringExpr(ast)); - + annotationValues = Collections.singletonList(getStringExpr(ast)); + break; case TokenTypes.ANNOTATION_ARRAY_INIT: - return findAllExpressionsInChildren(ast); - + annotationValues = findAllExpressionsInChildren(ast); + break; default: throw new IllegalArgumentException( "Expression or annotation array initializer AST expected: " + ast); } + return annotationValues; } /** @@ -451,7 +477,7 @@ * @return list of expressions in strings */ private static List findAllExpressionsInChildren(DetailAST parent) { - final List valueList = Lists.newLinkedList(); + final List valueList = new LinkedList<>(); DetailAST childAST = parent.getFirstChild(); while (childAST != null) { if (childAST.getType() == TokenTypes.EXPR) { @@ -464,6 +490,7 @@ /** Records a particular suppression for a region of a file. */ private static class Entry { + /** The source name of the suppressed check. */ private final String checkName; /** The suppression region for the check - first line. */ @@ -531,5 +558,7 @@ public int getLastColumn() { return lastColumn; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/TodoCommentCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/TodoCommentCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/TodoCommentCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/TodoCommentCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,10 +21,10 @@ import java.util.regex.Pattern; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    @@ -51,8 +51,9 @@ * @author Oliver Burn * @author Baratali Izmailov */ +@StatelessCheck public class TodoCommentCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -61,14 +62,9 @@ public static final String MSG_KEY = "todo.match"; /** - * Format of 'todo' comment. - */ - private String format = "TODO:"; - - /** * Regular expression pattern compiled from format. */ - private Pattern regexp = Pattern.compile(format); + private Pattern format = Pattern.compile("TODO:"); @Override public boolean isCommentNodesRequired() { @@ -76,30 +72,27 @@ } /** - * Setter for 'todo' comment format. - * @param format - * format of 'todo' comment. - * @throws org.apache.commons.beanutils.ConversionException - * if unable to create Pattern object. + * Setter for 'todo' comment pattern. + * @param pattern + * pattern of 'todo' comment. */ - public void setFormat(String format) { - this.format = format; - regexp = CommonUtils.createPattern(format); + public void setFormat(Pattern pattern) { + format = pattern; } @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.COMMENT_CONTENT }; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.COMMENT_CONTENT }; } @Override @@ -107,9 +100,10 @@ final String[] lines = ast.getText().split("\n"); for (int i = 0; i < lines.length; i++) { - if (regexp.matcher(lines[i]).find()) { - log(ast.getLineNo() + i, MSG_KEY, format); + if (format.matcher(lines[i]).find()) { + log(ast.getLineNo() + i, MSG_KEY, format.pattern()); } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/TrailingCommentCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,31 +19,31 @@ package com.puppycrawl.tools.checkstyle.checks; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; -import org.apache.commons.lang3.ArrayUtils; - -import com.google.common.collect.Sets; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TextBlock; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    - * The check to ensure that requires that comments be the only thing on a line. - * For the case of // comments that means that the only thing that should + * The check to ensure that comments are the only thing on a line. + * For the case of {@code //} comments that means that the only thing that should * precede it is whitespace. * It doesn't check comments if they do not end line, i.e. it accept * the following: - * {@code Thread.sleep( 10 <some comment here> );} - * Format property is intended to deal with the "} // while" example. + *

    + *
    Thread.sleep( 10 /*some comment here*/ );
    + *

    Format property is intended to deal with the } // while example. *

    * - *

    Rationale: Steve McConnel in "Code Complete" suggests that endline + *

    Rationale: Steve McConnell in "Code Complete" suggests that endline * comments are a bad practice. An end line comment would * be one that is on the same line as actual code. For example: *

    @@ -98,8 +98,10 @@
      * 
    * * @author o_sukhodolsky + * @noinspection HtmlTagCanBeJavadocTag */ -public class TrailingCommentCheck extends Check { +@StatelessCheck +public class TrailingCommentCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -110,43 +112,38 @@ /** Pattern for legal trailing comment. */ private Pattern legalComment; - /** The format string of the regexp. */ - private String format = "^[\\s\\}\\);]*$"; - /** The regexp to match against. */ - private Pattern regexp = Pattern.compile(format); + private Pattern format = Pattern.compile("^[\\s});]*$"); /** * Sets patter for legal trailing comments. - * @param legalComment format to set. + * @param legalComment pattern to set. */ - public void setLegalComment(final String legalComment) { - this.legalComment = CommonUtils.createPattern(legalComment); + public void setLegalComment(final Pattern legalComment) { + this.legalComment = legalComment; } /** - * Set the format to the specified regular expression. - * @param format a {@code String} value - * @throws org.apache.commons.beanutils.ConversionException unable to parse format + * Set the format for the specified regular expression. + * @param pattern a pattern */ - public final void setFormat(String format) { - this.format = format; - regexp = CommonUtils.createPattern(format); + public final void setFormat(Pattern pattern) { + format = pattern; } @Override public int[] getDefaultTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -157,10 +154,10 @@ @Override public void beginTree(DetailAST rootAST) { final Map cppComments = getFileContents() - .getCppComments(); + .getSingleLineComments(); final Map> cComments = getFileContents() - .getCComments(); - final Set lines = Sets.newHashSet(); + .getBlockComments(); + final Set lines = new HashSet<>(); lines.addAll(cppComments.keySet()); lines.addAll(cComments.keySet()); @@ -179,11 +176,12 @@ // do not check comment which doesn't end line if (comment.getText().length == 1 - && !line.substring(comment.getEndColNo() + 1).trim().isEmpty()) { + && !CommonUtils.isBlank(line + .substring(comment.getEndColNo() + 1))) { continue; } } - if (!regexp.matcher(lineBefore).find() + if (!format.matcher(lineBefore).find() && !isLegalComment(comment)) { log(lineNo, MSG_KEY); } @@ -216,4 +214,5 @@ } return legal; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/TranslationCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,37 +24,39 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; import java.util.Collections; -import java.util.Enumeration; -import java.util.List; +import java.util.HashSet; import java.util.Locale; +import java.util.Optional; import java.util.Properties; import java.util.Set; import java.util.SortedSet; +import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import com.google.common.base.Splitter; import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableSortedSet; -import com.google.common.collect.Lists; import com.google.common.collect.SetMultimap; -import com.google.common.collect.Sets; import com.google.common.io.Closeables; import com.puppycrawl.tools.checkstyle.Definitions; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; +import com.puppycrawl.tools.checkstyle.api.FileText; import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; import com.puppycrawl.tools.checkstyle.api.MessageDispatcher; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    * The TranslationCheck class helps to ensure the correct translation of code by - * checking property files for consistency regarding their keys. - * Two property files describing one and the same context are consistent if they - * contain the same keys. + * checking locale-specific resource files for consistency regarding their keys. + * Two locale-specific resource files describing one and the same context are consistent if they + * contain the same keys. TranslationCheck also can check an existence of required translations + * which must exist in project, if 'requiredTranslations' option is used. *

    *

    * An example of how to configure the check is: @@ -62,36 +64,44 @@ *

      * <module name="Translation"/>
      * 
    - * Check has the following properties: + * Check has the following options: * - *

    basenameSeparator which allows setting separator in file names, - * default value is '_'. - *

    - * E.g.: - *

    - *

    - * messages_test.properties //separator is '_' + *

    baseName - a base name regexp for resource bundles which contain message resources. It + * helps the check to distinguish config and localization resources. Default value is + * ^messages.*$ + *

    An example of how to configure the check to validate only bundles which base names start with + * "ButtonLabels": *

    - *

    - * app-dev.properties //separator is '-' + *

    + * <module name="Translation">
    + *     <property name="baseName" value="^ButtonLabels.*$"/>
    + * </module>
    + * 
    + *

    To configure the check to check only files which have '.properties' and '.translations' + * extensions: *

    + *
    + * <module name="Translation">
    + *     <property name="fileExtensions" value="properties, translations"/>
    + * </module>
    + * 
    * - *

    requiredTranslations which allows to specify language codes of - * required translations which must exist in project. The check looks only for - * messages bundles which names contain the word 'messages'. - * Language code is composed of the lowercase, two-letter codes as defined by - * ISO 639-1. + *

    requiredTranslations which allows to specify language codes of required translations + * which must exist in project. Language code is composed of the lowercase, two-letter codes as + * defined by ISO 639-1. * Default value is empty String Set which means that only the existence of - * default translation is checked. - * Note, if you specify language codes (or just one language code) of required translations - * the check will also check for existence of default translation files in project. + * default translation is checked. Note, if you specify language codes (or just one language + * code) of required translations the check will also check for existence of default translation + * files in project. ATTENTION: the check will perform the validation of ISO codes if the option + * is used. So, if you specify, for example, "mm" for language code, TranslationCheck will rise + * violation that the language code is incorrect. *
    + * * @author Alexandra Bunge * @author lkuehne * @author Andrei Selkin */ -public class TranslationCheck - extends AbstractFileSetCheck { +public class TranslationCheck extends AbstractFileSetCheck { /** * A key is pointing to the warning message text for missing key @@ -106,289 +116,376 @@ public static final String MSG_KEY_MISSING_TRANSLATION_FILE = "translation.missingTranslationFile"; + /** Resource bundle which contains messages for TranslationCheck. */ + private static final String TRANSLATION_BUNDLE = + "com.puppycrawl.tools.checkstyle.checks.messages"; + + /** + * A key is pointing to the warning message text for wrong language code + * in "messages.properties" file. + */ + private static final String WRONG_LANGUAGE_CODE_KEY = "translation.wrongLanguageCode"; + + /** + * Regexp string for default translation files. + * For example, messages.properties. + */ + private static final String DEFAULT_TRANSLATION_REGEXP = "^.+\\..+$"; + + /** + * Regexp pattern for bundles names which end with language code, followed by country code and + * variant suffix. For example, messages_es_ES_UNIX.properties. + */ + private static final Pattern LANGUAGE_COUNTRY_VARIANT_PATTERN = + CommonUtils.createPattern("^.+\\_[a-z]{2}\\_[A-Z]{2}\\_[A-Za-z]+\\..+$"); + /** + * Regexp pattern for bundles names which end with language code, followed by country code + * suffix. For example, messages_es_ES.properties. + */ + private static final Pattern LANGUAGE_COUNTRY_PATTERN = + CommonUtils.createPattern("^.+\\_[a-z]{2}\\_[A-Z]{2}\\..+$"); + /** + * Regexp pattern for bundles names which end with language code suffix. + * For example, messages_es.properties. + */ + private static final Pattern LANGUAGE_PATTERN = + CommonUtils.createPattern("^.+\\_[a-z]{2}\\..+$"); + + /** File name format for default translation. */ + private static final String DEFAULT_TRANSLATION_FILE_NAME_FORMATTER = "%s.%s"; + /** File name format with language code. */ + private static final String FILE_NAME_WITH_LANGUAGE_CODE_FORMATTER = "%s_%s.%s"; + + /** Formatting string to form regexp to validate required translations file names. */ + private static final String REGEXP_FORMAT_TO_CHECK_REQUIRED_TRANSLATIONS = + "^%1$s\\_%2$s(\\_[A-Z]{2})?\\.%3$s$|^%1$s\\_%2$s\\_[A-Z]{2}\\_[A-Za-z]+\\.%3$s$"; + /** Formatting string to form regexp to validate default translations file names. */ + private static final String REGEXP_FORMAT_TO_CHECK_DEFAULT_TRANSLATIONS = "^%s\\.%s$"; + /** Logger for TranslationCheck. */ - private static final Log LOG = LogFactory.getLog(TranslationCheck.class); + private final Log log; - /** The property files to process. */ - private final List propertyFiles = Lists.newArrayList(); + /** The files to process. */ + private final Set filesToProcess = new HashSet<>(); - /** The separator string used to separate translation files. */ - private String basenameSeparator; + /** The base name regexp pattern. */ + private Pattern baseName; /** * Language codes of required translations for the check (de, pt, ja, etc). */ - private SortedSet requiredTranslations = ImmutableSortedSet.of(); + private Set requiredTranslations = new HashSet<>(); /** * Creates a new {@code TranslationCheck} instance. */ public TranslationCheck() { setFileExtensions("properties"); - basenameSeparator = "_"; + baseName = CommonUtils.createPattern("^messages.*$"); + log = LogFactory.getLog(TranslationCheck.class); } /** - * Sets language codes of required translations for the check. - * @param translationCodes a comma separated list of language codes. + * Sets the base name regexp pattern. + * @param baseName base name regexp. */ - public void setRequiredTranslations(String translationCodes) { - requiredTranslations = Sets.newTreeSet(Splitter.on(',') - .trimResults().omitEmptyStrings().split(translationCodes)); - } - - @Override - public void beginProcessing(String charset) { - super.beginProcessing(charset); - propertyFiles.clear(); + public void setBaseName(Pattern baseName) { + this.baseName = baseName; } - @Override - protected void processFiltered(File file, List lines) { - propertyFiles.add(file); - } - - @Override - public void finishProcessing() { - super.finishProcessing(); - final SetMultimap propFilesMap = - arrangePropertyFiles(propertyFiles, basenameSeparator); - checkExistenceOfTranslations(propFilesMap); - checkPropertyFileSets(propFilesMap); + /** + * Sets language codes of required translations for the check. + * @param translationCodes a comma separated list of language codes. + */ + public void setRequiredTranslations(String... translationCodes) { + requiredTranslations = Arrays.stream(translationCodes).collect(Collectors.toSet()); + validateUserSpecifiedLanguageCodes(requiredTranslations); } /** - * Checks existence of translation files (arranged in a map) - * for each resource bundle in project. - * @param translations the translation files bundles organized as Map. - */ - private void checkExistenceOfTranslations(SetMultimap translations) { - for (String fullyQualifiedBundleName : translations.keySet()) { - final String bundleBaseName = extractName(fullyQualifiedBundleName); - if (bundleBaseName.contains("messages")) { - final Set filesInBundle = translations.get(fullyQualifiedBundleName); - checkExistenceOfDefaultTranslation(filesInBundle); - checkExistenceOfRequiredTranslations(filesInBundle); + * Validates the correctness of user specified language codes for the check. + * @param languageCodes user specified language codes for the check. + */ + private void validateUserSpecifiedLanguageCodes(Set languageCodes) { + for (String code : languageCodes) { + if (!isValidLanguageCode(code)) { + final LocalizedMessage msg = new LocalizedMessage(0, TRANSLATION_BUNDLE, + WRONG_LANGUAGE_CODE_KEY, new Object[] {code}, getId(), getClass(), null); + final String exceptionMessage = String.format(Locale.ROOT, + "%s [%s]", msg.getMessage(), TranslationCheck.class.getSimpleName()); + throw new IllegalArgumentException(exceptionMessage); } } } /** - * Checks an existence of default translation file in - * a set of files in resource bundle. The name of this file - * begins with the full name of the resource bundle and ends - * with the extension suffix. - * @param filesInResourceBundle a set of files in resource bundle. - */ - private void checkExistenceOfDefaultTranslation(Set filesInResourceBundle) { - final String fullBundleName = getFullBundleName(filesInResourceBundle); - final String extension = getFileExtensions()[0]; - final String defaultTranslationFileName = fullBundleName + extension; - - final boolean missing = isMissing(defaultTranslationFileName, filesInResourceBundle); - if (missing) { - logMissingTranslation(defaultTranslationFileName); + * Checks whether user specified language code is correct (is contained in available locales). + * @param userSpecifiedLanguageCode user specified language code. + * @return true if user specified language code is correct. + */ + private static boolean isValidLanguageCode(final String userSpecifiedLanguageCode) { + boolean valid = false; + final Locale[] locales = Locale.getAvailableLocales(); + for (Locale locale : locales) { + if (userSpecifiedLanguageCode.equals(locale.toString())) { + valid = true; + break; + } } + return valid; } - /** - * Checks existence of translation files in a set of files - * in resource bundle. If there is no translation file - * with required language code, there will be a violation. - * The name of translation file begins with the full name - * of resource bundle which is followed by '_' and language code, - * it ends with the extension suffix. - * @param filesInResourceBundle a set of files in resource bundle. - */ - private void checkExistenceOfRequiredTranslations(Set filesInResourceBundle) { - final String fullBundleName = getFullBundleName(filesInResourceBundle); - final String extension = getFileExtensions()[0]; + @Override + public void beginProcessing(String charset) { + filesToProcess.clear(); + } - for (String languageCode : requiredTranslations) { - final String translationFileName = - fullBundleName + '_' + languageCode + extension; + @Override + protected void processFiltered(File file, FileText fileText) { + // We just collecting files for processing at finishProcessing() + filesToProcess.add(file); + } - final boolean missing = isMissing(translationFileName, filesInResourceBundle); - if (missing) { - final String missingTranslationFileName = - formMissingTranslationName(fullBundleName, languageCode); - logMissingTranslation(missingTranslationFileName); - } + @Override + public void finishProcessing() { + final Set bundles = groupFilesIntoBundles(filesToProcess, baseName); + for (ResourceBundle currentBundle : bundles) { + checkExistenceOfDefaultTranslation(currentBundle); + checkExistenceOfRequiredTranslations(currentBundle); + checkTranslationKeys(currentBundle); } } /** - * Gets full name of resource bundle. - * Full name of resource bundle consists of bundle path and - * full base name. - * @param filesInResourceBundle a set of files in resource bundle. - * @return full name of resource bundle. - */ - private String getFullBundleName(Set filesInResourceBundle) { - final String fullBundleName; - - final File firstTranslationFile = Collections.min(filesInResourceBundle); - final String translationPath = firstTranslationFile.getPath(); - final String extension = getFileExtensions()[0]; - - final Pattern pattern = Pattern.compile("^.+_[a-z]{2}" - + extension + "$"); - final Matcher matcher = pattern.matcher(translationPath); - if (matcher.matches()) { - fullBundleName = translationPath - .substring(0, translationPath.lastIndexOf('_')); - } - else { - fullBundleName = translationPath - .substring(0, translationPath.lastIndexOf('.')); + * Checks an existence of default translation file in the resource bundle. + * @param bundle resource bundle. + */ + private void checkExistenceOfDefaultTranslation(ResourceBundle bundle) { + final Optional fileName = getMissingFileName(bundle, null); + if (fileName.isPresent()) { + logMissingTranslation(bundle.getPath(), fileName.get()); } - return fullBundleName; } /** - * Checks whether file is missing in resource bundle. - * @param fileName file name. - * @param filesInResourceBundle a set of files in resource bundle. - * @return true if file is missing. + * Checks an existence of translation files in the resource bundle. + * The name of translation file begins with the base name of resource bundle which is followed + * by '_' and a language code (country and variant are optional), it ends with the extension + * suffix. + * @param bundle resource bundle. */ - private static boolean isMissing(String fileName, Set filesInResourceBundle) { - boolean missing = false; - for (File file : filesInResourceBundle) { - final String currentFileName = file.getPath(); - missing = !currentFileName.equals(fileName); - if (!missing) { - break; + private void checkExistenceOfRequiredTranslations(ResourceBundle bundle) { + for (String languageCode : requiredTranslations) { + final Optional fileName = getMissingFileName(bundle, languageCode); + if (fileName.isPresent()) { + logMissingTranslation(bundle.getPath(), fileName.get()); } } - return missing; } /** - * Forms a name of translation file which is missing. - * @param fullBundleName full bundle name. + * Returns the name of translation file which is absent in resource bundle or Guava's Optional, + * if there is not missing translation. + * @param bundle resource bundle. * @param languageCode language code. - * @return name of translation file which is missing. + * @return the name of translation file which is absent in resource bundle or Guava's Optional, + * if there is not missing translation. */ - private String formMissingTranslationName(String fullBundleName, String languageCode) { - final String extension = getFileExtensions()[0]; - return String.format(Locale.ROOT, "%s_%s%s", fullBundleName, languageCode, extension); + private static Optional getMissingFileName(ResourceBundle bundle, String languageCode) { + final String fileNameRegexp; + final boolean searchForDefaultTranslation; + final String extension = bundle.getExtension(); + final String baseName = bundle.getBaseName(); + if (languageCode == null) { + searchForDefaultTranslation = true; + fileNameRegexp = String.format(Locale.ROOT, REGEXP_FORMAT_TO_CHECK_DEFAULT_TRANSLATIONS, + baseName, extension); + } + else { + searchForDefaultTranslation = false; + fileNameRegexp = String.format(Locale.ROOT, + REGEXP_FORMAT_TO_CHECK_REQUIRED_TRANSLATIONS, baseName, languageCode, extension); + } + Optional missingFileName = Optional.empty(); + if (!bundle.containsFile(fileNameRegexp)) { + if (searchForDefaultTranslation) { + missingFileName = Optional.of(String.format(Locale.ROOT, + DEFAULT_TRANSLATION_FILE_NAME_FORMATTER, baseName, extension)); + } + else { + missingFileName = Optional.of(String.format(Locale.ROOT, + FILE_NAME_WITH_LANGUAGE_CODE_FORMATTER, baseName, languageCode, extension)); + } + } + return missingFileName; } /** * Logs that translation file is missing. - * @param fullyQualifiedFileName fully qualified file name. + * @param filePath file path. + * @param fileName file name. */ - private void logMissingTranslation(String fullyQualifiedFileName) { - final String filePath = extractPath(fullyQualifiedFileName); - + private void logMissingTranslation(String filePath, String fileName) { final MessageDispatcher dispatcher = getMessageDispatcher(); dispatcher.fireFileStarted(filePath); - - log(0, MSG_KEY_MISSING_TRANSLATION_FILE, extractName(fullyQualifiedFileName)); - + log(0, MSG_KEY_MISSING_TRANSLATION_FILE, fileName); fireErrors(filePath); dispatcher.fireFileFinished(filePath); } /** - * Extracts path from fully qualified file name. - * @param fullyQualifiedFileName fully qualified file name. - * @return file path. - */ - private static String extractPath(String fullyQualifiedFileName) { - return fullyQualifiedFileName - .substring(0, fullyQualifiedFileName.lastIndexOf(File.separator)); + * Groups a set of files into bundles. + * Only files, which names match base name regexp pattern will be grouped. + * @param files set of files. + * @param baseNameRegexp base name regexp pattern. + * @return set of ResourceBundles. + */ + private static Set groupFilesIntoBundles(Set files, + Pattern baseNameRegexp) { + final Set resourceBundles = new HashSet<>(); + for (File currentFile : files) { + final String fileName = currentFile.getName(); + final String baseName = extractBaseName(fileName); + final Matcher baseNameMatcher = baseNameRegexp.matcher(baseName); + if (baseNameMatcher.matches()) { + final String extension = CommonUtils.getFileExtension(fileName); + final String path = getPath(currentFile.getAbsolutePath()); + final ResourceBundle newBundle = new ResourceBundle(baseName, path, extension); + final Optional bundle = findBundle(resourceBundles, newBundle); + if (bundle.isPresent()) { + bundle.get().addFile(currentFile); + } + else { + newBundle.addFile(currentFile); + resourceBundles.add(newBundle); + } + } + } + return resourceBundles; } /** - * Extracts short file name from fully qualified file name. - * @param fullyQualifiedFileName fully qualified file name. - * @return short file name. - */ - private static String extractName(String fullyQualifiedFileName) { - return fullyQualifiedFileName - .substring(fullyQualifiedFileName.lastIndexOf(File.separator) + 1); + * Searches for specific resource bundle in a set of resource bundles. + * @param bundles set of resource bundles. + * @param targetBundle target bundle to search for. + * @return Guava's Optional of resource bundle (present if target bundle is found). + */ + private static Optional findBundle(Set bundles, + ResourceBundle targetBundle) { + Optional result = Optional.empty(); + for (ResourceBundle currentBundle : bundles) { + if (targetBundle.getBaseName().equals(currentBundle.getBaseName()) + && targetBundle.getExtension().equals(currentBundle.getExtension()) + && targetBundle.getPath().equals(currentBundle.getPath())) { + result = Optional.of(currentBundle); + break; + } + } + return result; } /** - * Gets the basename (the unique prefix) of a property file. For example - * "xyz/messages" is the basename of "xyz/messages.properties", - * "xyz/messages_de_AT.properties", "xyz/messages_en.properties", etc. - * - * @param file the file - * @param basenameSeparator the basename separator - * @return the extracted basename - */ - private static String extractPropertyIdentifier(File file, String basenameSeparator) { - final String filePath = file.getPath(); - final int dirNameEnd = filePath.lastIndexOf(File.separatorChar); - final int baseNameStart = dirNameEnd + 1; - final int underscoreIdx = filePath.indexOf(basenameSeparator, - baseNameStart); - final int dotIdx = filePath.indexOf('.', baseNameStart); - final int cutoffIdx; - - if (underscoreIdx == -1) { - cutoffIdx = dotIdx; + * Extracts the base name (the unique prefix) of resource bundle from translation file name. + * For example "messages" is the base name of "messages.properties", + * "messages_de_AT.properties", "messages_en.properties", etc. + * @param fileName the fully qualified name of the translation file. + * @return the extracted base name. + */ + private static String extractBaseName(String fileName) { + final String regexp; + final Matcher languageCountryVariantMatcher = + LANGUAGE_COUNTRY_VARIANT_PATTERN.matcher(fileName); + final Matcher languageCountryMatcher = LANGUAGE_COUNTRY_PATTERN.matcher(fileName); + final Matcher languageMatcher = LANGUAGE_PATTERN.matcher(fileName); + if (languageCountryVariantMatcher.matches()) { + regexp = LANGUAGE_COUNTRY_VARIANT_PATTERN.pattern(); + } + else if (languageCountryMatcher.matches()) { + regexp = LANGUAGE_COUNTRY_PATTERN.pattern(); + } + else if (languageMatcher.matches()) { + regexp = LANGUAGE_PATTERN.pattern(); } else { - cutoffIdx = underscoreIdx; + regexp = DEFAULT_TRANSLATION_REGEXP; } - return filePath.substring(0, cutoffIdx); + // We use substring(...) instead of replace(...), so that the regular expression does + // not have to be compiled each time it is used inside 'replace' method. + final String removePattern = regexp.substring("^.+".length(), regexp.length()); + return fileName.replaceAll(removePattern, ""); } /** - * Sets the separator used to determine the basename of a property file. - * This defaults to "_" - * - * @param basenameSeparator the basename separator + * Extracts path from a file name which contains the path. + * For example, if file nam is /xyz/messages.properties, then the method + * will return /xyz/. + * @param fileNameWithPath file name which contains the path. + * @return file path. */ - public final void setBasenameSeparator(String basenameSeparator) { - this.basenameSeparator = basenameSeparator; + private static String getPath(String fileNameWithPath) { + return fileNameWithPath + .substring(0, fileNameWithPath.lastIndexOf(File.separator)); } /** - * Arranges a set of property files by their prefix. - * The method returns a Map object. The filename prefixes - * work as keys each mapped to a set of files. - * @param propFiles the set of property files - * @param basenameSeparator the basename separator - * @return a Map object which holds the arranged property file sets - */ - private static SetMultimap arrangePropertyFiles( - List propFiles, String basenameSeparator) { - final SetMultimap propFileMap = HashMultimap.create(); - - for (final File file : propFiles) { - final String identifier = extractPropertyIdentifier(file, - basenameSeparator); + * Checks resource files in bundle for consistency regarding their keys. + * All files in bundle must have the same key set. If this is not the case + * an error message is posted giving information which key misses in which file. + * @param bundle resource bundle. + */ + private void checkTranslationKeys(ResourceBundle bundle) { + final Set filesInBundle = bundle.getFiles(); + if (filesInBundle.size() >= 2) { + // build a map from files to the keys they contain + final Set allTranslationKeys = new HashSet<>(); + final SetMultimap filesAssociatedWithKeys = HashMultimap.create(); + for (File currentFile : filesInBundle) { + final Set keysInCurrentFile = getTranslationKeys(currentFile); + allTranslationKeys.addAll(keysInCurrentFile); + filesAssociatedWithKeys.putAll(currentFile, keysInCurrentFile); + } + checkFilesForConsistencyRegardingTheirKeys(filesAssociatedWithKeys, allTranslationKeys); + } + } - final Set fileSet = propFileMap.get(identifier); - fileSet.add(file); + /** + * Compares th the specified key set with the key sets of the given translation files (arranged + * in a map). All missing keys are reported. + * @param fileKeys a Map from translation files to their key sets. + * @param keysThatMustExist the set of keys to compare with. + */ + private void checkFilesForConsistencyRegardingTheirKeys(SetMultimap fileKeys, + Set keysThatMustExist) { + for (File currentFile : fileKeys.keySet()) { + final MessageDispatcher dispatcher = getMessageDispatcher(); + final String path = currentFile.getPath(); + dispatcher.fireFileStarted(path); + final Set currentFileKeys = fileKeys.get(currentFile); + final Set missingKeys = keysThatMustExist.stream() + .filter(e -> !currentFileKeys.contains(e)).collect(Collectors.toSet()); + if (!missingKeys.isEmpty()) { + for (Object key : missingKeys) { + log(0, MSG_KEY, key); + } + } + fireErrors(path); + dispatcher.fireFileFinished(path); } - return propFileMap; } /** - * Loads the keys of the specified property file into a set. - * @param file the property file - * @return a Set object which holds the loaded keys + * Loads the keys from the specified translation file into a set. + * @param file translation file. + * @return a Set object which holds the loaded keys. */ - private Set loadKeys(File file) { - final Set keys = Sets.newHashSet(); + private Set getTranslationKeys(File file) { + Set keys = new HashSet<>(); InputStream inStream = null; - try { - // Load file and properties. inStream = new FileInputStream(file); - final Properties props = new Properties(); - props.load(inStream); - - // Gather the keys and put them into a set - final Enumeration element = props.propertyNames(); - while (element.hasMoreElements()) { - keys.add(element.nextElement()); - } + final Properties translations = new Properties(); + translations.load(inStream); + keys = translations.stringPropertyNames(); } catch (final IOException ex) { logIoException(ex, file); @@ -419,71 +516,77 @@ args, getId(), getClass(), null); - final SortedSet messages = Sets.newTreeSet(); + final SortedSet messages = new TreeSet<>(); messages.add(message); getMessageDispatcher().fireErrors(file.getPath(), messages); - LOG.debug("IOException occurred.", exception); + log.debug("IOException occurred.", exception); } - /** - * Compares the key sets of the given property files (arranged in a map) - * with the specified key set. All missing keys are reported. - * @param keys the set of keys to compare with - * @param fileMap a Map from property files to their key sets - */ - private void compareKeySets(Set keys, - SetMultimap fileMap) { + /** Class which represents a resource bundle. */ + private static class ResourceBundle { - for (File currentFile : fileMap.keySet()) { - final MessageDispatcher dispatcher = getMessageDispatcher(); - final String path = currentFile.getPath(); - dispatcher.fireFileStarted(path); - final Set currentKeys = fileMap.get(currentFile); + /** Bundle base name. */ + private final String baseName; + /** Common extension of files which are included in the resource bundle. */ + private final String extension; + /** Common path of files which are included in the resource bundle. */ + private final String path; + /** Set of files which are included in the resource bundle. */ + private final Set files; - // Clone the keys so that they are not lost - final Set keysClone = Sets.newHashSet(keys); - keysClone.removeAll(currentKeys); - - // Remaining elements in the key set are missing in the current file - if (!keysClone.isEmpty()) { - for (Object key : keysClone) { - log(0, MSG_KEY, key); - } - } - fireErrors(path); - dispatcher.fireFileFinished(path); + /** + * Creates a ResourceBundle object with specific base name, common files extension. + * @param baseName bundle base name. + * @param path common path of files which are included in the resource bundle. + * @param extension common extension of files which are included in the resource bundle. + */ + ResourceBundle(String baseName, String path, String extension) { + this.baseName = baseName; + this.path = path; + this.extension = extension; + files = new HashSet<>(); } - } - /** - * Tests whether the given property files (arranged by their prefixes - * in a Map) contain the proper keys. - * - *

    Each group of files must have the same keys. If this is not the case - * an error message is posted giving information which key misses in - * which file. - * - * @param propFiles the property files organized as Map - */ - private void checkPropertyFileSets(SetMultimap propFiles) { - - for (String key : propFiles.keySet()) { - final Set files = propFiles.get(key); - - if (files.size() >= 2) { - // build a map from files to the keys they contain - final Set keys = Sets.newHashSet(); - final SetMultimap fileMap = HashMultimap.create(); - - for (File file : files) { - final Set fileKeys = loadKeys(file); - keys.addAll(fileKeys); - fileMap.putAll(file, fileKeys); - } + public String getBaseName() { + return baseName; + } + + public String getPath() { + return path; + } + + public String getExtension() { + return extension; + } - // check the map for consistency - compareKeySets(keys, fileMap); + public Set getFiles() { + return Collections.unmodifiableSet(files); + } + + /** + * Adds a file into resource bundle. + * @param file file which should be added into resource bundle. + */ + public void addFile(File file) { + files.add(file); + } + + /** + * Checks whether a resource bundle contains a file which name matches file name regexp. + * @param fileNameRegexp file name regexp. + * @return true if a resource bundle contains a file which name matches file name regexp. + */ + public boolean containsFile(String fileNameRegexp) { + boolean containsFile = false; + for (File currentFile : files) { + if (Pattern.matches(fileNameRegexp, currentFile.getName())) { + containsFile = true; + break; + } } + return containsFile; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/UncommentedMainCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/UncommentedMainCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/UncommentedMainCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/UncommentedMainCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,14 +19,14 @@ package com.puppycrawl.tools.checkstyle.checks; +import java.util.Optional; import java.util.regex.Pattern; -import com.google.common.base.Optional; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FullIdent; import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * Detects uncommented main methods. Basically detects @@ -40,8 +40,9 @@ * @author Michael Yui * @author o_sukhodolsky */ +@FileStatefulCheck public class UncommentedMainCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -49,11 +50,8 @@ */ public static final String MSG_KEY = "uncommented.main"; - /** The pattern to exclude classes from the check. */ - private String excludedClasses = "^$"; /** Compiled regexp to exclude classes from check. */ - private Pattern excludedClassesPattern = - CommonUtils.createPattern(excludedClasses); + private Pattern excludedClasses = Pattern.compile("^$"); /** Current class name. */ private String currentClass; /** Current package. */ @@ -63,30 +61,29 @@ /** * Set the excluded classes pattern. - * @param excludedClasses a {@code String} value + * @param excludedClasses a pattern */ - public void setExcludedClasses(String excludedClasses) { + public void setExcludedClasses(Pattern excludedClasses) { this.excludedClasses = excludedClasses; - excludedClassesPattern = CommonUtils.createPattern(excludedClasses); } @Override public int[] getAcceptableTokens() { - return new int[] { - TokenTypes.METHOD_DEF, - TokenTypes.CLASS_DEF, - TokenTypes.PACKAGE_DEF, - }; + return getRequiredTokens(); } @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] { + TokenTypes.METHOD_DEF, + TokenTypes.CLASS_DEF, + TokenTypes.PACKAGE_DEF, + }; } @Override @@ -99,16 +96,12 @@ @Override public void leaveToken(DetailAST ast) { if (ast.getType() == TokenTypes.CLASS_DEF) { - if (classDepth == 1) { - currentClass = null; - } classDepth--; } } @Override public void visitToken(DetailAST ast) { - switch (ast.getType()) { case TokenTypes.PACKAGE_DEF: visitPackageDef(ast); @@ -153,16 +146,13 @@ * @param method method definition node */ private void visitMethodDef(DetailAST method) { - if (classDepth != 1) { - // method in inner class or in interface definition - return; - } - - if (checkClassName() - && checkName(method) - && checkModifiers(method) - && checkType(method) - && checkParams(method)) { + if (classDepth == 1 + // method not in inner class or in interface definition + && checkClassName() + && checkName(method) + && checkModifiers(method) + && checkType(method) + && checkParams(method)) { log(method.getLineNo(), MSG_KEY); } } @@ -172,7 +162,7 @@ * @return true if check passed, false otherwise */ private boolean checkClassName() { - return !excludedClassesPattern.matcher(currentClass).find(); + return !excludedClasses.matcher(currentClass).find(); } /** @@ -194,8 +184,8 @@ final DetailAST modifiers = method.findFirstToken(TokenTypes.MODIFIERS); - return modifiers.branchContains(TokenTypes.LITERAL_PUBLIC) - && modifiers.branchContains(TokenTypes.LITERAL_STATIC); + return modifiers.findFirstToken(TokenTypes.LITERAL_PUBLIC) != null + && modifiers.findFirstToken(TokenTypes.LITERAL_STATIC) != null; } /** @@ -220,9 +210,9 @@ if (params.getChildCount() == 1) { final DetailAST parameterType = params.getFirstChild().findFirstToken(TokenTypes.TYPE); - final Optional arrayDecl = Optional.fromNullable( + final Optional arrayDecl = Optional.ofNullable( parameterType.findFirstToken(TokenTypes.ARRAY_DECLARATOR)); - final Optional varargs = Optional.fromNullable( + final Optional varargs = Optional.ofNullable( params.getFirstChild().findFirstToken(TokenTypes.ELLIPSIS)); if (arrayDecl.isPresent()) { @@ -245,4 +235,5 @@ return "String".equals(type.getText()) || "java.lang.String".equals(type.getText()); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/UniquePropertiesCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/UniquePropertiesCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/UniquePropertiesCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/UniquePropertiesCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,7 +22,6 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; -import java.util.List; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -31,7 +30,10 @@ import com.google.common.collect.ImmutableMultiset; import com.google.common.collect.Multiset; import com.google.common.collect.Multiset.Entry; +import com.google.common.io.Closeables; +import com.puppycrawl.tools.checkstyle.StatelessCheck; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; +import com.puppycrawl.tools.checkstyle.api.FileText; /** * Checks the uniqueness of property keys (left from equal sign) in the @@ -39,6 +41,7 @@ * * @author Pavel Baranchikov */ +@StatelessCheck public class UniquePropertiesCheck extends AbstractFileSetCheck { /** @@ -63,28 +66,25 @@ } @Override - protected void processFiltered(File file, List lines) { + protected void processFiltered(File file, FileText fileText) { final UniqueProperties properties = new UniqueProperties(); - + FileInputStream fileInputStream = null; try { - final FileInputStream fileInputStream = new FileInputStream(file); - try { - // As file is already read, there should not be any exceptions. - properties.load(fileInputStream); - } - finally { - fileInputStream.close(); - } + fileInputStream = new FileInputStream(file); + properties.load(fileInputStream); } catch (IOException ex) { log(0, MSG_IO_EXCEPTION_KEY, file.getPath(), ex.getLocalizedMessage()); } + finally { + Closeables.closeQuietly(fileInputStream); + } for (Entry duplication : properties .getDuplicatedKeys().entrySet()) { final String keyName = duplication.getElement(); - final int lineNumber = getLineNumber(lines, keyName); + final int lineNumber = getLineNumber(fileText, keyName); // Number of occurrences is number of duplications + 1 log(lineNumber, MSG_KEY, keyName, duplication.getCount() + 1); } @@ -94,38 +94,54 @@ * Method returns line number the key is detected in the checked properties * files first. * - * @param lines - * properties file lines list + * @param fileText + * {@link FileText} object contains the lines to process * @param keyName * key name to look for * @return line number of first occurrence. If no key found in properties * file, 0 is returned */ - protected static int getLineNumber(List lines, String keyName) { - final String keyPatternString = "^" + SPACE_PATTERN.matcher(keyName) - .replaceAll(Matcher.quoteReplacement("\\\\ ")) + "[\\s:=].*$"; - final Pattern keyPattern = Pattern.compile(keyPatternString); + private static int getLineNumber(FileText fileText, String keyName) { + final Pattern keyPattern = getKeyPattern(keyName); int lineNumber = 1; final Matcher matcher = keyPattern.matcher(""); - for (String line : lines) { + for (int index = 0; index < fileText.size(); index++) { + final String line = fileText.get(index); matcher.reset(line); if (matcher.matches()) { break; } ++lineNumber; } - if (lineNumber > lines.size()) { + // -1 as check seeks for the first duplicate occurrence in file, + // so it cannot be the last line. + if (lineNumber > fileText.size() - 1) { lineNumber = 0; } return lineNumber; } /** + * Method returns regular expression pattern given key name. + * + * @param keyName + * key name to look for + * @return regular expression pattern given key name + */ + private static Pattern getKeyPattern(String keyName) { + final String keyPatternString = "^" + SPACE_PATTERN.matcher(keyName) + .replaceAll(Matcher.quoteReplacement("\\\\ ")) + "[\\s:=].*$"; + return Pattern.compile(keyPatternString); + } + + /** * Properties subclass to store duplicated property keys in a separate map. * * @author Pavel Baranchikov + * @noinspection ClassExtendsConcreteCollection, SerializableHasSerializationMethods */ private static class UniqueProperties extends Properties { + private static final long serialVersionUID = 1L; /** * Multiset, holding duplicated keys. Keys are added here only if they @@ -134,8 +150,12 @@ private final Multiset duplicatedKeys = HashMultiset .create(); + /** + * Puts the value into properties by the key specified. + * @noinspection UseOfPropertiesAsHashtable + */ @Override - public Object put(Object key, Object value) { + public synchronized Object put(Object key, Object value) { final Object oldValue = super.put(key, value); if (oldValue != null && key instanceof String) { final String keyString = (String) key; @@ -152,5 +172,7 @@ public Multiset getDuplicatedKeys() { return ImmutableMultiset.copyOf(duplicatedKeys); } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/UpperEllCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/UpperEllCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/UpperEllCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/UpperEllCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -28,7 +29,7 @@ *

    Checks that long constants are defined with an upper ell. * That is 'L' and not * 'l'. This is in accordance to the Java Language - * Specification, + * Specification, * Section 3.10.1. *

    *

    @@ -47,7 +48,8 @@ * * @author Oliver Burn */ -public class UpperEllCheck extends Check { +@StatelessCheck +public class UpperEllCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -57,17 +59,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.NUM_LONG}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.NUM_LONG}; } @Override @@ -78,4 +80,5 @@ MSG_KEY); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/AbstractParenPadCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/AbstractParenPadCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/AbstractParenPadCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/AbstractParenPadCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,9 +21,8 @@ import java.util.Locale; -import org.apache.commons.beanutils.ConversionException; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -34,8 +33,9 @@ *

    * @author Oliver Burn */ +@StatelessCheck public abstract class AbstractParenPadCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -73,14 +73,14 @@ /** * Set the option to enforce. * @param optionStr string to decode option from - * @throws ConversionException if unable to decode + * @throws IllegalArgumentException if unable to decode */ public void setOption(String optionStr) { try { option = PadOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + optionStr, iae); + throw new IllegalArgumentException("unable to parse " + optionStr, iae); } } @@ -109,9 +109,9 @@ * @param ast the token representing a right parentheses */ protected void processRight(DetailAST ast) { - final String line = getLines()[ast.getLineNo() - 1]; final int before = ast.getColumnNo() - 1; if (before >= 0) { + final String line = getLines()[ast.getLineNo() - 1]; if (option == PadOption.NOSPACE && Character.isWhitespace(line.charAt(before)) && !CommonUtils.hasWhitespaceBefore(before, line)) { @@ -125,4 +125,5 @@ } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyForInitializerPadCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyForInitializerPadCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyForInitializerPadCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyForInitializerPadCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,9 +21,8 @@ import java.util.Locale; -import org.apache.commons.beanutils.ConversionException; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -50,8 +49,9 @@ * * @author lkuehne */ +@StatelessCheck public class EmptyForInitializerPadCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -74,30 +74,30 @@ /** * Set the option to enforce. * @param optionStr string to decode option from - * @throws ConversionException if unable to decode + * @throws IllegalArgumentException if unable to decode */ public void setOption(String optionStr) { try { option = PadOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + optionStr, iae); + throw new IllegalArgumentException("unable to parse " + optionStr, iae); } } @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.FOR_INIT}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.FOR_INIT}; } @Override @@ -121,4 +121,5 @@ } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyForIteratorPadCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyForIteratorPadCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyForIteratorPadCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyForIteratorPadCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,9 +21,8 @@ import java.util.Locale; -import org.apache.commons.beanutils.ConversionException; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; @@ -50,8 +49,9 @@ * * @author Rick Giles */ +@StatelessCheck public class EmptyForIteratorPadCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -74,30 +74,30 @@ /** * Set the option to enforce. * @param optionStr string to decode option from - * @throws ConversionException if unable to decode + * @throws IllegalArgumentException if unable to decode */ public void setOption(String optionStr) { try { option = PadOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + optionStr, iae); + throw new IllegalArgumentException("unable to parse " + optionStr, iae); } } @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.FOR_ITERATOR}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.FOR_ITERATOR}; } @Override @@ -120,4 +120,5 @@ } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyLineSeparatorCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyLineSeparatorCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyLineSeparatorCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/EmptyLineSeparatorCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,12 +19,16 @@ package com.puppycrawl.tools.checkstyle.checks.whitespace; -import org.apache.commons.lang3.ArrayUtils; +import java.util.ArrayList; +import java.util.List; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; +import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; /** * Checks for empty line separators after header, package, all import declarations, @@ -143,10 +147,50 @@ * </module> * * + *

    + * An example how to disallow multiple empty line inside methods, constructors, etc.: + *

    + *
    + * <module name="EmptyLineSeparator">
    + *    <property name="allowMultipleEmptyLinesInsideClassMembers" value="false"/>
    + * </module>
    + * 
    + * + *

    The check is valid only for statements that have body: + * {@link TokenTypes#CLASS_DEF}, + * {@link TokenTypes#INTERFACE_DEF}, + * {@link TokenTypes#ENUM_DEF}, + * {@link TokenTypes#STATIC_INIT}, + * {@link TokenTypes#INSTANCE_INIT}, + * {@link TokenTypes#METHOD_DEF}, + * {@link TokenTypes#CTOR_DEF} + *

    + *

    + * Example of declarations with multiple empty lines inside method: + *

    + * + *
    + * ///////////////////////////////////////////////////
    + * //HEADER
    + * ///////////////////////////////////////////////////
    + *
    + * package com.puppycrawl.tools.checkstyle.whitespace;
    + *
    + * class Foo
    + * {
    + *
    + *     public void foo() {
    + *
    + *
    + *          System.out.println(1); // violation since method has 2 empty lines subsequently
    + *     }
    + * }
    + * 
    * @author maxvetrenko * @author Aleksey Nesterenko */ -public class EmptyLineSeparatorCheck extends Check { +@StatelessCheck +public class EmptyLineSeparatorCheck extends AbstractCheck { /** * A key is pointing to the warning message empty.line.separator in "messages.properties" @@ -168,12 +212,22 @@ public static final String MSG_MULTIPLE_LINES_AFTER = "empty.line.separator.multiple.lines.after"; + /** + * A key is pointing to the warning message empty.line.separator.multiple.lines.inside + * in "messages.properties" file. + */ + public static final String MSG_MULTIPLE_LINES_INSIDE = + "empty.line.separator.multiple.lines.inside"; + /** Allows no empty line between fields. */ private boolean allowNoEmptyLineBetweenFields; /** Allows multiple empty lines between class members. */ private boolean allowMultipleEmptyLines = true; + /** Allows multiple empty lines inside class members. */ + private boolean allowMultipleEmptyLinesInsideClassMembers = true; + /** * Allow no empty line between fields. * @param allow @@ -191,6 +245,19 @@ allowMultipleEmptyLines = allow; } + /** + * Allow multiple empty lines inside class members. + * @param allow User's value. + */ + public void setAllowMultipleEmptyLinesInsideClassMembers(boolean allow) { + allowMultipleEmptyLinesInsideClassMembers = allow; + } + + @Override + public boolean isCommentNodesRequired() { + return true; + } + @Override public int[] getDefaultTokens() { return getAcceptableTokens(); @@ -214,7 +281,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -222,8 +289,14 @@ if (hasMultipleLinesBefore(ast)) { log(ast.getLineNo(), MSG_MULTIPLE_LINES, ast.getText()); } + if (!allowMultipleEmptyLinesInsideClassMembers) { + processMultipleLinesInside(ast); + } - final DetailAST nextToken = ast.getNextSibling(); + DetailAST nextToken = ast.getNextSibling(); + while (nextToken != null && isComment(nextToken)) { + nextToken = nextToken.getNextSibling(); + } if (nextToken != null) { final int astType = ast.getType(); switch (astType) { @@ -251,6 +324,79 @@ } /** + * Log violation in case there are multiple empty lines inside constructor, + * initialization block or method. + * @param ast the ast to check. + */ + private void processMultipleLinesInside(DetailAST ast) { + final int astType = ast.getType(); + if (astType != TokenTypes.CLASS_DEF && isClassMemberBlock(astType)) { + final List emptyLines = getEmptyLines(ast); + final List emptyLinesToLog = getEmptyLinesToLog(emptyLines); + + for (Integer lineNo : emptyLinesToLog) { + // Checkstyle counts line numbers from 0 but IDE from 1 + log(lineNo + 1, MSG_MULTIPLE_LINES_INSIDE); + } + } + } + + /** + * Whether the AST is a class member block. + * @param astType the AST to check. + * @return true if the AST is a class member block. + */ + private static boolean isClassMemberBlock(int astType) { + return astType == TokenTypes.STATIC_INIT + || astType == TokenTypes.INSTANCE_INIT + || astType == TokenTypes.METHOD_DEF + || astType == TokenTypes.CTOR_DEF; + } + + /** + * Get list of empty lines. + * @param ast the ast to check. + * @return list of line numbers for empty lines. + */ + private List getEmptyLines(DetailAST ast) { + final DetailAST lastToken = ast.getLastChild().getLastChild(); + int lastTokenLineNo = 0; + if (lastToken != null) { + // -1 as count starts from 0 + // -2 as last token line cannot be empty, because it is a RCURLY + lastTokenLineNo = lastToken.getLineNo() - 2; + } + final List emptyLines = new ArrayList<>(); + final FileContents fileContents = getFileContents(); + + for (int lineNo = ast.getLineNo(); lineNo <= lastTokenLineNo; lineNo++) { + if (fileContents.lineIsBlank(lineNo)) { + emptyLines.add(lineNo); + } + } + return emptyLines; + } + + /** + * Get list of empty lines to log. + * @param emptyLines list of empty lines. + * @return list of empty lines to log. + */ + private static List getEmptyLinesToLog(List emptyLines) { + final List emptyLinesToLog = new ArrayList<>(); + if (emptyLines.size() >= 2) { + int previousEmptyLineNo = emptyLines.get(0); + for (int emptyLineNo : emptyLines) { + if (previousEmptyLineNo + 1 == emptyLineNo) { + emptyLinesToLog.add(emptyLineNo); + } + previousEmptyLineNo = emptyLineNo; + } + } + return emptyLinesToLog; + } + + /** * Whether the token has not allowed multiple empty lines before. * @param ast the ast to check. * @return true if the token has not allowed multiple empty lines before. @@ -272,7 +418,14 @@ */ private void processPackage(DetailAST ast, DetailAST nextToken) { if (ast.getLineNo() > 1 && !hasEmptyLineBefore(ast)) { - log(ast.getLineNo(), MSG_SHOULD_BE_SEPARATED, ast.getText()); + if (getFileContents().getFileName().endsWith("package-info.java")) { + if (ast.getFirstChild().getChildCount() == 0 && !isPrecededByJavadoc(ast)) { + log(ast.getLineNo(), MSG_SHOULD_BE_SEPARATED, ast.getText()); + } + } + else { + log(ast.getLineNo(), MSG_SHOULD_BE_SEPARATED, ast.getText()); + } } if (!hasEmptyLineAfter(ast)) { log(nextToken.getLineNo(), MSG_SHOULD_BE_SEPARATED, nextToken.getText()); @@ -339,7 +492,7 @@ final int number = 3; if (lineNo >= number) { final String prePreviousLine = getLines()[lineNo - number]; - result = prePreviousLine.trim().isEmpty(); + result = CommonUtils.isBlank(prePreviousLine); } return result; } @@ -354,8 +507,12 @@ if (lastToken == null) { lastToken = token.getLastChild(); } + DetailAST nextToken = token.getNextSibling(); + if (isComment(nextToken)) { + nextToken = nextToken.getNextSibling(); + } // Start of the next token - final int nextBegin = token.getNextSibling().getLineNo(); + final int nextBegin = nextToken.getLineNo(); // End of current token. final int currentEnd = lastToken.getLineNo(); return hasEmptyLine(currentEnd + 1, nextBegin - 1); @@ -366,7 +523,7 @@ * started from 1 for parameter values * @param startLine number of the first line in the range * @param endLine number of the second line in the range - * @return true if found any blank line within the range, false + * @return {@code true} if found any blank line within the range, {@code false} * otherwise */ private boolean hasEmptyLine(int startLine, int endLine) { @@ -391,13 +548,39 @@ * @return true, if token have empty line before. */ private boolean hasEmptyLineBefore(DetailAST token) { + boolean result = false; final int lineNo = token.getLineNo(); - if (lineNo == 1) { - return false; + if (lineNo != 1) { + // [lineNo - 2] is the number of the previous line as the numbering starts from zero. + final String lineBefore = getLines()[lineNo - 2]; + result = CommonUtils.isBlank(lineBefore); + } + return result; + } + + /** + * Check if token is preceded by javadoc comment. + * @param token token for check. + * @return true, if token is preceded by javadoc comment. + */ + private static boolean isPrecededByJavadoc(DetailAST token) { + boolean result = false; + final DetailAST previous = token.getPreviousSibling(); + if (previous.getType() == TokenTypes.BLOCK_COMMENT_BEGIN + && JavadocUtils.isJavadocComment(previous.getFirstChild().getText())) { + result = true; } - // [lineNo - 2] is the number of the previous line because the numbering starts from zero. - final String lineBefore = getLines()[lineNo - 2]; - return lineBefore.trim().isEmpty(); + return result; + } + + /** + * Check if token is a comment. + * @param ast ast node + * @return true, if given ast is comment. + */ + private static boolean isComment(DetailAST ast) { + return ast.getType() == TokenTypes.SINGLE_LINE_COMMENT + || ast.getType() == TokenTypes.BLOCK_COMMENT_BEGIN; } /** @@ -409,4 +592,5 @@ final int parentType = variableDef.getParent().getParent().getType(); return parentType == TokenTypes.CLASS_DEF; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/FileTabCharacterCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/FileTabCharacterCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/FileTabCharacterCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/FileTabCharacterCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,14 +20,16 @@ package com.puppycrawl.tools.checkstyle.checks.whitespace; import java.io.File; -import java.util.List; +import com.puppycrawl.tools.checkstyle.StatelessCheck; import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; +import com.puppycrawl.tools.checkstyle.api.FileText; /** * Checks to see if a file contains a tab character. * @author oliverb */ +@StatelessCheck public class FileTabCharacterCheck extends AbstractFileSetCheck { /** @@ -46,9 +48,10 @@ private boolean eachLine; @Override - protected void processFiltered(File file, List lines) { + protected void processFiltered(File file, FileText fileText) { int lineNum = 0; - for (final String line : lines) { + for (int index = 0; index < fileText.size(); index++) { + final String line = fileText.get(index); lineNum++; final int tabPosition = line.indexOf('\t'); if (tabPosition != -1) { @@ -70,4 +73,5 @@ public void setEachLine(boolean eachLine) { this.eachLine = eachLine; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/GenericWhitespaceCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/GenericWhitespaceCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/GenericWhitespaceCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/GenericWhitespaceCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,7 +19,8 @@ package com.puppycrawl.tools.checkstyle.checks.whitespace; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.FileStatefulCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -67,7 +68,8 @@ * * @author Oliver Burn */ -public class GenericWhitespaceCheck extends Check { +@FileStatefulCheck +public class GenericWhitespaceCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -104,17 +106,17 @@ @Override public int[] getDefaultTokens() { - return getAcceptableTokens(); + return getRequiredTokens(); } @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.GENERIC_START, TokenTypes.GENERIC_END}; + return getRequiredTokens(); } @Override public int[] getRequiredTokens() { - return getAcceptableTokens(); + return new int[] {TokenTypes.GENERIC_START, TokenTypes.GENERIC_END}; } @Override @@ -150,12 +152,11 @@ final int after = ast.getColumnNo() + 1; if (before >= 0 && Character.isWhitespace(line.charAt(before)) - && !CommonUtils.hasWhitespaceBefore(before, line)) { + && !containsWhitespaceBefore(before, line)) { log(ast.getLineNo(), before, MSG_WS_PRECEDED, CLOSE_ANGLE_BRACKET); } if (after < line.length()) { - // Check if the last Generic, in which case must be a whitespace // or a '(),[.'. if (depth == 1) { @@ -183,7 +184,7 @@ // should be whitespace if followed by & -+ // final int indexOfAmp = line.indexOf('&', after); - if (indexOfAmp >= 0 + if (indexOfAmp >= 1 && containsWhitespaceBetween(after, indexOfAmp, line)) { if (indexOfAmp - after == 0) { log(ast.getLineNo(), after, MSG_WS_NOT_PRECEDED, "&"); @@ -271,7 +272,7 @@ } // Whitespace not required else if (Character.isWhitespace(line.charAt(before)) - && !CommonUtils.hasWhitespaceBefore(before, line)) { + && !containsWhitespaceBefore(before, line)) { log(ast.getLineNo(), before, MSG_WS_PRECEDED, OPEN_ANGLE_BRACKET); } } @@ -291,14 +292,27 @@ * @param line the line to check * @return whether there are only whitespaces (or nothing) */ - private static boolean containsWhitespaceBetween( - int fromIndex, int toIndex, String line) { + private static boolean containsWhitespaceBetween(int fromIndex, int toIndex, String line) { + boolean result = true; for (int i = fromIndex; i < toIndex; i++) { if (!Character.isWhitespace(line.charAt(i))) { - return false; + result = false; + break; } } - return true; + return result; + } + + /** + * Returns whether the specified string contains only whitespace up to specified index. + * + * @param before the index to start the search from. Inclusive + * @param line the index to finish the search. Exclusive + * @return {@code true} if there are only whitespaces, + * false if there is nothing before or some other characters + */ + private static boolean containsWhitespaceBefore(int before, String line) { + return before != 0 && CommonUtils.hasWhitespaceBefore(before, line); } /** @@ -313,4 +327,5 @@ || charAfter == ';' || Character.isWhitespace(charAfter); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/MethodParamPadCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/MethodParamPadCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/MethodParamPadCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/MethodParamPadCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,10 +21,8 @@ import java.util.Locale; -import org.apache.commons.beanutils.ConversionException; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -67,8 +65,9 @@ * @author Rick Giles */ +@StatelessCheck public class MethodParamPadCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -116,7 +115,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -128,26 +127,25 @@ else { parenAST = ast.findFirstToken(TokenTypes.LPAREN); // array construction => parenAST == null - if (parenAST == null) { - return; - } } - final String line = getLines()[parenAST.getLineNo() - 1]; - if (CommonUtils.hasWhitespaceBefore(parenAST.getColumnNo(), line)) { - if (!allowLineBreaks) { - log(parenAST, MSG_LINE_PREVIOUS, parenAST.getText()); - } - } - else { - final int before = parenAST.getColumnNo() - 1; - if (option == PadOption.NOSPACE - && Character.isWhitespace(line.charAt(before))) { - log(parenAST, MSG_WS_PRECEDED, parenAST.getText()); + if (parenAST != null) { + final String line = getLines()[parenAST.getLineNo() - 1]; + if (CommonUtils.hasWhitespaceBefore(parenAST.getColumnNo(), line)) { + if (!allowLineBreaks) { + log(parenAST, MSG_LINE_PREVIOUS, parenAST.getText()); + } } - else if (option == PadOption.SPACE - && !Character.isWhitespace(line.charAt(before))) { - log(parenAST, MSG_WS_NOT_PRECEDED, parenAST.getText()); + else { + final int before = parenAST.getColumnNo() - 1; + if (option == PadOption.NOSPACE + && Character.isWhitespace(line.charAt(before))) { + log(parenAST, MSG_WS_PRECEDED, parenAST.getText()); + } + else if (option == PadOption.SPACE + && !Character.isWhitespace(line.charAt(before))) { + log(parenAST, MSG_WS_NOT_PRECEDED, parenAST.getText()); + } } } } @@ -164,14 +162,15 @@ /** * Set the option to enforce. * @param optionStr string to decode option from - * @throws ConversionException if unable to decode + * @throws IllegalArgumentException if unable to decode */ public void setOption(String optionStr) { try { option = PadOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + optionStr, iae); + throw new IllegalArgumentException("unable to parse " + optionStr, iae); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoLineWrapCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoLineWrapCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoLineWrapCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoLineWrapCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,11 +19,11 @@ package com.puppycrawl.tools.checkstyle.checks.whitespace; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    Checks that chosen statements are not line-wrapped. @@ -36,7 +36,7 @@ * tools.checkstyle.checks; * * import com.puppycrawl.tools. - * checkstyle.api.Check; + * checkstyle.api.AbstractCheck; * } * *

    @@ -58,12 +58,13 @@ * * *

    Examples of not line-wrapped statements (good case): - *

    {@code import com.puppycrawl.tools.checkstyle.api.Check;
    + * 
    {@code import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
      * }
    * * @author maxvetrenko */ -public class NoLineWrapCheck extends Check { +@StatelessCheck +public class NoLineWrapCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -73,13 +74,14 @@ @Override public int[] getDefaultTokens() { - return new int[] {TokenTypes.PACKAGE_DEF, TokenTypes.IMPORT}; + return new int[] {TokenTypes.PACKAGE_DEF, TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT}; } @Override public int[] getAcceptableTokens() { return new int[] { TokenTypes.IMPORT, + TokenTypes.STATIC_IMPORT, TokenTypes.PACKAGE_DEF, TokenTypes.CLASS_DEF, TokenTypes.METHOD_DEF, @@ -91,7 +93,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -100,4 +102,5 @@ log(ast.getLineNo(), MSG_KEY, ast.getText()); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceAfterCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceAfterCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceAfterCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceAfterCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,9 +19,11 @@ package com.puppycrawl.tools.checkstyle.checks.whitespace; -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    @@ -33,6 +35,7 @@ *

    *

    By default the check will check the following operators: * {@link TokenTypes#ARRAY_INIT ARRAY_INIT}, + * {@link TokenTypes#AT AT}, * {@link TokenTypes#BNOT BNOT}, * {@link TokenTypes#DEC DEC}, * {@link TokenTypes#DOT DOT}, @@ -50,6 +53,9 @@ * {@link TokenTypes#INDEX_OP INDEX_OP} * specially from other tokens. Actually it is checked that there is * no whitespace before this tokens, not after them. + * Spaces after the {@link TokenTypes#ANNOTATIONS ANNOTATIONS} + * before {@link TokenTypes#ARRAY_DECLARATOR ARRAY_DECLARATOR} + * and {@link TokenTypes#INDEX_OP INDEX_OP} will be ignored. *

    *

    * An example of how to configure the check is: @@ -66,12 +72,19 @@ * <property name="allowLineBreaks" value="false"/> * </module> *

    + *

    + * If the annotation is between the type and the array, the check will skip validation for spaces: + *

    + *
    + * public void foo(final char @NotNull [] param) {} // No violation
    + * 
    * @author Rick Giles * @author lkuehne * @author Aleksey Nesterenko * @author attatrol */ -public class NoWhitespaceAfterCheck extends Check { +@StatelessCheck +public class NoWhitespaceAfterCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -86,6 +99,7 @@ public int[] getDefaultTokens() { return new int[] { TokenTypes.ARRAY_INIT, + TokenTypes.AT, TokenTypes.INC, TokenTypes.DEC, TokenTypes.UNARY_MINUS, @@ -102,6 +116,7 @@ public int[] getAcceptableTokens() { return new int[] { TokenTypes.ARRAY_INIT, + TokenTypes.AT, TokenTypes.INC, TokenTypes.DEC, TokenTypes.UNARY_MINUS, @@ -112,9 +127,16 @@ TokenTypes.TYPECAST, TokenTypes.ARRAY_DECLARATOR, TokenTypes.INDEX_OP, + TokenTypes.LITERAL_SYNCHRONIZED, + TokenTypes.METHOD_REF, }; } + @Override + public int[] getRequiredTokens() { + return CommonUtils.EMPTY_INT_ARRAY; + } + /** * Control whether whitespace is flagged at linebreaks. * @param allowLineBreaks whether whitespace should be @@ -128,12 +150,15 @@ public void visitToken(DetailAST ast) { final DetailAST whitespaceFollowedAst = getWhitespaceFollowedNode(ast); - final int whitespaceColumnNo = getPositionAfter(whitespaceFollowedAst); - final int whitespaceLineNo = whitespaceFollowedAst.getLineNo(); - - if (hasTrailingWhitespace(ast, whitespaceColumnNo, whitespaceLineNo)) { - log(whitespaceLineNo, whitespaceColumnNo, - MSG_KEY, whitespaceFollowedAst.getText()); + if (whitespaceFollowedAst.getNextSibling() == null + || whitespaceFollowedAst.getNextSibling().getType() != TokenTypes.ANNOTATIONS) { + final int whitespaceColumnNo = getPositionAfter(whitespaceFollowedAst); + final int whitespaceLineNo = whitespaceFollowedAst.getLineNo(); + + if (hasTrailingWhitespace(ast, whitespaceColumnNo, whitespaceLineNo)) { + log(whitespaceLineNo, whitespaceColumnNo, + MSG_KEY, whitespaceFollowedAst.getText()); + } } } @@ -193,7 +218,7 @@ * , line number of a possible whitespace. * @return true if whitespace found. */ - boolean hasTrailingWhitespace(DetailAST ast, + private boolean hasTrailingWhitespace(DetailAST ast, int whitespaceColumnNo, int whitespaceLineNo) { final boolean result; final int astLineNo = ast.getLineNo(); @@ -262,7 +287,7 @@ } break; default: - throw new IllegalStateException("unexpected ast syntax" + parent); + throw new IllegalStateException("unexpected ast syntax " + parent); } } return previousElement; @@ -286,8 +311,16 @@ else { final DetailAST ident = getIdentLastToken(ast); if (ident == null) { + final DetailAST rparen = ast.findFirstToken(TokenTypes.RPAREN); + // construction like new int[]{1}[0] + if (rparen == null) { + final DetailAST lastChild = firstChild.getLastChild(); + result = lastChild.findFirstToken(TokenTypes.RCURLY); + } // construction like ((byte[]) pixels)[0] - result = ast.findFirstToken(TokenTypes.RPAREN); + else { + result = rparen; + } } else { result = ident; @@ -357,8 +390,12 @@ } //ident and lastTypeNode lay on one line else { - if (ident.getColumnNo() > ast.getColumnNo() - || lastTypeNode.getColumnNo() > ident.getColumnNo()) { + final int instanceOfSize = 13; + // +2 because ast has `[]` after the ident + if (ident.getColumnNo() >= ast.getColumnNo() + 2 + // +13 because ident (at most 1 character) is followed by + // ' instanceof ' (12 characters) + || lastTypeNode.getColumnNo() >= ident.getColumnNo() + instanceOfSize) { previousElement = lastTypeNode; } else { diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/NoWhitespaceBeforeCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,11 +19,11 @@ package com.puppycrawl.tools.checkstyle.checks.whitespace; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    @@ -31,12 +31,15 @@ * More specifically, it checks that it is not preceded with whitespace, * or (if line breaks are allowed) all characters on the line before are * whitespace. To allow line breaks before a token, set property - * allowLineBreaks to true. + * allowLineBreaks to true. No check occurs before semi-colons in empty + * for loop initializers or conditions. *

    *

    By default the check will check the following operators: + * {@link TokenTypes#COMMA COMMA}, * {@link TokenTypes#SEMI SEMI}, * {@link TokenTypes#POST_DEC POST_DEC}, - * {@link TokenTypes#POST_INC POST_INC}. + * {@link TokenTypes#POST_INC POST_INC}, + * {@link TokenTypes#ELLIPSIS ELLIPSIS}. * {@link TokenTypes#DOT DOT} is also an acceptable token in a configuration * of this check. *

    @@ -59,8 +62,9 @@ * @author Rick Giles * @author lkuehne */ +@StatelessCheck public class NoWhitespaceBeforeCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -78,6 +82,7 @@ TokenTypes.SEMI, TokenTypes.POST_INC, TokenTypes.POST_DEC, + TokenTypes.ELLIPSIS, }; } @@ -91,12 +96,14 @@ TokenTypes.DOT, TokenTypes.GENERIC_START, TokenTypes.GENERIC_END, + TokenTypes.ELLIPSIS, + TokenTypes.METHOD_REF, }; } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -104,14 +111,14 @@ final String line = getLine(ast.getLineNo() - 1); final int before = ast.getColumnNo() - 1; - if ((before < 0 || Character.isWhitespace(line.charAt(before))) - && !isInEmptyForInitializer(ast)) { - + if ((before == -1 || Character.isWhitespace(line.charAt(before))) + && !isInEmptyForInitializerOrCondition(ast)) { boolean flag = !allowLineBreaks; // verify all characters before '.' are whitespace - for (int i = 0; !flag && i < before; i++) { + for (int i = 0; !flag && i <= before - 1; i++) { if (!Character.isWhitespace(line.charAt(i))) { flag = true; + break; } } if (flag) { @@ -121,16 +128,17 @@ } /** - * Checks that semicolon is in empty for initializer. + * Checks that semicolon is in empty for initializer or condition. * @param semicolonAst DetailAST of semicolon. - * @return true if semicolon is in empty for initializer. + * @return true if semicolon is in empty for initializer or condition. */ - private static boolean isInEmptyForInitializer(DetailAST semicolonAst) { + private static boolean isInEmptyForInitializerOrCondition(DetailAST semicolonAst) { boolean result = false; if (semicolonAst.getType() == TokenTypes.SEMI) { final DetailAST sibling = semicolonAst.getPreviousSibling(); if (sibling != null - && sibling.getType() == TokenTypes.FOR_INIT + && (sibling.getType() == TokenTypes.FOR_INIT + || sibling.getType() == TokenTypes.FOR_CONDITION) && sibling.getChildCount() == 0) { result = true; } @@ -146,4 +154,5 @@ public void setAllowLineBreaks(boolean allowLineBreaks) { this.allowLineBreaks = allowLineBreaks; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/OperatorWrapCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/OperatorWrapCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/OperatorWrapCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/OperatorWrapCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,11 +21,8 @@ import java.util.Locale; -import org.apache.commons.beanutils.ConversionException; -import org.apache.commons.lang3.ArrayUtils; -import org.apache.commons.lang3.StringUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -72,6 +69,7 @@ * {@link TokenTypes#SL_ASSIGN SL_ASSIGN}, * {@link TokenTypes#SR_ASSIGN SR_ASSIGN}, * {@link TokenTypes#STAR_ASSIGN STAR_ASSIGN}. + * {@link TokenTypes#METHOD_REF METHOD_REF}. *

    *

    * An example of how to configure the check is: @@ -85,15 +83,17 @@ *

      * <module name="OperatorWrap">
      *     <property name="tokens"
    - *               value="ASSIGN,DIV_ASSIGN,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,MOD_ASSIGN,SR_ASSIGN,BSR_ASSIGN,SL_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,BAND_ASSIGN"/>
    + *               value="ASSIGN,DIV_ASSIGN,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,MOD_ASSIGN
    + *               ,SR_ASSIGN,BSR_ASSIGN,SL_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,BAND_ASSIGN"/>
      *     <property name="option" value="eol"/>
    -  * </module>
    + * </module>
      * 
    * * @author Rick Giles */ +@StatelessCheck public class OperatorWrapCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -113,14 +113,14 @@ /** * Set the option to enforce. * @param optionStr string to decode option from - * @throws ConversionException if unable to decode + * @throws IllegalArgumentException if unable to decode */ public void setOption(String optionStr) { try { option = WrapOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + optionStr, iae); + throw new IllegalArgumentException("unable to parse " + optionStr, iae); } } @@ -191,42 +191,40 @@ TokenTypes.BXOR_ASSIGN, // "^=" TokenTypes.BOR_ASSIGN, // "|=" TokenTypes.BAND_ASSIGN, // "&=" - + TokenTypes.METHOD_REF, // "::" }; } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override public void visitToken(DetailAST ast) { - if (ast.getType() == TokenTypes.COLON) { - final DetailAST parent = ast.getParent(); - if (parent.getType() == TokenTypes.LITERAL_DEFAULT - || parent.getType() == TokenTypes.LITERAL_CASE) { - //we do not want to check colon for cases and defaults - return; + final DetailAST parent = ast.getParent(); + //we do not want to check colon for cases and defaults + if (ast.getType() != TokenTypes.COLON + || parent.getType() != TokenTypes.LITERAL_DEFAULT + && parent.getType() != TokenTypes.LITERAL_CASE) { + final String text = ast.getText(); + final int colNo = ast.getColumnNo(); + final int lineNo = ast.getLineNo(); + final String currentLine = getLine(lineNo - 1); + + // Check if rest of line is whitespace, and not just the operator + // by itself. This last bit is to handle the operator on a line by + // itself. + if (option == WrapOption.NL + && !text.equals(currentLine.trim()) + && CommonUtils.isBlank(currentLine.substring(colNo + text.length()))) { + log(lineNo, colNo, MSG_LINE_NEW, text); + } + else if (option == WrapOption.EOL + && CommonUtils.hasWhitespaceBefore(colNo - 1, currentLine)) { + log(lineNo, colNo, MSG_LINE_PREVIOUS, text); } - } - - final String text = ast.getText(); - final int colNo = ast.getColumnNo(); - final int lineNo = ast.getLineNo(); - final String currentLine = getLine(lineNo - 1); - - // Check if rest of line is whitespace, and not just the operator - // by itself. This last bit is to handle the operator on a line by - // itself. - if (option == WrapOption.NL - && !text.equals(currentLine.trim()) - && StringUtils.isBlank(currentLine.substring(colNo + text.length()))) { - log(lineNo, colNo, MSG_LINE_NEW, text); - } - else if (option == WrapOption.EOL - && CommonUtils.hasWhitespaceBefore(colNo - 1, currentLine)) { - log(lineNo, colNo, MSG_LINE_PREVIOUS, text); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/PadOption.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/PadOption.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/PadOption.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/PadOption.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -27,6 +27,7 @@ * @see ParenPadCheck */ public enum PadOption { + /** * Represents no spacing following a left parenthesis * or preceding a right one. @@ -38,4 +39,5 @@ * and preceding a right one. */ SPACE + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/ParenPadCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/ParenPadCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/ParenPadCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/ParenPadCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,17 +21,17 @@ import java.util.Arrays; -import org.apache.commons.lang3.ArrayUtils; - import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    Checks the padding of parentheses; that is whether a space is required * after a left parenthesis and before a right parenthesis, or such spaces are - * forbidden, with the exception that it does - * not check for padding of the right parenthesis at an empty for iterator and - * empty for initializer. + * forbidden. No check occurs at the right parenthesis after an empty for + * iterator, at the left parenthesis before an empty for initialization, or at + * the right parenthesis of a try-with-resources resource specification where + * the last resource variable has a trailing semi-colon. * Use Check {@link EmptyForIteratorPadCheck EmptyForIteratorPad} to validate * empty for iterators and {@link EmptyForInitializerPadCheck EmptyForInitializerPad} * to validate empty for initializers. Typecasts are also not checked, as there is @@ -47,6 +47,7 @@ * {@link TokenTypes#ANNOTATION_FIELD_DEF ANNOTATION_FIELD_DEF}, * {@link TokenTypes#CTOR_DEF CTOR_DEF}, * {@link TokenTypes#CTOR_CALL CTOR_CALL}, + * {@link TokenTypes#DOT DOT}, * {@link TokenTypes#ENUM_CONSTANT_DEF ENUM_CONSTANT_DEF}, * {@link TokenTypes#EXPR EXPR}, * {@link TokenTypes#LITERAL_CATCH LITERAL_CATCH}, @@ -62,6 +63,7 @@ * {@link TokenTypes#RESOURCE_SPECIFICATION RESOURCE_SPECIFICATION}, * {@link TokenTypes#SUPER_CTOR_CALL SUPER_CTOR_CALL}, * {@link TokenTypes#QUESTION QUESTION}, + * {@link TokenTypes#LAMBDA LAMBDA}, *

    *

    * An example of how to configure the check is: @@ -110,7 +112,7 @@ @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -119,8 +121,8 @@ case TokenTypes.METHOD_CALL: processLeft(ast); processRight(ast.findFirstToken(TokenTypes.RPAREN)); - processExpression(ast); break; + case TokenTypes.DOT: case TokenTypes.EXPR: case TokenTypes.QUESTION: processExpression(ast); @@ -132,7 +134,11 @@ case TokenTypes.ENUM_CONSTANT_DEF: case TokenTypes.LITERAL_NEW: case TokenTypes.LITERAL_SYNCHRONIZED: - visitNewEnumConstDefAnnotationSync(ast); + case TokenTypes.LAMBDA: + visitTokenWithOptionalParentheses(ast); + break; + case TokenTypes.RESOURCE_SPECIFICATION: + visitResourceSpecification(ast); break; default: processLeft(ast.findFirstToken(TokenTypes.LPAREN)); @@ -141,11 +147,13 @@ } /** - * Checks parens in {@link TokenTypes#ENUM_CONSTANT_DEF}, {@link TokenTypes#ANNOTATION} - * {@link TokenTypes#LITERAL_SYNCHRONIZED} and {@link TokenTypes#LITERAL_NEW}. + * Checks parens in token which may not contain parens, e.g. + * {@link TokenTypes#ENUM_CONSTANT_DEF}, {@link TokenTypes#ANNOTATION} + * {@link TokenTypes#LITERAL_SYNCHRONIZED}, {@link TokenTypes#LITERAL_NEW} and + * {@link TokenTypes#LAMBDA}. * @param ast the token to check. */ - private void visitNewEnumConstDefAnnotationSync(DetailAST ast) { + private void visitTokenWithOptionalParentheses(DetailAST ast) { final DetailAST parenAst = ast.findFirstToken(TokenTypes.LPAREN); if (parenAst != null) { processLeft(parenAst); @@ -154,6 +162,27 @@ } /** + * Checks parens in {@link TokenTypes#RESOURCE_SPECIFICATION}. + * @param ast the token to check. + */ + private void visitResourceSpecification(DetailAST ast) { + processLeft(ast.findFirstToken(TokenTypes.LPAREN)); + final DetailAST rparen = ast.findFirstToken(TokenTypes.RPAREN); + if (!hasPrecedingSemiColon(rparen)) { + processRight(rparen); + } + } + + /** + * Checks that a token is preceded by a semi-colon. + * @param ast the token to check + * @return whether a token is preceded by a semi-colon + */ + private static boolean hasPrecedingSemiColon(DetailAST ast) { + return ast.getPreviousSibling().getType() == TokenTypes.SEMI; + } + + /** * Checks parens in {@link TokenTypes#LITERAL_FOR}. * @param ast the token to check. */ @@ -179,7 +208,6 @@ while (childAst != null) { if (childAst.getType() == TokenTypes.LPAREN) { processLeft(childAst); - processExpression(childAst); } else if (childAst.getType() == TokenTypes.RPAREN && !isInTypecast(childAst)) { processRight(childAst); @@ -208,6 +236,7 @@ } /** + * Returns array of acceptable tokens. * @return acceptableTokens. */ private static int[] makeAcceptableTokens() { @@ -215,6 +244,7 @@ TokenTypes.ANNOTATION_FIELD_DEF, TokenTypes.CTOR_CALL, TokenTypes.CTOR_DEF, + TokenTypes.DOT, TokenTypes.ENUM_CONSTANT_DEF, TokenTypes.EXPR, TokenTypes.LITERAL_CATCH, @@ -230,6 +260,7 @@ TokenTypes.QUESTION, TokenTypes.RESOURCE_SPECIFICATION, TokenTypes.SUPER_CTOR_CALL, + TokenTypes.LAMBDA, }; } @@ -284,4 +315,5 @@ } return result; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SeparatorWrapCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,12 +21,11 @@ import java.util.Locale; -import org.apache.commons.beanutils.ConversionException; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    @@ -82,8 +81,9 @@ * * @author maxvetrenko */ +@StatelessCheck public class SeparatorWrapCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -103,14 +103,14 @@ /** * Set the option to enforce. * @param optionStr string to decode option from - * @throws ConversionException if unable to decode + * @throws IllegalArgumentException if unable to decode */ public void setOption(String optionStr) { try { option = WrapOption.valueOf(optionStr.trim().toUpperCase(Locale.ENGLISH)); } catch (IllegalArgumentException iae) { - throw new ConversionException("unable to parse " + optionStr, iae); + throw new IllegalArgumentException("unable to parse " + optionStr, iae); } } @@ -134,12 +134,13 @@ TokenTypes.RPAREN, TokenTypes.ARRAY_DECLARATOR, TokenTypes.RBRACK, + TokenTypes.METHOD_REF, }; } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override @@ -162,4 +163,5 @@ log(lineNo, colNo, MSG_LINE_NEW, text); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SingleSpaceSeparatorCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SingleSpaceSeparatorCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SingleSpaceSeparatorCheck.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/SingleSpaceSeparatorCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,264 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.checks.whitespace; + +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; + +/** + *

    + * Checks that non-whitespace characters are separated by no more than one + * whitespace. Separating characters by tabs or multiple spaces will be + * reported. Currently the check doesn't permit horizontal alignment. To inspect + * whitespaces before and after comments, set the property + * validateComments to true. + *

    + * + *

    + * Setting validateComments to false will ignore cases like: + *

    + * + *
    + * int i;  // Multiple whitespaces before comment tokens will be ignored.
    + * private void foo(int  /* whitespaces before and after block-comments will be
    + * ignored */  i) {
    + * 
    + * + *

    + * Sometimes, users like to space similar items on different lines to the same + * column position for easier reading. This feature isn't supported by this + * check, so both braces in the following case will be reported as violations. + *

    + * + *
    + * public long toNanos(long d)  { return d;             }  // 2 violations
    + * public long toMicros(long d) { return d / (C1 / C0); }
    + * 
    + * + *

    + * Check have following options: + *

    + * + *
      + *
    • validateComments - Boolean when set to {@code true}, whitespaces + * surrounding comments will be ignored. Default value is {@code false}.
    • + *
    + * + *

    + * To configure the check: + *

    + * + *
    + * <module name="SingleSpaceSeparator"/>
    + * 
    + * + *

    + * To configure the check so that it validates comments: + *

    + * + *
    + * <module name="SingleSpaceSeparator">
    + * <property name="validateComments" value="true"/>
    + * </module>
    + * 
    + * + * @author Robert Whitebit + * @author Richard Veach + */ +@StatelessCheck +public class SingleSpaceSeparatorCheck extends AbstractCheck { + + /** + * A key is pointing to the warning message text in "messages.properties" + * file. + */ + public static final String MSG_KEY = "single.space.separator"; + + /** Indicates if whitespaces surrounding comments will be ignored. */ + private boolean validateComments; + + /** + * Sets whether or not to validate surrounding whitespaces at comments. + * + * @param validateComments {@code true} to validate surrounding whitespaces at comments. + */ + public void setValidateComments(boolean validateComments) { + this.validateComments = validateComments; + } + + @Override + public int[] getDefaultTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getAcceptableTokens() { + return getRequiredTokens(); + } + + @Override + public int[] getRequiredTokens() { + return CommonUtils.EMPTY_INT_ARRAY; + } + + // -@cs[SimpleAccessorNameNotation] Overrides method from base class. + // Issue: https://github.com/sevntu-checkstyle/sevntu.checkstyle/issues/166 + @Override + public boolean isCommentNodesRequired() { + return validateComments; + } + + @Override + public void beginTree(DetailAST rootAST) { + visitEachToken(rootAST); + } + + /** + * Examines every sibling and child of {@code node} for violations. + * + * @param node The node to start examining. + */ + private void visitEachToken(DetailAST node) { + DetailAST sibling = node; + + while (sibling != null) { + final int columnNo = sibling.getColumnNo() - 1; + + // in such expression: "j =123", placed at the start of the string index of the second + // space character will be: 2 = 0(j) + 1(whitespace) + 1(whitespace). It is a minimal + // possible index for the second whitespace between non-whitespace characters. + final int minSecondWhitespaceColumnNo = 2; + + if (columnNo >= minSecondWhitespaceColumnNo + && !isTextSeparatedCorrectlyFromPrevious(getLine(sibling.getLineNo() - 1), + columnNo)) { + log(sibling.getLineNo(), columnNo, MSG_KEY); + } + if (sibling.getChildCount() >= 1) { + visitEachToken(sibling.getFirstChild()); + } + + sibling = sibling.getNextSibling(); + } + } + + /** + * Checks if characters in {@code line} at and around {@code columnNo} has + * the correct number of spaces. to return {@code true} the following + * conditions must be met:
    + * - the character at {@code columnNo} is the first in the line.
    + * - the character at {@code columnNo} is not separated by whitespaces from + * the previous non-whitespace character.
    + * - the character at {@code columnNo} is separated by only one whitespace + * from the previous non-whitespace character.
    + * - {@link #validateComments} is disabled and the previous text is the + * end of a block comment. + * + * @param line The line in the file to examine. + * @param columnNo The column position in the {@code line} to examine. + * @return {@code true} if the text at {@code columnNo} is separated + * correctly from the previous token. + */ + private boolean isTextSeparatedCorrectlyFromPrevious(String line, int columnNo) { + return isSingleSpace(line, columnNo) + || !isWhitespace(line, columnNo) + || isFirstInLine(line, columnNo) + || !validateComments && isBlockCommentEnd(line, columnNo); + } + + /** + * Checks if the {@code line} at {@code columnNo} is a single space, and not + * preceded by another space. + * + * @param line The line in the file to examine. + * @param columnNo The column position in the {@code line} to examine. + * @return {@code true} if the character at {@code columnNo} is a space, and + * not preceded by another space. + */ + private static boolean isSingleSpace(String line, int columnNo) { + return !isPrecededByMultipleWhitespaces(line, columnNo) + && isSpace(line, columnNo); + } + + /** + * Checks if the {@code line} at {@code columnNo} is a space. + * + * @param line The line in the file to examine. + * @param columnNo The column position in the {@code line} to examine. + * @return {@code true} if the character at {@code columnNo} is a space. + */ + private static boolean isSpace(String line, int columnNo) { + return line.charAt(columnNo) == ' '; + } + + /** + * Checks if the {@code line} at {@code columnNo} is preceded by at least 2 + * whitespaces. + * + * @param line The line in the file to examine. + * @param columnNo The column position in the {@code line} to examine. + * @return {@code true} if there are at least 2 whitespace characters before + * {@code columnNo}. + */ + private static boolean isPrecededByMultipleWhitespaces(String line, int columnNo) { + return Character.isWhitespace(line.charAt(columnNo)) + && Character.isWhitespace(line.charAt(columnNo - 1)); + } + + /** + * Checks if the {@code line} at {@code columnNo} is a whitespace character. + * + * @param line The line in the file to examine. + * @param columnNo The column position in the {@code line} to examine. + * @return {@code true} if the character at {@code columnNo} is a + * whitespace. + */ + private static boolean isWhitespace(String line, int columnNo) { + return Character.isWhitespace(line.charAt(columnNo)); + } + + /** + * Checks if the {@code line} up to and including {@code columnNo} is all + * non-whitespace text encountered. + * + * @param line The line in the file to examine. + * @param columnNo The column position in the {@code line} to examine. + * @return {@code true} if the column position is the first non-whitespace + * text on the {@code line}. + */ + private static boolean isFirstInLine(String line, int columnNo) { + return CommonUtils.isBlank(line.substring(0, columnNo)); + } + + /** + * Checks if the {@code line} at {@code columnNo} is the end of a comment, + * '*/'. + * + * @param line The line in the file to examine. + * @param columnNo The column position in the {@code line} to examine. + * @return {@code true} if the previous text is a end comment block. + */ + private static boolean isBlockCommentEnd(String line, int columnNo) { + return line.substring(0, columnNo).trim().endsWith("*/"); + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/TypecastParenPadCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/TypecastParenPadCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/TypecastParenPadCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/TypecastParenPadCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -49,6 +49,7 @@ * @author Oliver Burn */ public class TypecastParenPadCheck extends AbstractParenPadCheck { + @Override public int[] getRequiredTokens() { return new int[] {TokenTypes.RPAREN, TokenTypes.TYPECAST}; @@ -61,7 +62,7 @@ @Override public int[] getAcceptableTokens() { - return new int[] {TokenTypes.RPAREN, TokenTypes.TYPECAST}; + return getRequiredTokens(); } @Override @@ -76,4 +77,5 @@ processRight(ast); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAfterCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAfterCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAfterCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAfterCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,11 +19,11 @@ package com.puppycrawl.tools.checkstyle.checks.whitespace; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

    @@ -35,7 +35,13 @@ *

    By default the check will check the following tokens: * {@link TokenTypes#COMMA COMMA}, * {@link TokenTypes#SEMI SEMI}, - * {@link TokenTypes#TYPECAST TYPECAST}. + * {@link TokenTypes#TYPECAST TYPECAST}, + * {@link TokenTypes#LITERAL_IF LITERAL_IF}, + * {@link TokenTypes#LITERAL_ELSE LITERAL_ELSE}, + * {@link TokenTypes#LITERAL_WHILE LITERAL_WHILE}, + * {@link TokenTypes#LITERAL_FOR LITERAL_FOR}, + * {@link TokenTypes#LITERAL_DO LITERAL_DO}, + * {@link TokenTypes#DO_WHILE DO_WHILE}. *

    *

    * An example of how to configure the check is: @@ -54,8 +60,9 @@ * @author Oliver Burn * @author Rick Giles */ +@StatelessCheck public class WhitespaceAfterCheck - extends Check { + extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -80,19 +87,25 @@ TokenTypes.COMMA, TokenTypes.SEMI, TokenTypes.TYPECAST, + TokenTypes.LITERAL_IF, + TokenTypes.LITERAL_ELSE, + TokenTypes.LITERAL_WHILE, + TokenTypes.LITERAL_DO, + TokenTypes.LITERAL_FOR, + TokenTypes.DO_WHILE, }; } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } @Override public void visitToken(DetailAST ast) { - final String line = getLine(ast.getLineNo() - 1); if (ast.getType() == TokenTypes.TYPECAST) { final DetailAST targetAST = ast.findFirstToken(TokenTypes.RPAREN); + final String line = getLine(targetAST.getLineNo() - 1); if (!isFollowedByWhitespace(targetAST, line)) { log(targetAST.getLineNo(), targetAST.getColumnNo() + targetAST.getText().length(), @@ -100,6 +113,7 @@ } } else { + final String line = getLine(ast.getLineNo() - 1); if (!isFollowedByWhitespace(ast, line)) { final Object[] message = {ast.getText()}; log(ast.getLineNo(), @@ -129,4 +143,5 @@ } return followedByWhitespace; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheck.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WhitespaceAroundCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,11 +19,11 @@ package com.puppycrawl.tools.checkstyle.checks.whitespace; -import org.apache.commons.lang3.ArrayUtils; - -import com.puppycrawl.tools.checkstyle.api.Check; +import com.puppycrawl.tools.checkstyle.StatelessCheck; +import com.puppycrawl.tools.checkstyle.api.AbstractCheck; import com.puppycrawl.tools.checkstyle.api.DetailAST; import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * Checks that a token is surrounded by whitespace. @@ -93,7 +93,18 @@ *

      * <module name="WhitespaceAround">
      *     <property name="tokens"
    - *               value="ASSIGN,DIV_ASSIGN,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,MOD_ASSIGN,SR_ASSIGN,BSR_ASSIGN,SL_ASSIGN,BXOR_ASSIGN,BOR_ASSIGN,BAND_ASSIGN"/>
    + *               value="ASSIGN,DIV_ASSIGN,PLUS_ASSIGN,MINUS_ASSIGN,STAR_ASSIGN,
    + *                      MOD_ASSIGN,SR_ASSIGN,BSR_ASSIGN,SL_ASSIGN,BXOR_ASSIGN,
    + *                      BOR_ASSIGN,BAND_ASSIGN"/>
    + * </module>
    + * 
    + * + *

    An example of how to configure the check for whitespace only around + * curly braces is: + *

    + * <module name="WhitespaceAround">
    + *     <property name="tokens"
    + *               value="LCURLY,RCURLY"/>
      * </module>
      * 
    * @@ -115,6 +126,13 @@ * public @interface Beta {} // empty annotation type * } * + *

    This check does not flag as violation double brace initialization like:

    + *
    + *   new Properties() {{
    + *     setProperty("key", "value");
    + *   }};
    + * 
    + * *

    To configure the check to allow empty method blocks use * *

       <property name="allowEmptyMethods" value="true" />
    @@ -146,7 +164,8 @@ * @author maxvetrenko * @author Andrei Selkin */ -public class WhitespaceAroundCheck extends Check { +@StatelessCheck +public class WhitespaceAroundCheck extends AbstractCheck { /** * A key is pointing to the warning message text in "messages.properties" @@ -170,6 +189,8 @@ private boolean allowEmptyLoops; /** Whether or not empty lambda blocks are allowed. */ private boolean allowEmptyLambdas; + /** Whether or not empty catch blocks are allowed. */ + private boolean allowEmptyCatches; /** Whether or not to ignore a colon in a enhanced for loop. */ private boolean ignoreEnhancedForColon = true; @@ -192,6 +213,7 @@ TokenTypes.EQUAL, TokenTypes.GE, TokenTypes.GT, + TokenTypes.LAMBDA, TokenTypes.LAND, TokenTypes.LCURLY, TokenTypes.LE, @@ -233,6 +255,7 @@ public int[] getAcceptableTokens() { return new int[] { TokenTypes.ASSIGN, + TokenTypes.ARRAY_INIT, TokenTypes.BAND, TokenTypes.BAND_ASSIGN, TokenTypes.BOR, @@ -248,6 +271,7 @@ TokenTypes.EQUAL, TokenTypes.GE, TokenTypes.GT, + TokenTypes.LAMBDA, TokenTypes.LAND, TokenTypes.LCURLY, TokenTypes.LE, @@ -285,12 +309,13 @@ TokenTypes.WILDCARD_TYPE, TokenTypes.GENERIC_START, TokenTypes.GENERIC_END, + TokenTypes.ELLIPSIS, }; } @Override public int[] getRequiredTokens() { - return ArrayUtils.EMPTY_INT_ARRAY; + return CommonUtils.EMPTY_INT_ARRAY; } /** @@ -342,53 +367,43 @@ allowEmptyLambdas = allow; } + /** + * Sets whether or not empty catch blocks are allowed. + * @param allow {@code true} to allow empty catch blocks. + */ + public void setAllowEmptyCatches(boolean allow) { + allowEmptyCatches = allow; + } + @Override public void visitToken(DetailAST ast) { final int currentType = ast.getType(); - if (isNotRelevantSituation(ast, currentType)) { - return; - } - - final String line = getLine(ast.getLineNo() - 1); - final int before = ast.getColumnNo() - 1; - final int after = ast.getColumnNo() + ast.getText().length(); - - if (before >= 0 && !Character.isWhitespace(line.charAt(before))) { - log(ast.getLineNo(), ast.getColumnNo(), - MSG_WS_NOT_PRECEDED, ast.getText()); - } - - if (after >= line.length()) { - return; - } - - final char nextChar = line.charAt(after); - if (!Character.isWhitespace(nextChar) - // Check for "return;" - && !(currentType == TokenTypes.LITERAL_RETURN - && ast.getFirstChild().getType() == TokenTypes.SEMI) - && !isAnonymousInnerClassEnd(currentType, nextChar)) { - - log(ast.getLineNo(), ast.getColumnNo() + ast.getText().length(), - MSG_WS_NOT_FOLLOWED, ast.getText()); + if (!isNotRelevantSituation(ast, currentType)) { + final String line = getLine(ast.getLineNo() - 1); + final int before = ast.getColumnNo() - 1; + final int after = ast.getColumnNo() + ast.getText().length(); + + if (before >= 0) { + final char prevChar = line.charAt(before); + if (shouldCheckSeparationFromPreviousToken(ast) + && !Character.isWhitespace(prevChar)) { + log(ast.getLineNo(), ast.getColumnNo(), + MSG_WS_NOT_PRECEDED, ast.getText()); + } + } + + if (after < line.length()) { + final char nextChar = line.charAt(after); + if (shouldCheckSeparationFromNextToken(ast, nextChar) + && !Character.isWhitespace(nextChar)) { + log(ast.getLineNo(), ast.getColumnNo() + ast.getText().length(), + MSG_WS_NOT_FOLLOWED, ast.getText()); + } + } } } /** - * Check for "})" or "};" or "},". Happens with anon-inners - * @param currentType token - * @param nextChar next symbol - * @return true is that is end of anon inner class - */ - private static boolean isAnonymousInnerClassEnd(int currentType, char nextChar) { - return currentType == TokenTypes.RCURLY - && (nextChar == ')' - || nextChar == ';' - || nextChar == ',' - || nextChar == '.'); - } - - /** * Is ast not a target of Check. * @param ast ast * @param currentType type of ast @@ -404,9 +419,10 @@ final boolean starImportOrSlistInsideCaseGroup = starImport || slistInsideCaseGroup; final boolean colonOfCaseOrDefaultOrForEach = isColonOfCaseOrDefault(currentType, parentType) - || isColonOfForEach(currentType, parentType); - final boolean emptyBlockOrType = isEmptyBlock(ast, parentType) - || allowEmptyTypes && isEmptyType(ast); + || isColonOfForEach(currentType, parentType); + final boolean emptyBlockOrType = + isEmptyBlock(ast, parentType) + || allowEmptyTypes && isEmptyType(ast); return starImportOrSlistInsideCaseGroup || colonOfCaseOrDefaultOrForEach @@ -415,6 +431,57 @@ } /** + * Check if it should be checked if previous token is separated from current by + * whitespace. + * This function is needed to recognise double brace initialization as valid, + * unfortunately its not possible to implement this functionality + * in isNotRelevantSituation method, because in this method when we return + * true(is not relevant) ast is later doesn't check at all. For example: + * new Properties() {{setProperty("double curly braces", "are not a style error"); + * }}; + * For second left curly brace in first line when we would return true from + * isNotRelevantSituation it wouldn't later check that the next token(setProperty) + * is not separated from previous token. + * @param ast current AST. + * @return true if it should be checked if previous token is separated by whitespace, + * false otherwise. + */ + private static boolean shouldCheckSeparationFromPreviousToken(DetailAST ast) { + return !isPartOfDoubleBraceInitializerForPreviousToken(ast); + } + + /** + * Check if it should be checked if next token is separated from current by + * whitespace. Explanation why this method is needed is identical to one + * included in shouldCheckSeparationFromPreviousToken method. + * @param ast current AST. + * @param nextChar next character. + * @return true if it should be checked if next token is separated by whitespace, + * false otherwise. + */ + private static boolean shouldCheckSeparationFromNextToken(DetailAST ast, char nextChar) { + return !(ast.getType() == TokenTypes.LITERAL_RETURN + && ast.getFirstChild().getType() == TokenTypes.SEMI) + && ast.getType() != TokenTypes.ARRAY_INIT + && !isAnonymousInnerClassEnd(ast.getType(), nextChar) + && !isPartOfDoubleBraceInitializerForNextToken(ast); + } + + /** + * Check for "})" or "};" or "},". Happens with anon-inners + * @param currentType token + * @param nextChar next symbol + * @return true is that is end of anon inner class + */ + private static boolean isAnonymousInnerClassEnd(int currentType, char nextChar) { + return currentType == TokenTypes.RCURLY + && (nextChar == ')' + || nextChar == ';' + || nextChar == ',' + || nextChar == '.'); + } + + /** * Is empty block. * @param ast ast * @param parentType parent @@ -424,7 +491,8 @@ return isEmptyMethodBlock(ast, parentType) || isEmptyCtorBlock(ast, parentType) || isEmptyLoop(ast, parentType) - || isEmptyLambda(ast, parentType); + || isEmptyLambda(ast, parentType) + || isEmptyCatch(ast, parentType); } /** @@ -443,18 +511,21 @@ * node. */ private static boolean isEmptyBlock(DetailAST ast, int parentType, int match) { + final boolean result; final int type = ast.getType(); if (type == TokenTypes.RCURLY) { final DetailAST parent = ast.getParent(); final DetailAST grandParent = ast.getParent().getParent(); - return parentType == TokenTypes.SLIST - && parent.getFirstChild().getType() == TokenTypes.RCURLY - && grandParent.getType() == match; + result = parentType == TokenTypes.SLIST + && parent.getFirstChild().getType() == TokenTypes.RCURLY + && grandParent.getType() == match; } - - return type == TokenTypes.SLIST - && parentType == match - && ast.getFirstChild().getType() == TokenTypes.RCURLY; + else { + result = type == TokenTypes.SLIST + && parentType == match + && ast.getFirstChild().getType() == TokenTypes.RCURLY; + } + return result; } /** @@ -466,7 +537,7 @@ private static boolean isColonOfCaseOrDefault(int currentType, int parentType) { return currentType == TokenTypes.COLON && (parentType == TokenTypes.LITERAL_DEFAULT - || parentType == TokenTypes.LITERAL_CASE); + || parentType == TokenTypes.LITERAL_CASE); } /** @@ -477,8 +548,8 @@ */ private boolean isColonOfForEach(int currentType, int parentType) { return currentType == TokenTypes.COLON - && parentType == TokenTypes.FOR_EACH_CLAUSE - && ignoreEnhancedForColon; + && parentType == TokenTypes.FOR_EACH_CLAUSE + && ignoreEnhancedForColon; } /** @@ -488,10 +559,9 @@ * @return true is current token inside array initialization */ private static boolean isArrayInitialization(int currentType, int parentType) { - return (currentType == TokenTypes.RCURLY - || currentType == TokenTypes.LCURLY) - && (parentType == TokenTypes.ARRAY_INIT - || parentType == TokenTypes.ANNOTATION_ARRAY_INIT); + return (currentType == TokenTypes.RCURLY || currentType == TokenTypes.LCURLY) + && (parentType == TokenTypes.ARRAY_INIT + || parentType == TokenTypes.ANNOTATION_ARRAY_INIT); } /** @@ -504,7 +574,7 @@ */ private boolean isEmptyMethodBlock(DetailAST ast, int parentType) { return allowEmptyMethods - && isEmptyBlock(ast, parentType, TokenTypes.METHOD_DEF); + && isEmptyBlock(ast, parentType, TokenTypes.METHOD_DEF); } /** @@ -517,11 +587,11 @@ */ private boolean isEmptyCtorBlock(DetailAST ast, int parentType) { return allowEmptyConstructors - && isEmptyBlock(ast, parentType, TokenTypes.CTOR_DEF); + && isEmptyBlock(ast, parentType, TokenTypes.CTOR_DEF); } /** - * + * Checks if loop is empty. * @param ast ast the {@code DetailAST} to test. * @param parentType the token type of {@code ast}'s parent. * @return {@code true} if {@code ast} makes up part of an @@ -529,11 +599,9 @@ */ private boolean isEmptyLoop(DetailAST ast, int parentType) { return allowEmptyLoops - && (isEmptyBlock(ast, parentType, TokenTypes.LITERAL_FOR) - || isEmptyBlock(ast, - parentType, TokenTypes.LITERAL_WHILE) - || isEmptyBlock(ast, - parentType, TokenTypes.LITERAL_DO)); + && (isEmptyBlock(ast, parentType, TokenTypes.LITERAL_FOR) + || isEmptyBlock(ast, parentType, TokenTypes.LITERAL_WHILE) + || isEmptyBlock(ast, parentType, TokenTypes.LITERAL_DO)); } /** @@ -549,6 +617,18 @@ } /** + * Tests if the given {@code DetailAst} is part of an allowed empty + * catch block. + * @param ast the {@code DetailAst} to test. + * @param parentType the token type of {@code ast}'s parent + * @return {@code true} if {@code ast} makes up part of an + * allowed empty catch block. + */ + private boolean isEmptyCatch(DetailAST ast, int parentType) { + return allowEmptyCatches && isEmptyBlock(ast, parentType, TokenTypes.LITERAL_CATCH); + } + + /** * Test if the given {@code DetailAST} is part of an empty block. * An example empty block might look like the following *

    @@ -565,9 +645,43 @@ final DetailAST nextSibling = ast.getNextSibling(); final DetailAST previousSibling = ast.getPreviousSibling(); return type == TokenTypes.LCURLY - && nextSibling.getType() == TokenTypes.RCURLY - || type == TokenTypes.RCURLY - && previousSibling != null - && previousSibling.getType() == TokenTypes.LCURLY; + && nextSibling.getType() == TokenTypes.RCURLY + || type == TokenTypes.RCURLY + && previousSibling != null + && previousSibling.getType() == TokenTypes.LCURLY; } + + /** + * Check if given ast is part of double brace initializer and if it + * should omit checking if previous token is separated by whitespace. + * @param ast ast to check + * @return true if it should omit checking for previous token, false otherwise + */ + private static boolean isPartOfDoubleBraceInitializerForPreviousToken(DetailAST ast) { + final boolean initializerBeginsAfterClassBegins = ast.getType() == TokenTypes.SLIST + && ast.getParent().getType() == TokenTypes.INSTANCE_INIT; + final boolean classEndsAfterInitializerEnds = ast.getType() == TokenTypes.RCURLY + && ast.getPreviousSibling() != null + && ast.getPreviousSibling().getType() == TokenTypes.INSTANCE_INIT; + return initializerBeginsAfterClassBegins || classEndsAfterInitializerEnds; + } + + /** + * Check if given ast is part of double brace initializer and if it + * should omit checking if next token is separated by whitespace. + * See + * PR#2845 for more information why this function was needed. + * @param ast ast to check + * @return true if it should omit checking for next token, false otherwise + */ + private static boolean isPartOfDoubleBraceInitializerForNextToken(DetailAST ast) { + final boolean classBeginBeforeInitializerBegin = ast.getType() == TokenTypes.LCURLY + && ast.getNextSibling().getType() == TokenTypes.INSTANCE_INIT; + final boolean initalizerEndsBeforeClassEnds = ast.getType() == TokenTypes.RCURLY + && ast.getParent().getType() == TokenTypes.SLIST + && ast.getParent().getParent().getType() == TokenTypes.INSTANCE_INIT + && ast.getParent().getParent().getNextSibling().getType() == TokenTypes.RCURLY; + return classBeginBeforeInitializerBegin || initalizerEndsBeforeClassEnds; + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WrapOption.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WrapOption.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WrapOption.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/checks/whitespace/WrapOption.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,8 +25,10 @@ * @author Rick Giles */ public enum WrapOption { + /** Require that the token is on a new line. */ NL, /** Require that the token is at the end of the line. */ EOL + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/ConfigurationLoader.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/ConfigurationLoader.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/ConfigurationLoader.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/ConfigurationLoader.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,25 +23,23 @@ import java.io.InputStream; import java.net.URI; import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; import java.util.Deque; +import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Optional; import javax.xml.parsers.ParserConfigurationException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; import org.xml.sax.Attributes; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; -import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.puppycrawl.tools.checkstyle.api.AbstractLoader; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Configuration; import com.puppycrawl.tools.checkstyle.api.SeverityLevel; @@ -53,15 +51,33 @@ * @author Oliver Burn */ public final class ConfigurationLoader { - /** Logger for ConfigurationLoader. */ - private static final Log LOG = LogFactory.getLog(ConfigurationLoader.class); + + /** + * Enum to specify behaviour regarding ignored modules. + */ + public enum IgnoredModulesOptions { + + /** + * Omit ignored modules. + */ + OMIT, + + /** + * Execute ignored modules. + */ + EXECUTE + + } + + /** Format of message for sax parse exception. */ + private static final String SAX_PARSE_EXCEPTION_FORMAT = "%s - %s:%s:%s"; /** The public ID for version 1_0 of the configuration dtd. */ private static final String DTD_PUBLIC_ID_1_0 = "-//Puppy Crawl//DTD Check Configuration 1.0//EN"; /** The resource for version 1_0 of the configuration dtd. */ - private static final String DTD_RESOURCE_NAME_1_0 = + private static final String DTD_CONFIGURATION_NAME_1_0 = "com/puppycrawl/tools/checkstyle/configuration_1_0.dtd"; /** The public ID for version 1_1 of the configuration dtd. */ @@ -69,7 +85,7 @@ "-//Puppy Crawl//DTD Check Configuration 1.1//EN"; /** The resource for version 1_1 of the configuration dtd. */ - private static final String DTD_RESOURCE_NAME_1_1 = + private static final String DTD_CONFIGURATION_NAME_1_1 = "com/puppycrawl/tools/checkstyle/configuration_1_1.dtd"; /** The public ID for version 1_2 of the configuration dtd. */ @@ -77,7 +93,7 @@ "-//Puppy Crawl//DTD Check Configuration 1.2//EN"; /** The resource for version 1_2 of the configuration dtd. */ - private static final String DTD_RESOURCE_NAME_1_2 = + private static final String DTD_CONFIGURATION_NAME_1_2 = "com/puppycrawl/tools/checkstyle/configuration_1_2.dtd"; /** The public ID for version 1_3 of the configuration dtd. */ @@ -85,7 +101,7 @@ "-//Puppy Crawl//DTD Check Configuration 1.3//EN"; /** The resource for version 1_3 of the configuration dtd. */ - private static final String DTD_RESOURCE_NAME_1_3 = + private static final String DTD_CONFIGURATION_NAME_1_3 = "com/puppycrawl/tools/checkstyle/configuration_1_3.dtd"; /** Prefix for the exception when unable to parse resource. */ @@ -106,6 +122,9 @@ /** Flags if modules with the severity 'ignore' should be omitted. */ private final boolean omitIgnoredModules; + /** The thread mode configuration. */ + private final ThreadModeSettings threadModeSettings; + /** The Configuration that is being built. */ private Configuration configuration; @@ -119,10 +138,27 @@ */ private ConfigurationLoader(final PropertyResolver overrideProps, final boolean omitIgnoredModules) - throws ParserConfigurationException, SAXException { + throws ParserConfigurationException, SAXException { + this(overrideProps, omitIgnoredModules, ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE); + } + + /** + * Creates a new {@code ConfigurationLoader} instance. + * @param overrideProps resolver for overriding properties + * @param omitIgnoredModules {@code true} if ignored modules should be + * omitted + * @param threadModeSettings the thread mode configuration + * @throws ParserConfigurationException if an error occurs + * @throws SAXException if an error occurs + */ + private ConfigurationLoader(final PropertyResolver overrideProps, + final boolean omitIgnoredModules, + final ThreadModeSettings threadModeSettings) + throws ParserConfigurationException, SAXException { saxHandler = new InternalLoader(); overridePropsResolver = overrideProps; this.omitIgnoredModules = omitIgnoredModules; + this.threadModeSettings = threadModeSettings; } /** @@ -130,11 +166,11 @@ * @return map between local resources and dtd ids. */ private static Map createIdToResourceNameMap() { - final Map map = Maps.newHashMap(); - map.put(DTD_PUBLIC_ID_1_0, DTD_RESOURCE_NAME_1_0); - map.put(DTD_PUBLIC_ID_1_1, DTD_RESOURCE_NAME_1_1); - map.put(DTD_PUBLIC_ID_1_2, DTD_RESOURCE_NAME_1_2); - map.put(DTD_PUBLIC_ID_1_3, DTD_RESOURCE_NAME_1_3); + final Map map = new HashMap<>(); + map.put(DTD_PUBLIC_ID_1_0, DTD_CONFIGURATION_NAME_1_0); + map.put(DTD_PUBLIC_ID_1_1, DTD_CONFIGURATION_NAME_1_1); + map.put(DTD_PUBLIC_ID_1_2, DTD_CONFIGURATION_NAME_1_2); + map.put(DTD_PUBLIC_ID_1_3, DTD_CONFIGURATION_NAME_1_3); return map; } @@ -149,7 +185,7 @@ * @throws SAXException if an error occurs */ private void parseInputSource(InputSource source) - throws IOException, SAXException { + throws IOException, SAXException { saxHandler.parseInputSource(source); } @@ -162,7 +198,22 @@ */ public static Configuration loadConfiguration(String config, PropertyResolver overridePropsResolver) throws CheckstyleException { - return loadConfiguration(config, overridePropsResolver, false); + return loadConfiguration(config, overridePropsResolver, IgnoredModulesOptions.EXECUTE); + } + + /** + * Returns the module configurations in a specified file. + * @param config location of config file, can be either a URL or a filename + * @param overridePropsResolver overriding properties + * @param threadModeSettings the thread mode configuration + * @return the check configurations + * @throws CheckstyleException if an error occurs + */ + public static Configuration loadConfiguration(String config, + PropertyResolver overridePropsResolver, ThreadModeSettings threadModeSettings) + throws CheckstyleException { + return loadConfiguration(config, overridePropsResolver, + IgnoredModulesOptions.EXECUTE, threadModeSettings); } /** @@ -174,15 +225,40 @@ * 'ignore' should be omitted, {@code false} otherwise * @return the check configurations * @throws CheckstyleException if an error occurs + * @deprecated in order to fulfill demands of BooleanParameter IDEA check. + * @noinspection BooleanParameter */ + @Deprecated public static Configuration loadConfiguration(String config, PropertyResolver overridePropsResolver, boolean omitIgnoredModules) - throws CheckstyleException { + throws CheckstyleException { + return loadConfiguration(config, overridePropsResolver, omitIgnoredModules, + ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE); + } + + /** + * Returns the module configurations in a specified file. + * + * @param config location of config file, can be either a URL or a filename + * @param overridePropsResolver overriding properties + * @param omitIgnoredModules {@code true} if modules with severity + * 'ignore' should be omitted, {@code false} otherwise + * @param threadModeSettings the thread mode configuration + * @return the check configurations + * @throws CheckstyleException if an error occurs + * @deprecated in order to fulfill demands of BooleanParameter IDEA check. + * @noinspection BooleanParameter, WeakerAccess + */ + @Deprecated + public static Configuration loadConfiguration(String config, + PropertyResolver overridePropsResolver, + boolean omitIgnoredModules, ThreadModeSettings threadModeSettings) + throws CheckstyleException { // figure out if this is a File or a URL final URI uri = CommonUtils.getUriByFilename(config); final InputSource source = new InputSource(uri.toString()); return loadConfiguration(source, overridePropsResolver, - omitIgnoredModules); + omitIgnoredModules, threadModeSettings); } /** @@ -201,11 +277,12 @@ * {@link #loadConfiguration(InputSource,PropertyResolver,boolean) * version using an InputSource} * should be used instead + * @noinspection BooleanParameter */ @Deprecated public static Configuration loadConfiguration(InputStream configStream, PropertyResolver overridePropsResolver, boolean omitIgnoredModules) - throws CheckstyleException { + throws CheckstyleException { return loadConfiguration(new InputSource(configStream), overridePropsResolver, omitIgnoredModules); } @@ -221,19 +298,145 @@ * 'ignore' should be omitted, {@code false} otherwise * @return the check configurations * @throws CheckstyleException if an error occurs + * @deprecated in order to fulfill demands of BooleanParameter IDEA check. + * @noinspection BooleanParameter */ + @Deprecated public static Configuration loadConfiguration(InputSource configSource, PropertyResolver overridePropsResolver, boolean omitIgnoredModules) - throws CheckstyleException { + throws CheckstyleException { + return loadConfiguration(configSource, overridePropsResolver, + omitIgnoredModules, ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE); + } + + /** + * Returns the module configurations from a specified input source. + * Note that if the source does wrap an open byte or character + * stream, clients are required to close that stream by themselves + * + * @param configSource the input stream to the Checkstyle configuration + * @param overridePropsResolver overriding properties + * @param omitIgnoredModules {@code true} if modules with severity + * 'ignore' should be omitted, {@code false} otherwise + * @param threadModeSettings the thread mode configuration + * @return the check configurations + * @throws CheckstyleException if an error occurs + * @deprecated in order to fulfill demands of BooleanParameter IDEA check. + * @noinspection BooleanParameter, WeakerAccess + */ + @Deprecated + public static Configuration loadConfiguration(InputSource configSource, + PropertyResolver overridePropsResolver, + boolean omitIgnoredModules, ThreadModeSettings threadModeSettings) + throws CheckstyleException { try { final ConfigurationLoader loader = new ConfigurationLoader(overridePropsResolver, - omitIgnoredModules); + omitIgnoredModules, threadModeSettings); loader.parseInputSource(configSource); return loader.configuration; } catch (final SAXParseException ex) { - final String message = String.format(Locale.ROOT, "%s - %s:%s:%s", + final String message = String.format(Locale.ROOT, SAX_PARSE_EXCEPTION_FORMAT, + UNABLE_TO_PARSE_EXCEPTION_PREFIX, + ex.getMessage(), ex.getLineNumber(), ex.getColumnNumber()); + throw new CheckstyleException(message, ex); + } + catch (final ParserConfigurationException | IOException | SAXException ex) { + throw new CheckstyleException(UNABLE_TO_PARSE_EXCEPTION_PREFIX, ex); + } + } + + /** + * Returns the module configurations in a specified file. + * + * @param config location of config file, can be either a URL or a filename + * @param overridePropsResolver overriding properties + * @param ignoredModulesOptions {@code OMIT} if modules with severity + * 'ignore' should be omitted, {@code EXECUTE} otherwise + * @return the check configurations + * @throws CheckstyleException if an error occurs + */ + public static Configuration loadConfiguration(String config, + PropertyResolver overridePropsResolver, + IgnoredModulesOptions ignoredModulesOptions) + throws CheckstyleException { + return loadConfiguration(config, overridePropsResolver, ignoredModulesOptions, + ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE); + } + + /** + * Returns the module configurations in a specified file. + * + * @param config location of config file, can be either a URL or a filename + * @param overridePropsResolver overriding properties + * @param ignoredModulesOptions {@code OMIT} if modules with severity + * 'ignore' should be omitted, {@code EXECUTE} otherwise + * @param threadModeSettings the thread mode configuration + * @return the check configurations + * @throws CheckstyleException if an error occurs + */ + public static Configuration loadConfiguration(String config, + PropertyResolver overridePropsResolver, + IgnoredModulesOptions ignoredModulesOptions, + ThreadModeSettings threadModeSettings) + throws CheckstyleException { + // figure out if this is a File or a URL + final URI uri = CommonUtils.getUriByFilename(config); + final InputSource source = new InputSource(uri.toString()); + return loadConfiguration(source, overridePropsResolver, + ignoredModulesOptions, threadModeSettings); + } + + /** + * Returns the module configurations from a specified input source. + * Note that if the source does wrap an open byte or character + * stream, clients are required to close that stream by themselves + * + * @param configSource the input stream to the Checkstyle configuration + * @param overridePropsResolver overriding properties + * @param ignoredModulesOptions {@code OMIT} if modules with severity + * 'ignore' should be omitted, {@code EXECUTE} otherwise + * @return the check configurations + * @throws CheckstyleException if an error occurs + */ + public static Configuration loadConfiguration(InputSource configSource, + PropertyResolver overridePropsResolver, + IgnoredModulesOptions ignoredModulesOptions) + throws CheckstyleException { + return loadConfiguration(configSource, overridePropsResolver, + ignoredModulesOptions, ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE); + } + + /** + * Returns the module configurations from a specified input source. + * Note that if the source does wrap an open byte or character + * stream, clients are required to close that stream by themselves + * + * @param configSource the input stream to the Checkstyle configuration + * @param overridePropsResolver overriding properties + * @param ignoredModulesOptions {@code OMIT} if modules with severity + * 'ignore' should be omitted, {@code EXECUTE} otherwise + * @param threadModeSettings the thread mode configuration + * @return the check configurations + * @throws CheckstyleException if an error occurs + * @noinspection WeakerAccess + */ + public static Configuration loadConfiguration(InputSource configSource, + PropertyResolver overridePropsResolver, + IgnoredModulesOptions ignoredModulesOptions, + ThreadModeSettings threadModeSettings) + throws CheckstyleException { + try { + final boolean omitIgnoreModules = ignoredModulesOptions == IgnoredModulesOptions.OMIT; + final ConfigurationLoader loader = + new ConfigurationLoader(overridePropsResolver, + omitIgnoreModules, threadModeSettings); + loader.parseInputSource(configSource); + return loader.configuration; + } + catch (final SAXParseException ex) { + final String message = String.format(Locale.ROOT, SAX_PARSE_EXCEPTION_FORMAT, UNABLE_TO_PARSE_EXCEPTION_PREFIX, ex.getMessage(), ex.getLineNumber(), ex.getColumnNumber()); throw new CheckstyleException(message, ex); @@ -247,8 +450,6 @@ * Replaces {@code ${xxx}} style constructions in the given value * with the string value of the corresponding data types. * - *

    The method is package visible to facilitate testing. - * *

    Code copied from ant - * http://cvs.apache.org/viewcvs/jakarta-ant/src/main/org/apache/tools/ant/ProjectHelper.java * @@ -265,20 +466,20 @@ * @throws CheckstyleException if the string contains an opening * {@code ${} without a closing * {@code }} + * @noinspection MethodWithMultipleReturnPoints */ - @VisibleForTesting - static String replaceProperties( + private static String replaceProperties( String value, PropertyResolver props, String defaultValue) - throws CheckstyleException { + throws CheckstyleException { if (value == null) { return null; } - final List fragments = Lists.newArrayList(); - final List propertyRefs = Lists.newArrayList(); + final List fragments = new ArrayList<>(); + final List propertyRefs = new ArrayList<>(); parsePropertyString(value, fragments, propertyRefs); - final StringBuilder sb = new StringBuilder(); + final StringBuilder sb = new StringBuilder(256); final Iterator fragmentsIterator = fragments.iterator(); final Iterator propertyRefsIterator = propertyRefs.iterator(); while (fragmentsIterator.hasNext()) { @@ -288,7 +489,8 @@ fragment = props.resolve(propertyName); if (fragment == null) { if (defaultValue != null) { - return defaultValue; + sb.replace(0, sb.length(), defaultValue); + break; } throw new CheckstyleException( "Property ${" + propertyName + "} has not been set"); @@ -323,12 +525,11 @@ private static void parsePropertyString(String value, List fragments, List propertyRefs) - throws CheckstyleException { + throws CheckstyleException { int prev = 0; //search for the next instance of $ from the 'prev' position int pos = value.indexOf(DOLLAR_SIGN, prev); while (pos >= 0) { - //if there was any text before this, add it as a fragment if (pos > 0) { fragments.add(value.substring(prev, pos)); @@ -342,7 +543,7 @@ else if (value.charAt(pos + 1) == '{') { //property found, extract its name or bail on a typo final int endName = value.indexOf('}', pos); - if (endName < 0) { + if (endName == -1) { throw new CheckstyleException("Syntax error in property: " + value); } @@ -379,7 +580,8 @@ * appear in the public API of the ConfigurationLoader. */ private final class InternalLoader - extends AbstractLoader { + extends XmlLoader { + /** Module elements. */ private static final String MODULE = "module"; /** Name attribute. */ @@ -405,7 +607,7 @@ * @throws ParserConfigurationException if an error occurs */ InternalLoader() - throws SAXException, ParserConfigurationException { + throws SAXException, ParserConfigurationException { super(createIdToResourceNameMap()); } @@ -414,12 +616,13 @@ String localName, String qName, Attributes attributes) - throws SAXException { + throws SAXException { if (qName.equals(MODULE)) { //create configuration - final String name = attributes.getValue(NAME); + final String originalName = attributes.getValue(NAME); + final String name = threadModeSettings.resolveName(originalName); final DefaultConfiguration conf = - new DefaultConfiguration(name); + new DefaultConfiguration(name, threadModeSettings); if (configuration == null) { configuration = conf; @@ -442,6 +645,7 @@ overridePropsResolver, attributes.getValue(DEFAULT)); } catch (final CheckstyleException ex) { + // -@cs[IllegalInstantiation] SAXException is in the overridden method signature throw new SAXException(ex); } final String name = attributes.getValue(NAME); @@ -470,21 +674,25 @@ @Override public void endElement(String uri, String localName, - String qName) { + String qName) throws SAXException { if (qName.equals(MODULE)) { - final Configuration recentModule = configStack.pop(); - // remove modules with severity ignore if these modules should - // be omitted + // get severity attribute if it exists SeverityLevel level = null; - try { - final String severity = recentModule.getAttribute(SEVERITY); - level = SeverityLevel.getInstance(severity); - } - catch (final CheckstyleException ex) { - LOG.debug("Severity not set, ignoring exception", ex); + if (containsAttribute(recentModule, SEVERITY)) { + try { + final String severity = recentModule.getAttribute(SEVERITY); + level = SeverityLevel.getInstance(severity); + } + catch (final CheckstyleException ex) { + // -@cs[IllegalInstantiation] SAXException is in the overridden + // method signature + throw new SAXException( + "Problem during accessing '" + SEVERITY + "' attribute for " + + recentModule.getName(), ex); + } } // omit this module if these should be omitted and the module @@ -499,5 +707,20 @@ } } } + + /** + * Util method to recheck attribute in module. + * @param module module to check + * @param attributeName name of attribute in module to find + * @return true if attribute is present in module + */ + private boolean containsAttribute(Configuration module, String attributeName) { + final String[] names = module.getAttributeNames(); + final Optional result = Arrays.stream(names) + .filter(name -> name.equals(attributeName)).findFirst(); + return result.isPresent(); + } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/DefaultConfiguration.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/DefaultConfiguration.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/DefaultConfiguration.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/DefaultConfiguration.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,41 +19,57 @@ package com.puppycrawl.tools.checkstyle; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import com.google.common.collect.ImmutableMap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Configuration; /** * Default implementation of the Configuration interface. * @author lkuehne + * @noinspection SerializableHasSerializationMethods */ public final class DefaultConfiguration implements Configuration { + private static final long serialVersionUID = 1157875385356127169L; /** The name of this configuration. */ private final String name; /** The list of child Configurations. */ - private final List children = Lists.newArrayList(); + private final List children = new ArrayList<>(); /** The map from attribute names to attribute values. */ - private final Map attributeMap = Maps.newHashMap(); + private final Map attributeMap = new HashMap<>(); /** The map containing custom messages. */ - private final Map messages = Maps.newHashMap(); + private final Map messages = new HashMap<>(); + + /** The thread mode configuration. */ + private final ThreadModeSettings threadModeSettings; /** * Instantiates a DefaultConfiguration. * @param name the name for this DefaultConfiguration. */ public DefaultConfiguration(String name) { + this(name, ThreadModeSettings.SINGLE_THREAD_MODE_INSTANCE); + } + + /** + * Instantiates a DefaultConfiguration. + * @param name the name for this DefaultConfiguration. + * @param threadModeSettings the thread mode configuration. + */ + public DefaultConfiguration(String name, + ThreadModeSettings threadModeSettings) { this.name = name; + this.threadModeSettings = threadModeSettings; } @Override @@ -131,4 +147,13 @@ public ImmutableMap getMessages() { return ImmutableMap.copyOf(messages); } + + /** + * Gets the thread mode configuration. + * @return the thread mode configuration. + */ + public ThreadModeSettings getThreadModeSettings() { + return threadModeSettings; + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/DefaultContext.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/DefaultContext.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/DefaultContext.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/DefaultContext.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,11 +19,11 @@ package com.puppycrawl.tools.checkstyle; +import java.util.HashMap; import java.util.Map; import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Maps; import com.puppycrawl.tools.checkstyle.api.Context; /** @@ -31,8 +31,9 @@ * @author lkuehne */ public final class DefaultContext implements Context { + /** Stores the context entries. */ - private final Map entries = Maps.newHashMap(); + private final Map entries = new HashMap<>(); @Override public Object get(String key) { @@ -52,4 +53,5 @@ public void add(String key, Object value) { entries.put(key, value); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/DefaultLogger.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/DefaultLogger.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/DefaultLogger.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/DefaultLogger.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -28,6 +28,8 @@ import com.puppycrawl.tools.checkstyle.api.AuditEvent; import com.puppycrawl.tools.checkstyle.api.AuditListener; import com.puppycrawl.tools.checkstyle.api.AutomaticBean; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; import com.puppycrawl.tools.checkstyle.api.SeverityLevel; /** @@ -39,9 +41,26 @@ * * @author Stephane Bailliez * @see XMLLogger + * @noinspection ClassWithTooManyConstructors */ public class DefaultLogger extends AutomaticBean implements AuditListener { + /** + * A key pointing to the add exception + * message in the "messages.properties" file. + */ + public static final String ADD_EXCEPTION_MESSAGE = "DefaultLogger.addException"; + /** + * A key pointing to the started audit + * message in the "messages.properties" file. + */ + public static final String AUDIT_STARTED_MESSAGE = "DefaultLogger.auditStarted"; + /** + * A key pointing to the finished audit + * message in the "messages.properties" file. + */ + public static final String AUDIT_FINISHED_MESSAGE = "DefaultLogger.auditFinished"; + /** Where to write info messages. **/ private final PrintWriter infoWriter; /** Close info stream after use. */ @@ -59,19 +78,25 @@ * Creates a new {@code DefaultLogger} instance. * @param outputStream where to log infos and errors * @param closeStreamsAfterUse if oS should be closed in auditFinished() + * @deprecated in order to fulfill demands of BooleanParameter IDEA check. + * @noinspection BooleanParameter */ + @Deprecated public DefaultLogger(OutputStream outputStream, boolean closeStreamsAfterUse) { // no need to close oS twice this(outputStream, closeStreamsAfterUse, outputStream, false); } /** - * Creates a new DefaultLogger instance. + * Creates a new {@code DefaultLogger} instance. * @param infoStream the {@code OutputStream} for info messages. * @param closeInfoAfterUse auditFinished should close infoStream. * @param errorStream the {@code OutputStream} for error messages. * @param closeErrorAfterUse auditFinished should close errorStream + * @deprecated in order to fulfill demands of BooleanParameter IDEA check. + * @noinspection BooleanParameter */ + @Deprecated public DefaultLogger(OutputStream infoStream, boolean closeInfoAfterUse, OutputStream errorStream, @@ -88,7 +113,10 @@ * @param errorStream the {@code OutputStream} for error messages * @param closeErrorAfterUse auditFinished should close errorStream * @param messageFormatter formatter for the log message. + * @deprecated in order to fulfill demands of BooleanParameter IDEA check. + * @noinspection BooleanParameter, WeakerAccess */ + @Deprecated public DefaultLogger(OutputStream infoStream, boolean closeInfoAfterUse, OutputStream errorStream, @@ -97,24 +125,83 @@ closeInfo = closeInfoAfterUse; closeError = closeErrorAfterUse; final Writer infoStreamWriter = new OutputStreamWriter(infoStream, StandardCharsets.UTF_8); - final Writer errorStreamWriter = new OutputStreamWriter(errorStream, - StandardCharsets.UTF_8); infoWriter = new PrintWriter(infoStreamWriter); if (infoStream == errorStream) { errorWriter = infoWriter; } else { + final Writer errorStreamWriter = new OutputStreamWriter(errorStream, + StandardCharsets.UTF_8); errorWriter = new PrintWriter(errorStreamWriter); } formatter = messageFormatter; } /** + * Creates a new {@code DefaultLogger} instance. + * @param outputStream where to log infos and errors + * @param outputStreamOptions if {@code CLOSE} that should be closed in auditFinished() + */ + public DefaultLogger(OutputStream outputStream, OutputStreamOptions outputStreamOptions) { + // no need to close oS twice + this(outputStream, outputStreamOptions, outputStream, OutputStreamOptions.NONE); + } + + /** + * Creates a new {@code DefaultLogger} instance. + * @param infoStream the {@code OutputStream} for info messages. + * @param infoStreamOptions if {@code CLOSE} info should be closed in auditFinished() + * @param errorStream the {@code OutputStream} for error messages. + * @param errorStreamOptions if {@code CLOSE} error should be closed in auditFinished() + */ + public DefaultLogger(OutputStream infoStream, + OutputStreamOptions infoStreamOptions, + OutputStream errorStream, + OutputStreamOptions errorStreamOptions) { + this(infoStream, infoStreamOptions, errorStream, errorStreamOptions, + new AuditEventDefaultFormatter()); + } + + /** + * Creates a new {@code DefaultLogger} instance. + * + * @param infoStream the {@code OutputStream} for info messages + * @param infoStreamOptions if {@code CLOSE} info should be closed in auditFinished() + * @param errorStream the {@code OutputStream} for error messages + * @param errorStreamOptions if {@code CLOSE} error should be closed in auditFinished() + * @param messageFormatter formatter for the log message. + * @noinspection WeakerAccess + */ + public DefaultLogger(OutputStream infoStream, + OutputStreamOptions infoStreamOptions, + OutputStream errorStream, + OutputStreamOptions errorStreamOptions, + AuditEventFormatter messageFormatter) { + closeInfo = infoStreamOptions == OutputStreamOptions.CLOSE; + closeError = errorStreamOptions == OutputStreamOptions.CLOSE; + final Writer infoStreamWriter = new OutputStreamWriter(infoStream, StandardCharsets.UTF_8); + infoWriter = new PrintWriter(infoStreamWriter); + + if (infoStream == errorStream) { + errorWriter = infoWriter; + } + else { + final Writer errorStreamWriter = new OutputStreamWriter(errorStream, + StandardCharsets.UTF_8); + errorWriter = new PrintWriter(errorStreamWriter); + } + formatter = messageFormatter; + } + + @Override + protected void finishLocalSetup() throws CheckstyleException { + // No code by default + } + + /** * Print an Emacs compliant line on the error stream. * If the column number is non zero, then also display it. - * - * @param event the event details * @see AuditListener **/ @Override @@ -129,20 +216,30 @@ @Override public void addException(AuditEvent event, Throwable throwable) { synchronized (errorWriter) { - errorWriter.println("Error auditing " + event.getFileName()); + final LocalizedMessage addExceptionMessage = new LocalizedMessage(0, + Definitions.CHECKSTYLE_BUNDLE, ADD_EXCEPTION_MESSAGE, + new String[] {event.getFileName()}, null, + LocalizedMessage.class, null); + errorWriter.println(addExceptionMessage.getMessage()); throwable.printStackTrace(errorWriter); } } @Override public void auditStarted(AuditEvent event) { - infoWriter.println("Starting audit..."); + final LocalizedMessage auditStartMessage = new LocalizedMessage(0, + Definitions.CHECKSTYLE_BUNDLE, AUDIT_STARTED_MESSAGE, null, null, + LocalizedMessage.class, null); + infoWriter.println(auditStartMessage.getMessage()); infoWriter.flush(); } @Override public void auditFinished(AuditEvent event) { - infoWriter.println("Audit done."); + final LocalizedMessage auditFinishMessage = new LocalizedMessage(0, + Definitions.CHECKSTYLE_BUNDLE, AUDIT_FINISHED_MESSAGE, null, null, + LocalizedMessage.class, null); + infoWriter.println(auditFinishMessage.getMessage()); closeStreams(); } @@ -170,4 +267,5 @@ errorWriter.close(); } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/Definitions.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/Definitions.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/Definitions.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/Definitions.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,6 +24,7 @@ * @author Oliver Burn **/ public final class Definitions { + /** Name of resource bundle for Checkstyle. */ public static final String CHECKSTYLE_BUNDLE = "com.puppycrawl.tools.checkstyle.messages"; @@ -33,4 +34,5 @@ **/ private Definitions() { } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/DetailNodeTreeStringPrinter.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,174 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser.ParseErrorMessage; +import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser.ParseStatus; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.DetailNode; +import com.puppycrawl.tools.checkstyle.api.FileText; +import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; +import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; +import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; + +/** + * Parses file as javadoc DetailNode tree and prints to system output stream. + * @author bizmailov + */ +public final class DetailNodeTreeStringPrinter { + + /** OS specific line separator. */ + private static final String LINE_SEPARATOR = System.getProperty("line.separator"); + + /** Prevent instances. */ + private DetailNodeTreeStringPrinter() { + // no code + } + + /** + * Parse a file and print the parse tree. + * @param file the file to print. + * @return parse tree as a string + * @throws IOException if the file could not be read. + */ + public static String printFileAst(File file) throws IOException { + return printTree(parseFile(file), "", ""); + } + + /** + * Parse block comment DetailAST as Javadoc DetailNode tree. + * @param blockComment DetailAST + * @return DetailNode tree + */ + public static DetailNode parseJavadocAsDetailNode(DetailAST blockComment) { + final JavadocDetailNodeParser parser = new JavadocDetailNodeParser(); + final ParseStatus status = parser.parseJavadocAsDetailNode(blockComment); + if (status.getParseErrorMessage() != null) { + throw new IllegalArgumentException(getParseErrorMessage(status.getParseErrorMessage())); + } + return status.getTree(); + } + + /** + * Parse javadoc comment to DetailNode tree. + * @param javadocComment javadoc comment content + * @return tree + */ + private static DetailNode parseJavadocAsDetailNode(String javadocComment) { + final DetailAST blockComment = CommonUtils.createBlockCommentNode(javadocComment); + return parseJavadocAsDetailNode(blockComment); + } + + /** + * Builds error message base on ParseErrorMessage's message key, its arguments, etc. + * @param parseErrorMessage ParseErrorMessage + * @return error message + */ + private static String getParseErrorMessage(ParseErrorMessage parseErrorMessage) { + final LocalizedMessage lmessage = new LocalizedMessage( + parseErrorMessage.getLineNumber(), + "com.puppycrawl.tools.checkstyle.checks.javadoc.messages", + parseErrorMessage.getMessageKey(), + parseErrorMessage.getMessageArguments(), + "", + DetailNodeTreeStringPrinter.class, + null); + return "[ERROR:" + parseErrorMessage.getLineNumber() + "] " + lmessage.getMessage(); + } + + /** + * Print AST. + * @param ast the root AST node. + * @param rootPrefix prefix for the root node + * @param prefix prefix for other nodes + * @return string AST. + */ + public static String printTree(DetailNode ast, String rootPrefix, String prefix) { + final StringBuilder messageBuilder = new StringBuilder(1024); + DetailNode node = ast; + while (node != null) { + if (node.getType() == JavadocTokenTypes.JAVADOC) { + messageBuilder.append(rootPrefix); + } + else { + messageBuilder.append(prefix); + } + messageBuilder.append(getIndentation(node)) + .append(JavadocUtils.getTokenName(node.getType())).append(" -> ") + .append(JavadocUtils.escapeAllControlChars(node.getText())).append(" [") + .append(node.getLineNumber()).append(':').append(node.getColumnNumber()) + .append(']').append(LINE_SEPARATOR) + .append(printTree(JavadocUtils.getFirstChild(node), rootPrefix, prefix)); + node = JavadocUtils.getNextSibling(node); + } + return messageBuilder.toString(); + } + + /** + * Get indentation for a node. + * @param node the DetailNode to get the indentation for. + * @return the indentation in String format. + */ + private static String getIndentation(DetailNode node) { + final boolean isLastChild = JavadocUtils.getNextSibling(node) == null; + DetailNode currentNode = node; + final StringBuilder indentation = new StringBuilder(1024); + while (currentNode.getParent() != null) { + currentNode = currentNode.getParent(); + if (currentNode.getParent() == null) { + if (isLastChild) { + // only ASCII symbols must be used due to + // problems with running tests on Windows + indentation.append("`--"); + } + else { + indentation.append("|--"); + } + } + else { + if (JavadocUtils.getNextSibling(currentNode) == null) { + indentation.insert(0, " "); + } + else { + indentation.insert(0, "| "); + } + } + } + return indentation.toString(); + } + + /** + * Parse a file and return the parse tree. + * @param file the file to parse. + * @return the root node of the parse tree. + * @throws IOException if the file could not be read. + */ + private static DetailNode parseFile(File file) throws IOException { + final FileText text = new FileText(file.getAbsoluteFile(), + System.getProperty("file.encoding", StandardCharsets.UTF_8.name())); + return parseJavadocAsDetailNode(text.getFullText().toString()); + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/doclets/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/doclets/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/doclets/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/doclets/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/doclets/TokenTypesDoclet.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/doclets/TokenTypesDoclet.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/doclets/TokenTypesDoclet.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/doclets/TokenTypesDoclet.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,11 +25,16 @@ import java.io.PrintWriter; import java.io.Writer; import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.DocErrorReporter; import com.sun.javadoc.FieldDoc; import com.sun.javadoc.RootDoc; +import com.sun.javadoc.Tag; /** * Doclet which is used to write property file with short descriptions @@ -41,6 +46,7 @@ * @author o_sukhodolsky */ public final class TokenTypesDoclet { + /** Command line option to specify file to write output of the doclet. */ private static final String DEST_FILE_OPT = "-destfile"; @@ -67,13 +73,34 @@ final FieldDoc[] fields = classes[0].fields(); for (final FieldDoc field : fields) { if (field.isStatic() && field.isPublic() && field.isFinal() - && "int".equals(field.type().qualifiedTypeName())) { - if (field.firstSentenceTags().length != 1) { - final String message = "Should be only one tag."; + && "int".equals(field.type().qualifiedTypeName())) { + final String firstSentence; + + if (field.firstSentenceTags().length == 1) { + firstSentence = field.firstSentenceTags()[0].text(); + } + else if (Arrays.stream(field.firstSentenceTags()) + .filter(tag -> !"Text".equals(tag.name())).count() == 1) { + // We have to filter "Text" tags because of jdk parsing bug + // till JDK-8186270 + firstSentence = field.firstSentenceTags()[0].text() + + "" + + field.firstSentenceTags()[1].text() + + "" + + field.firstSentenceTags()[2].text(); + } + else { + final List tags = Arrays.asList(field.firstSentenceTags()); + final String joinedTags = tags + .stream() + .map(Tag::toString) + .collect(Collectors.joining("\", \"", "[\"", "\"]")); + final String message = String.format(Locale.ROOT, + "Should be only one tag for %s. Tags %s.", + field.toString(), joinedTags); throw new IllegalArgumentException(message); } - writer.println(field.name() + "=" - + field.firstSentenceTags()[0].text()); + writer.println(field.name() + "=" + firstSentence); } } } @@ -90,10 +117,11 @@ * @return option length (how many parts are in option). */ public static int optionLength(String option) { + int length = 0; if (DEST_FILE_OPT.equals(option)) { - return 2; + length = 2; } - return 0; + return length; } /** @@ -104,21 +132,21 @@ */ public static boolean checkOptions(String[][] options, DocErrorReporter reporter) { boolean foundDestFileOption = false; + boolean onlyOneDestFileOption = true; for (final String[] opt : options) { if (DEST_FILE_OPT.equals(opt[0])) { if (foundDestFileOption) { reporter.printError("Only one -destfile option allowed."); - return false; + onlyOneDestFileOption = false; + break; } foundDestFileOption = true; } } if (!foundDestFileOption) { - final String message = - "Usage: javadoc -destfile file -doclet TokenTypesDoclet ..."; - reporter.printError(message); + reporter.printError("Usage: javadoc -destfile file -doclet TokenTypesDoclet ..."); } - return foundDestFileOption; + return onlyOneDestFileOption && foundDestFileOption; } /** @@ -135,4 +163,5 @@ } return fileName; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filefilters/BeforeExecutionExclusionFileFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filefilters/BeforeExecutionExclusionFileFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filefilters/BeforeExecutionExclusionFileFilter.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filefilters/BeforeExecutionExclusionFileFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,95 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.filefilters; + +import java.util.regex.Pattern; + +import com.puppycrawl.tools.checkstyle.api.AutomaticBean; +import com.puppycrawl.tools.checkstyle.api.BeforeExecutionFileFilter; + +/** + *

    + * File filter {@code BeforeExecutionExclusionFileFilter} decides which files should be + * excluded from being processed by the utility. + *

    + * + *

    + * By default Checkstyle includes all files and sub-directories in a directory to be processed and + * checked for violations. Users could have files that are in these sub-directories that shouldn't + * be processed with their checkstyle configuration for various reasons, one of which is a valid + * Java file that won't pass Checkstyle's parser. When Checkstyle tries to parse a Java file and + * fails, it will throw an {@code Exception} and halt parsing any more files for violations. + * An example of a valid Java file Checkstyle can't parse is JDK 9's {@code module-info.java}. + * This file filter will exclude these problem files from being parsed, allowing the rest of the + * files to run normal and be validated. + *

    + * + *

    + * Note: When a file is excluded from the utility, it is excluded from all Checks and no + * testing for violations will be performed on them. + *

    + * + *

    + * Check have following options: + *

    + *
      + *
    • + * fileNamePattern - Regular expression to match the file name against. Default value is null.
    • + *
    + *
    + * + *

    + * To configure the filter to exclude all 'module-info.java' files: + *

    + * + *
    + * <module name="BeforeExecutionExclusionFileFilter">
    + *   <property name="fileNamePattern" value="module\-info\.java$"/>
    + * </module>
    + * 
    + * + * @author Richard Veach + */ +public final class BeforeExecutionExclusionFileFilter extends AutomaticBean + implements BeforeExecutionFileFilter { + + /** Filename of exclusion. */ + private Pattern fileNamePattern; + + /** + * Sets regular expression of the file to exclude. + * + * @param fileNamePattern regular expression of the excluded file. + */ + public void setFileNamePattern(Pattern fileNamePattern) { + this.fileNamePattern = fileNamePattern; + } + + @Override + protected void finishLocalSetup() { + // No code by default + } + + @Override + public boolean accept(String uri) { + return fileNamePattern == null || !fileNamePattern.matcher(uri).find(); + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filefilters/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filefilters/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filefilters/package-info.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filefilters/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +/** + * Contains the before execution file filters that are bundled with the main distribution. + */ +package com.puppycrawl.tools.checkstyle.filefilters; diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/FileStatefulCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/FileStatefulCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/FileStatefulCheck.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/FileStatefulCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,55 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation means that the check contains file-related context and therefore + * cannot be used from the others threads at the same time. + * This annotation should be used when the check holds a thread-unsafe state. + * Checker guarantees that the whole file processed inside the same thread. + * Checker guarantees that the whole file processed with the same check instance. + * Checker guarantees that each check instance processes only one file at the same time. + * Checker guarantees that all check instances have equal (but not the same) configuration. + * It means, that if a check holds a property of type "array of strings", + * the property value will not be shared across check instances. + * Instead, each check instance will hold its own array instance. + * Checker does not guarantee that each file will have it's own thread - + * there might be a list of files, which will be executed on the same thread. + * Checker does not guarantee that each file will have it's own check instance - + * there might be a list of files, which will be checked by the same instance. + * Note: Checks with such annotation will be executed in mode how all Checks worked + * before MT mode is introduced. + * @author Andrew Kuchev + * @noinspection AnnotationClass, ClassIndependentOfModule + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface FileStatefulCheck { + + // this annotation does not have properties + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/CsvFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/CsvFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/CsvFilter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/CsvFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,12 +20,11 @@ package com.puppycrawl.tools.checkstyle.filters; import java.util.Collections; +import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.StringTokenizer; -import com.google.common.collect.Sets; - /** *

    * This filter accepts an integer that matches a CSV value, where @@ -35,8 +34,9 @@ * @author o_sukhodolsky */ class CsvFilter implements IntFilter { + /** Filter set. */ - private final Set filters = Sets.newHashSet(); + private final Set filters = new HashSet<>(); /** * Constructs a {@code CsvFilter} from a CSV, Comma-Separated Values, @@ -89,12 +89,14 @@ */ @Override public boolean accept(int intValue) { + boolean result = false; for (IntFilter filter : getFilters()) { if (filter.accept(intValue)) { - return true; + result = true; + break; } } - return false; + return result; } @Override @@ -113,4 +115,5 @@ public int hashCode() { return Objects.hash(filters); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntFilter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -23,11 +23,14 @@ * An interface for filtering Integer. * @author o_sukhodolsky */ +@FunctionalInterface interface IntFilter { + /** * Determines whether or not a filtered Integer is accepted. * @param intValue the Integer to filter. * @return true if the intValue is accepted. */ boolean accept(int intValue); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntMatchFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntMatchFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntMatchFilter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntMatchFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,6 +24,7 @@ * @author Rick Giles */ class IntMatchFilter implements IntFilter { + /** The matching Integer. */ private final int matchValue; @@ -58,4 +59,5 @@ } return false; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntRangeFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntRangeFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntRangeFilter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/IntRangeFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -26,6 +26,7 @@ * @author Rick Giles */ class IntRangeFilter implements IntFilter { + /** Lower bound of the range. */ private final Integer lowerBound; @@ -66,4 +67,5 @@ return Objects.equals(lowerBound, intRangeFilter.lowerBound) && Objects.equals(upperBound, intRangeFilter.upperBound); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SeverityMatchFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SeverityMatchFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SeverityMatchFilter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SeverityMatchFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,6 +21,7 @@ import com.puppycrawl.tools.checkstyle.api.AuditEvent; import com.puppycrawl.tools.checkstyle.api.AutomaticBean; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Filter; import com.puppycrawl.tools.checkstyle.api.SeverityLevel; @@ -33,6 +34,7 @@ public class SeverityMatchFilter extends AutomaticBean implements Filter { + /** The severity level to accept. */ private SeverityLevel severity = SeverityLevel.ERROR; @@ -40,14 +42,13 @@ private boolean acceptOnMatch = true; /** - * Sets the severity level. The string should be one of the names - * defined in the {@code SeverityLevel} class. + * Sets the severity level. * * @param severity The new severity level * @see SeverityLevel */ - public final void setSeverity(String severity) { - this.severity = SeverityLevel.getInstance(severity); + public final void setSeverity(SeverityLevel severity) { + this.severity = severity; } /** @@ -60,11 +61,14 @@ } @Override + protected void finishLocalSetup() throws CheckstyleException { + // No code by default + } + + @Override public boolean accept(AuditEvent event) { - final boolean result = severity == event.getSeverityLevel(); - if (acceptOnMatch) { - return result; - } - return !result; + final boolean severityMatches = severity == event.getSeverityLevel(); + return acceptOnMatch == severityMatches; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressElement.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressElement.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressElement.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressElement.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,7 +24,6 @@ import com.puppycrawl.tools.checkstyle.api.AuditEvent; import com.puppycrawl.tools.checkstyle.api.Filter; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** * This filter processes {@link AuditEvent} @@ -41,6 +40,7 @@ */ public class SuppressElement implements Filter { + /** The regexp to match file names against. */ private final Pattern fileRegexp; @@ -48,60 +48,67 @@ private final String filePattern; /** The regexp to match check names against. */ - private Pattern checkRegexp; + private final Pattern checkRegexp; /** The pattern for check class names. */ - private String checkPattern; + private final String checkPattern; + + /** The regexp to match message names against. */ + private final Pattern messageRegexp; + + /** The pattern for message names. */ + private final String messagePattern; /** Module id filter. */ - private String moduleId; + private final String moduleId; /** Line number filter. */ - private CsvFilter lineFilter; + private final CsvFilter lineFilter; /** CSV for line number filter. */ - private String linesCsv; + private final String linesCsv; /** Column number filter. */ - private CsvFilter columnFilter; + private final CsvFilter columnFilter; /** CSV for column number filter. */ - private String columnsCsv; + private final String columnsCsv; /** * Constructs a {@code SuppressElement} for a - * file name pattern. Must either call {@link #setColumns(String)} or - * {@link #setModuleId(String)} before using this object. - * @param files regular expression for names of filtered files. + * file name pattern. + * + * @param files regular expression for names of filtered files. + * @param checks regular expression for filtered check classes. + * @param message regular expression for messages. + * @param modId the id + * @param lines lines CSV values and ranges for line number filtering. + * @param columns columns CSV values and ranges for column number filtering. */ - public SuppressElement(String files) { + public SuppressElement(String files, String checks, + String message, String modId, String lines, String columns) { filePattern = files; - fileRegexp = Pattern.compile(files); - } - - /** - * Set the check class pattern. - * @param checks regular expression for filtered check classes. - */ - public void setChecks(final String checks) { + if (files == null) { + fileRegexp = null; + } + else { + fileRegexp = Pattern.compile(files); + } checkPattern = checks; - checkRegexp = CommonUtils.createPattern(checks); - } - - /** - * Set the module id for filtering. Cannot be null. - * @param moduleId the id - */ - public void setModuleId(final String moduleId) { - this.moduleId = moduleId; - } - - /** - * Sets the CSV values and ranges for line number filtering. - * E.g. "1,7-15,18". - * @param lines CSV values and ranges for line number filtering. - */ - public void setLines(String lines) { + if (checks == null) { + checkRegexp = null; + } + else { + checkRegexp = Pattern.compile(checks); + } + messagePattern = message; + if (message == null) { + messageRegexp = null; + } + else { + messageRegexp = Pattern.compile(message); + } + moduleId = modId; linesCsv = lines; if (lines == null) { lineFilter = null; @@ -109,14 +116,6 @@ else { lineFilter = new CsvFilter(lines); } - } - - /** - * Sets the CSV values and ranges for column number filtering. - * E.g. "1,7-15,18". - * @param columns CSV values and ranges for column number filtering. - */ - public void setColumns(String columns) { columnsCsv = columns; if (columns == null) { columnFilter = null; @@ -128,15 +127,9 @@ @Override public boolean accept(AuditEvent event) { - // reject if file or check module mismatch? - if (isFileNameAndModuleNotMatching(event)) { - return true; - } - - // reject if no line/column matching - return (lineFilter != null || columnFilter != null) - && (lineFilter == null || !lineFilter.accept(event.getLine())) - && (columnFilter == null || !columnFilter.accept(event.getColumn())); + return isFileNameAndModuleNotMatching(event) + || !isMessageNameMatching(event) + || isLineAndColumnMatch(event); } /** @@ -146,15 +139,36 @@ */ private boolean isFileNameAndModuleNotMatching(AuditEvent event) { return event.getFileName() == null - || !fileRegexp.matcher(event.getFileName()).find() + || fileRegexp != null && !fileRegexp.matcher(event.getFileName()).find() || event.getLocalizedMessage() == null || moduleId != null && !moduleId.equals(event.getModuleId()) || checkRegexp != null && !checkRegexp.matcher(event.getSourceName()).find(); } + /** + * Is matching by message. + * @param event event + * @return true is matching or not set. + */ + private boolean isMessageNameMatching(AuditEvent event) { + return messageRegexp == null || messageRegexp.matcher(event.getMessage()).find(); + } + + /** + * Whether line and column match. + * @param event event to process. + * @return true if line and column match. + */ + private boolean isLineAndColumnMatch(AuditEvent event) { + return (lineFilter != null || columnFilter != null) + && (lineFilter == null || !lineFilter.accept(event.getLine())) + && (columnFilter == null || !columnFilter.accept(event.getColumn())); + } + @Override public int hashCode() { - return Objects.hash(filePattern, checkPattern, moduleId, linesCsv, columnsCsv); + return Objects.hash(filePattern, checkPattern, messagePattern, moduleId, linesCsv, + columnsCsv); } @Override @@ -168,8 +182,10 @@ final SuppressElement suppressElement = (SuppressElement) other; return Objects.equals(filePattern, suppressElement.filePattern) && Objects.equals(checkPattern, suppressElement.checkPattern) + && Objects.equals(messagePattern, suppressElement.messagePattern) && Objects.equals(moduleId, suppressElement.moduleId) && Objects.equals(linesCsv, suppressElement.linesCsv) && Objects.equals(columnsCsv, suppressElement.columnsCsv); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionCommentFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionCommentFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionCommentFilter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionCommentFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,6 +20,7 @@ package com.puppycrawl.tools.checkstyle.filters; import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -28,15 +29,12 @@ import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; -import org.apache.commons.beanutils.ConversionException; - -import com.google.common.collect.Lists; -import com.puppycrawl.tools.checkstyle.api.AuditEvent; +import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; +import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; import com.puppycrawl.tools.checkstyle.api.AutomaticBean; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.FileContents; -import com.puppycrawl.tools.checkstyle.api.Filter; import com.puppycrawl.tools.checkstyle.api.TextBlock; -import com.puppycrawl.tools.checkstyle.checks.FileContentsHolder; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** @@ -52,46 +50,57 @@ * This is sometimes superior to a separate suppressions file, which * must be kept up-to-date as the source file is edited. *

    - *

    - * Usage: - * This check only works in conjunction with the FileContentsHolder module - * since that module makes the suppression comments in the .java - * files available sub rosa. - *

    * @author Mike McMahon * @author Rick Giles - * @see FileContentsHolder */ public class SuppressionCommentFilter extends AutomaticBean - implements Filter { + implements TreeWalkerFilter { + + /** + * Enum to be used for switching checkstyle reporting for tags. + */ + public enum TagType { + + /** + * Switch reporting on. + */ + ON, + /** + * Switch reporting off. + */ + OFF + + } /** Turns checkstyle reporting off. */ - private static final String DEFAULT_OFF_FORMAT = "CHECKSTYLE\\:OFF"; + private static final String DEFAULT_OFF_FORMAT = "CHECKSTYLE:OFF"; /** Turns checkstyle reporting on. */ - private static final String DEFAULT_ON_FORMAT = "CHECKSTYLE\\:ON"; + private static final String DEFAULT_ON_FORMAT = "CHECKSTYLE:ON"; /** Control all checks. */ private static final String DEFAULT_CHECK_FORMAT = ".*"; /** Tagged comments. */ - private final List tags = Lists.newArrayList(); + private final List tags = new ArrayList<>(); /** Whether to look in comments of the C type. */ private boolean checkC = true; /** Whether to look in comments of the C++ type. */ + // -@cs[AbbreviationAsWordInName] we can not change it as, + // Check property is a part of API (used in configurations) private boolean checkCPP = true; /** Parsed comment regexp that turns checkstyle reporting off. */ - private Pattern offRegexp; + private Pattern offCommentFormat = Pattern.compile(DEFAULT_OFF_FORMAT); /** Parsed comment regexp that turns checkstyle reporting on. */ - private Pattern onRegexp; + private Pattern onCommentFormat = Pattern.compile(DEFAULT_ON_FORMAT); /** The check format to suppress. */ - private String checkFormat; + private String checkFormat = DEFAULT_CHECK_FORMAT; /** The message format to suppress. */ private String messageFormat; @@ -100,50 +109,39 @@ * References the current FileContents for this filter. * Since this is a weak reference to the FileContents, the FileContents * can be reclaimed as soon as the strong references in TreeWalker - * and FileContentsHolder are reassigned to the next FileContents, - * at which time filtering for the current FileContents is finished. + * are reassigned to the next FileContents, at which time filtering for + * the current FileContents is finished. */ private WeakReference fileContentsReference = new WeakReference<>(null); /** - * Constructs a SuppressionCommentFilter. - * Initializes comment on, comment off, and check formats - * to defaults. - */ - public SuppressionCommentFilter() { - setOnCommentFormat(DEFAULT_ON_FORMAT); - setOffCommentFormat(DEFAULT_OFF_FORMAT); - checkFormat = DEFAULT_CHECK_FORMAT; - } - - /** * Set the format for a comment that turns off reporting. - * @param format a {@code String} value. - * @throws ConversionException if unable to create Pattern object. + * @param pattern a pattern. */ - public final void setOffCommentFormat(String format) { - offRegexp = CommonUtils.createPattern(format); + public final void setOffCommentFormat(Pattern pattern) { + offCommentFormat = pattern; } /** * Set the format for a comment that turns on reporting. - * @param format a {@code String} value - * @throws ConversionException if unable to create Pattern object. + * @param pattern a pattern. */ - public final void setOnCommentFormat(String format) { - onRegexp = CommonUtils.createPattern(format); + public final void setOnCommentFormat(Pattern pattern) { + onCommentFormat = pattern; } /** + * Returns FileContents for this filter. * @return the FileContents for this filter. */ - public FileContents getFileContents() { + private FileContents getFileContents() { return fileContentsReference.get(); } /** * Set the FileContents for this filter. * @param fileContents the FileContents for this filter. + * @noinspection WeakerAccess */ public void setFileContents(FileContents fileContents) { fileContentsReference = new WeakReference<>(fileContents); @@ -169,6 +167,8 @@ * Set whether to look in C++ comments. * @param checkCpp {@code true} if C++ comments are checked. */ + // -@cs[AbbreviationAsWordInName] We can not change it as, + // check's property is a part of API (used in configurations). public void setCheckCPP(boolean checkCpp) { checkCPP = checkCpp; } @@ -182,22 +182,25 @@ } @Override - public boolean accept(AuditEvent event) { + protected void finishLocalSetup() throws CheckstyleException { + // No code by default + } + + @Override + public boolean accept(TreeWalkerAuditEvent event) { boolean accepted = true; if (event.getLocalizedMessage() != null) { // Lazy update. If the first event for the current file, update file // contents and tag suppressions - final FileContents currentContents = FileContentsHolder.getContents(); + final FileContents currentContents = event.getFileContents(); - if (currentContents != null) { - if (getFileContents() != currentContents) { - setFileContents(currentContents); - tagSuppressions(); - } - final Tag matchTag = findNearestMatch(event); - accepted = matchTag == null || matchTag.isReportingOn(); + if (getFileContents() != currentContents) { + setFileContents(currentContents); + tagSuppressions(); } + final Tag matchTag = findNearestMatch(event); + accepted = matchTag == null || matchTag.getTagType() == TagType.ON; } return accepted; } @@ -205,10 +208,10 @@ /** * Finds the nearest comment text tag that matches an audit event. * The nearest tag is before the line and column of the event. - * @param event the {@code AuditEvent} to match. + * @param event the {@code TreeWalkerAuditEvent} to match. * @return The {@code Tag} nearest event. */ - private Tag findNearestMatch(AuditEvent event) { + private Tag findNearestMatch(TreeWalkerAuditEvent event) { Tag result = null; for (Tag tag : tags) { if (tag.getLine() > event.getLine() @@ -231,14 +234,12 @@ tags.clear(); final FileContents contents = getFileContents(); if (checkCPP) { - tagSuppressions(contents.getCppComments().values()); + tagSuppressions(contents.getSingleLineComments().values()); } if (checkC) { final Collection> cComments = contents - .getCComments().values(); - for (List element : cComments) { - tagSuppressions(element); - } + .getBlockComments().values(); + cComments.forEach(this::tagSuppressions); } Collections.sort(tags); } @@ -267,14 +268,14 @@ * @param column the column number of text. */ private void tagCommentLine(String text, int line, int column) { - final Matcher offMatcher = offRegexp.matcher(text); + final Matcher offMatcher = offCommentFormat.matcher(text); if (offMatcher.find()) { - addTag(offMatcher.group(0), line, column, false); + addTag(offMatcher.group(0), line, column, TagType.OFF); } else { - final Matcher onMatcher = onRegexp.matcher(text); + final Matcher onMatcher = onCommentFormat.matcher(text); if (onMatcher.find()) { - addTag(onMatcher.group(0), line, column, true); + addTag(onMatcher.group(0), line, column, TagType.ON); } } } @@ -286,7 +287,7 @@ * @param column the column number of the tag. * @param reportingOn {@code true} if the tag turns checkstyle reporting on. */ - private void addTag(String text, int line, int column, boolean reportingOn) { + private void addTag(String text, int line, int column, TagType reportingOn) { final Tag tag = new Tag(line, column, text, reportingOn, this); tags.add(tag); } @@ -298,6 +299,7 @@ */ public static class Tag implements Comparable { + /** The text of the tag. */ private final String text; @@ -308,7 +310,7 @@ private final int column; /** Determines whether the suppression turns checkstyle reporting on. */ - private final boolean reportingOn; + private final TagType tagType; /** The parsed check regexp, expanded for the text of this tag. */ private final Pattern tagCheckRegexp; @@ -321,56 +323,56 @@ * @param line the line number. * @param column the column number. * @param text the text of the suppression. - * @param reportingOn {@code true} if the tag turns checkstyle reporting. + * @param tagType {@code ON} if the tag turns checkstyle reporting. * @param filter the {@code SuppressionCommentFilter} with the context - * @throws ConversionException if unable to parse expanded text. + * @throws IllegalArgumentException if unable to parse expanded text. */ - public Tag(int line, int column, String text, boolean reportingOn, + public Tag(int line, int column, String text, TagType tagType, SuppressionCommentFilter filter) { this.line = line; this.column = column; this.text = text; - this.reportingOn = reportingOn; + this.tagType = tagType; //Expand regexp for check and message //Does not intern Patterns with Utils.getPattern() String format = ""; try { - if (reportingOn) { + if (this.tagType == TagType.ON) { format = CommonUtils.fillTemplateWithStringsByRegexp( - filter.checkFormat, text, filter.onRegexp); + filter.checkFormat, text, filter.onCommentFormat); tagCheckRegexp = Pattern.compile(format); if (filter.messageFormat == null) { tagMessageRegexp = null; } else { format = CommonUtils.fillTemplateWithStringsByRegexp( - filter.messageFormat, text, filter.onRegexp); + filter.messageFormat, text, filter.onCommentFormat); tagMessageRegexp = Pattern.compile(format); } } else { format = CommonUtils.fillTemplateWithStringsByRegexp( - filter.checkFormat, text, filter.offRegexp); + filter.checkFormat, text, filter.offCommentFormat); tagCheckRegexp = Pattern.compile(format); if (filter.messageFormat == null) { tagMessageRegexp = null; } else { format = CommonUtils.fillTemplateWithStringsByRegexp( - filter.messageFormat, text, filter.offRegexp); + filter.messageFormat, text, filter.offCommentFormat); tagMessageRegexp = Pattern.compile(format); } } } catch (final PatternSyntaxException ex) { - throw new ConversionException( - "unable to parse expanded comment " + format, - ex); + throw new IllegalArgumentException( + "unable to parse expanded comment " + format, ex); } } /** + * Returns line number of the tag in the source file. * @return the line number of the tag in the source file. */ public int getLine() { @@ -390,10 +392,10 @@ /** * Determines whether the suppression turns checkstyle reporting on or * off. - * @return {@code true}if the suppression turns reporting on. + * @return {@code ON} if the suppression turns reporting on. */ - public boolean isReportingOn() { - return reportingOn; + public TagType getTagType() { + return tagType; } /** @@ -406,11 +408,14 @@ */ @Override public int compareTo(Tag object) { + final int result; if (line == object.line) { - return Integer.compare(column, object.column); + result = Integer.compare(column, object.column); } - - return Integer.compare(line, object.line); + else { + result = Integer.compare(line, object.line); + } + return result; } @Override @@ -424,22 +429,24 @@ final Tag tag = (Tag) other; return Objects.equals(line, tag.line) && Objects.equals(column, tag.column) - && Objects.equals(reportingOn, tag.reportingOn) - && Objects.equals(text, tag.text); + && Objects.equals(tagType, tag.tagType) + && Objects.equals(text, tag.text) + && Objects.equals(tagCheckRegexp, tag.tagCheckRegexp) + && Objects.equals(tagMessageRegexp, tag.tagMessageRegexp); } @Override public int hashCode() { - return Objects.hash(text, line, column, reportingOn); + return Objects.hash(text, line, column, tagType, tagCheckRegexp, tagMessageRegexp); } /** * Determines whether the source of an audit event * matches the text of this tag. - * @param event the {@code AuditEvent} to check. + * @param event the {@code TreeWalkerAuditEvent} to check. * @return true if the source of event matches the text of this tag. */ - public boolean isMatch(AuditEvent event) { + public boolean isMatch(TreeWalkerAuditEvent event) { boolean match = false; final Matcher tagMatcher = tagCheckRegexp.matcher(event.getSourceName()); if (tagMatcher.find()) { @@ -459,9 +466,15 @@ } @Override - public final String toString() { - return "Tag[line=" + line + "; col=" + column - + "; on=" + reportingOn + "; text='" + text + "']"; + public String toString() { + return "Tag[text='" + text + '\'' + + ", line=" + line + + ", column=" + column + + ", type=" + tagType + + ", tagCheckRegexp=" + tagCheckRegexp + + ", tagMessageRegexp=" + tagMessageRegexp + ']'; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -19,18 +19,17 @@ package com.puppycrawl.tools.checkstyle.filters; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URL; +import java.util.Collections; import java.util.Objects; +import java.util.Set; import com.puppycrawl.tools.checkstyle.api.AuditEvent; import com.puppycrawl.tools.checkstyle.api.AutomaticBean; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder; import com.puppycrawl.tools.checkstyle.api.Filter; import com.puppycrawl.tools.checkstyle.api.FilterSet; -import com.puppycrawl.tools.checkstyle.utils.CommonUtils; +import com.puppycrawl.tools.checkstyle.utils.FilterUtils; /** *

    @@ -39,11 +38,11 @@ *

    * @author Rick Giles * @author liscju + * @noinspection NonFinalFieldReferenceInEquals, NonFinalFieldReferencedInHashCode */ -public class SuppressionFilter - extends AutomaticBean - implements Filter { - /** Filename of supression file. */ +public class SuppressionFilter extends AutomaticBean implements Filter, ExternalResourceHolder { + + /** Filename of suppression file. */ private String file; /** Tells whether config file existence is optional. */ private boolean optional; @@ -51,7 +50,7 @@ private FilterSet filters = new FilterSet(); /** - * Sets name of the supression file. + * Sets name of the suppression file. * @param fileName name of the suppressions file. */ public void setFile(String fileName) { @@ -92,7 +91,7 @@ protected void finishLocalSetup() throws CheckstyleException { if (file != null) { if (optional) { - if (suppressionSourceExists(file)) { + if (FilterUtils.isFileExists(file)) { filters = SuppressionsLoader.loadSuppressions(file); } else { @@ -105,32 +104,9 @@ } } - /** - * Checks if suppression source with given fileName exists. - * @param fileName name of the suppressions file. - * @return true if suppression file exists, otherwise false - */ - private static boolean suppressionSourceExists(String fileName) { - boolean suppressionSourceExists = true; - InputStream sourceInput = null; - try { - final URI uriByFilename = CommonUtils.getUriByFilename(fileName); - final URL url = uriByFilename.toURL(); - sourceInput = url.openStream(); - } - catch (CheckstyleException | IOException ignored) { - suppressionSourceExists = false; - } - finally { - if (sourceInput != null) { - try { - sourceInput.close(); - } - catch (IOException ignored) { - suppressionSourceExists = false; - } - } - } - return suppressionSourceExists; + @Override + public Set getExternalResourceLocations() { + return Collections.singleton(file); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionsLoader.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionsLoader.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionsLoader.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionsLoader.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -22,8 +22,11 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.net.URI; +import java.util.HashMap; +import java.util.HashSet; import java.util.Locale; import java.util.Map; +import java.util.Set; import java.util.regex.PatternSyntaxException; import javax.xml.parsers.ParserConfigurationException; @@ -32,8 +35,8 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; -import com.google.common.collect.Maps; -import com.puppycrawl.tools.checkstyle.api.AbstractLoader; +import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; +import com.puppycrawl.tools.checkstyle.XmlLoader; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.FilterSet; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; @@ -43,21 +46,54 @@ * @author Rick Giles */ public final class SuppressionsLoader - extends AbstractLoader { + extends XmlLoader { + /** The public ID for the configuration dtd. */ private static final String DTD_PUBLIC_ID_1_0 = "-//Puppy Crawl//DTD Suppressions 1.0//EN"; /** The resource for the configuration dtd. */ - private static final String DTD_RESOURCE_NAME_1_0 = + private static final String DTD_SUPPRESSIONS_NAME_1_0 = "com/puppycrawl/tools/checkstyle/suppressions_1_0.dtd"; /** The public ID for the configuration dtd. */ private static final String DTD_PUBLIC_ID_1_1 = "-//Puppy Crawl//DTD Suppressions 1.1//EN"; /** The resource for the configuration dtd. */ - private static final String DTD_RESOURCE_NAME_1_1 = + private static final String DTD_SUPPRESSIONS_NAME_1_1 = "com/puppycrawl/tools/checkstyle/suppressions_1_1.dtd"; + /** The public ID for the configuration dtd. */ + private static final String DTD_PUBLIC_ID_1_2 = + "-//Puppy Crawl//DTD Suppressions 1.2//EN"; + /** The resource for the configuration dtd. */ + private static final String DTD_SUPPRESSIONS_NAME_1_2 = + "com/puppycrawl/tools/checkstyle/suppressions_1_2.dtd"; + /** The public ID for the configuration dtd. */ + private static final String DTD_PUBLIC_ID_1_1_XPATH = + "-//Puppy Crawl//DTD Suppressions Xpath Experimental 1.1//EN"; + /** The resource for the configuration dtd. */ + private static final String DTD_SUPPRESSIONS_NAME_1_1_XPATH = + "com/puppycrawl/tools/checkstyle/suppressions_1_1_xpath_experimental.dtd"; + /** The public ID for the configuration dtd. */ + private static final String DTD_PUBLIC_ID_1_2_XPATH = + "-//Puppy Crawl//DTD Suppressions Xpath Experimental 1.2//EN"; + /** The resource for the configuration dtd. */ + private static final String DTD_SUPPRESSIONS_NAME_1_2_XPATH = + "com/puppycrawl/tools/checkstyle/suppressions_1_2_xpath_experimental.dtd"; /** File search error message. **/ private static final String UNABLE_TO_FIND_ERROR_MESSAGE = "Unable to find: "; + /** String literal for attribute name. **/ + private static final String ATTRIBUTE_NAME_FILES = "files"; + /** String literal for attribute name. **/ + private static final String ATTRIBUTE_NAME_CHECKS = "checks"; + /** String literal for attribute name. **/ + private static final String ATTRIBUTE_NAME_MESSAGE = "message"; + /** String literal for attribute name. **/ + private static final String ATTRIBUTE_NAME_ID = "id"; + /** String literal for attribute name. **/ + private static final String ATTRIBUTE_NAME_QUERY = "query"; + /** String literal for attribute name. **/ + private static final String ATTRIBUTE_NAME_LINES = "lines"; + /** String literal for attribute name. **/ + private static final String ATTRIBUTE_NAME_COLUMNS = "columns"; /** * The filter chain to return in getAFilterChain(), @@ -66,12 +102,17 @@ private final FilterSet filterChain = new FilterSet(); /** + * The set of the {@code TreeWalkerFilter} filters. Being filled during parsing. + */ + private final Set treeWalkerFilters = new HashSet<>(); + + /** * Creates a new {@code SuppressionsLoader} instance. * @throws ParserConfigurationException if an error occurs * @throws SAXException if an error occurs */ private SuppressionsLoader() - throws ParserConfigurationException, SAXException { + throws ParserConfigurationException, SAXException { super(createIdToResourceNameMap()); } @@ -80,38 +121,74 @@ String localName, String qName, Attributes attributes) - throws SAXException { + throws SAXException { if ("suppress".equals(qName)) { //add SuppressElement filter to the filter chain - final String checks = attributes.getValue("checks"); - final String modId = attributes.getValue("id"); - if (checks == null && modId == null) { - throw new SAXException("missing checks and id attribute"); - } - final SuppressElement suppress; - try { - final String files = attributes.getValue("files"); - suppress = new SuppressElement(files); - if (modId != null) { - suppress.setModuleId(modId); - } - if (checks != null) { - suppress.setChecks(checks); - } - } - catch (final PatternSyntaxException ex) { - throw new SAXException("invalid files or checks format", ex); - } - final String lines = attributes.getValue("lines"); - if (lines != null) { - suppress.setLines(lines); - } - final String columns = attributes.getValue("columns"); - if (columns != null) { - suppress.setColumns(columns); - } + final SuppressElement suppress = getSuppressElement(attributes); filterChain.addFilter(suppress); } + else if ("suppress-xpath".equals(qName)) { + final XpathFilter filter = getXpathFilter(attributes); + treeWalkerFilters.add(filter); + } + } + + /** + * Returns the suppress element, initialized from given attributes. + * @param attributes the attributes of xml-tag "", specified inside + * suppression file. + * @return the suppress element + * @throws SAXException if an error occurs. + */ + private static SuppressElement getSuppressElement(Attributes attributes) throws SAXException { + final String checks = attributes.getValue(ATTRIBUTE_NAME_CHECKS); + final String modId = attributes.getValue(ATTRIBUTE_NAME_ID); + final String message = attributes.getValue(ATTRIBUTE_NAME_MESSAGE); + if (checks == null && modId == null && message == null) { + // -@cs[IllegalInstantiation] SAXException is in the overridden method signature + throw new SAXException("missing checks or id or message attribute"); + } + final SuppressElement suppress; + try { + final String files = attributes.getValue(ATTRIBUTE_NAME_FILES); + final String lines = attributes.getValue(ATTRIBUTE_NAME_LINES); + final String columns = attributes.getValue(ATTRIBUTE_NAME_COLUMNS); + suppress = new SuppressElement(files, checks, message, modId, lines, columns); + } + catch (final PatternSyntaxException ex) { + // -@cs[IllegalInstantiation] SAXException is in the overridden method signature + throw new SAXException("invalid files or checks or message format", ex); + } + return suppress; + } + + /** + * Returns the xpath filter, initialized from given attributes. + * @param attributes the attributes of xml-tag "", + * specified inside suppression file. + * @return the xpath filter + * @throws SAXException if an error occurs. + */ + private static XpathFilter getXpathFilter(Attributes attributes) throws SAXException { + final String checks = attributes.getValue(ATTRIBUTE_NAME_CHECKS); + final String modId = attributes.getValue(ATTRIBUTE_NAME_ID); + final String message = attributes.getValue(ATTRIBUTE_NAME_MESSAGE); + if (checks == null && modId == null && message == null) { + // -@cs[IllegalInstantiation] SAXException is in the overridden method signature + throw new SAXException("missing checks or id or message attribute for suppress-xpath"); + } + final XpathFilter filter; + try { + final String files = attributes.getValue(ATTRIBUTE_NAME_FILES); + final String xpathQuery = attributes.getValue(ATTRIBUTE_NAME_QUERY); + filter = new XpathFilter(files, checks, message, modId, xpathQuery); + } + catch (final PatternSyntaxException ex) { + // -@cs[IllegalInstantiation] SAXException is in the overridden method signature + throw new SAXException("invalid files or checks or message format for suppress-xpath", + ex); + } + return filter; } /** @@ -121,7 +198,7 @@ * @throws CheckstyleException if an error occurs. */ public static FilterSet loadSuppressions(String filename) - throws CheckstyleException { + throws CheckstyleException { // figure out if this is a File or a URL final URI uri = CommonUtils.getUriByFilename(filename); final InputSource source = new InputSource(uri.toString()); @@ -137,12 +214,51 @@ */ private static FilterSet loadSuppressions( InputSource source, String sourceName) - throws CheckstyleException { + throws CheckstyleException { + return getSuppressionLoader(source, sourceName).filterChain; + } + + /** + * Returns the suppression {@code TreeWalker} filters in a specified file. + * @param filename name of the suppressions file. + * @return the set of xpath suppression elements specified in the file. + * @throws CheckstyleException if an error occurs. + */ + public static Set loadXpathSuppressions(String filename) + throws CheckstyleException { + // figure out if this is a File or a URL + final URI uri = CommonUtils.getUriByFilename(filename); + final InputSource source = new InputSource(uri.toString()); + return loadXpathSuppressions(source, filename); + } + + /** + * Returns the suppression {@code TreeWalker} filters in a specified source. + * @param source the source for the suppressions. + * @param sourceName the name of the source. + * @return the set of xpath suppression elements specified in source. + * @throws CheckstyleException if an error occurs. + */ + private static Set loadXpathSuppressions( + InputSource source, String sourceName) + throws CheckstyleException { + return getSuppressionLoader(source, sourceName).treeWalkerFilters; + } + + /** + * Parses specified source and returns the suppression loader. + * @param source the source for the suppressions. + * @param sourceName the name of the source. + * @return the suppression loader + * @throws CheckstyleException if an error occurs. + */ + private static SuppressionsLoader getSuppressionLoader(InputSource source, String sourceName) + throws CheckstyleException { try { final SuppressionsLoader suppressionsLoader = new SuppressionsLoader(); suppressionsLoader.parseInputSource(source); - return suppressionsLoader.filterChain; + return suppressionsLoader; } catch (final FileNotFoundException ex) { throw new CheckstyleException(UNABLE_TO_FIND_ERROR_MESSAGE + sourceName, ex); @@ -167,9 +283,13 @@ * @return map between local resources and dtd ids. */ private static Map createIdToResourceNameMap() { - final Map map = Maps.newHashMap(); - map.put(DTD_PUBLIC_ID_1_0, DTD_RESOURCE_NAME_1_0); - map.put(DTD_PUBLIC_ID_1_1, DTD_RESOURCE_NAME_1_1); + final Map map = new HashMap<>(); + map.put(DTD_PUBLIC_ID_1_0, DTD_SUPPRESSIONS_NAME_1_0); + map.put(DTD_PUBLIC_ID_1_1, DTD_SUPPRESSIONS_NAME_1_1); + map.put(DTD_PUBLIC_ID_1_2, DTD_SUPPRESSIONS_NAME_1_2); + map.put(DTD_PUBLIC_ID_1_1_XPATH, DTD_SUPPRESSIONS_NAME_1_1_XPATH); + map.put(DTD_PUBLIC_ID_1_2_XPATH, DTD_SUPPRESSIONS_NAME_1_2_XPATH); return map; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathFilter.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionXpathFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,118 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.filters; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; +import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; +import com.puppycrawl.tools.checkstyle.api.AutomaticBean; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder; +import com.puppycrawl.tools.checkstyle.utils.FilterUtils; + +/** + * This filter accepts TreeWalkerAuditEvents according to file, check and xpath query, + * as specified in a suppression file. + * + * @author Timur Tibeyev. + * @noinspection NonFinalFieldReferenceInEquals, NonFinalFieldReferencedInHashCode + */ +public class SuppressionXpathFilter extends AutomaticBean implements + TreeWalkerFilter, ExternalResourceHolder { + + /** Filename of suppression file. */ + private String file; + /** Tells whether config file existence is optional. */ + private boolean optional; + /** Set of individual xpath suppresses. */ + private Set filters = new HashSet<>(); + + /** + * Sets name of the suppression file. + * @param fileName name of the suppressions file. + */ + public void setFile(String fileName) { + file = fileName; + } + + /** + * Sets whether config file existence is optional. + * @param optional tells if config file existence is optional. + */ + public void setOptional(boolean optional) { + this.optional = optional; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + final SuppressionXpathFilter suppressionXpathFilter = (SuppressionXpathFilter) obj; + return Objects.equals(filters, suppressionXpathFilter.filters); + } + + @Override + public int hashCode() { + return Objects.hash(filters); + } + + @Override + public boolean accept(TreeWalkerAuditEvent treeWalkerAuditEvent) { + boolean result = true; + for (TreeWalkerFilter filter : filters) { + if (!filter.accept(treeWalkerAuditEvent)) { + result = false; + break; + } + } + return result; + } + + @Override + public Set getExternalResourceLocations() { + return Collections.singleton(file); + } + + @Override + protected void finishLocalSetup() throws CheckstyleException { + if (file != null) { + if (optional) { + if (FilterUtils.isFileExists(file)) { + filters = SuppressionsLoader.loadXpathSuppressions(file); + } + else { + filters = new HashSet<>(); + } + } + else { + filters = SuppressionsLoader.loadXpathSuppressions(file); + } + } + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWarningsFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWarningsFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWarningsFilter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWarningsFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,6 +21,7 @@ import com.puppycrawl.tools.checkstyle.api.AuditEvent; import com.puppycrawl.tools.checkstyle.api.AutomaticBean; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Filter; import com.puppycrawl.tools.checkstyle.checks.SuppressWarningsHolder; @@ -32,8 +33,15 @@ public class SuppressWarningsFilter extends AutomaticBean implements Filter { + + @Override + protected void finishLocalSetup() throws CheckstyleException { + // No code by default + } + @Override public boolean accept(AuditEvent event) { return !SuppressWarningsHolder.isSuppressed(event); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWithNearbyCommentFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWithNearbyCommentFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWithNearbyCommentFilter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWithNearbyCommentFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,23 +20,20 @@ package com.puppycrawl.tools.checkstyle.filters; import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; -import org.apache.commons.beanutils.ConversionException; - -import com.google.common.collect.Lists; -import com.puppycrawl.tools.checkstyle.api.AuditEvent; +import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; +import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; import com.puppycrawl.tools.checkstyle.api.AutomaticBean; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.FileContents; -import com.puppycrawl.tools.checkstyle.api.Filter; import com.puppycrawl.tools.checkstyle.api.TextBlock; -import com.puppycrawl.tools.checkstyle.checks.FileContentsHolder; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** @@ -75,7 +72,7 @@ */ public class SuppressWithNearbyCommentFilter extends AutomaticBean - implements Filter { + implements TreeWalkerFilter { /** Format to turns checkstyle reporting off. */ private static final String DEFAULT_COMMENT_FORMAT = @@ -88,65 +85,57 @@ private static final String DEFAULT_INFLUENCE_FORMAT = "0"; /** Tagged comments. */ - private final List tags = Lists.newArrayList(); + private final List tags = new ArrayList<>(); /** Whether to look for trigger in C-style comments. */ private boolean checkC = true; /** Whether to look for trigger in C++-style comments. */ + // -@cs[AbbreviationAsWordInName] We can not change it as, + // check's property is a part of API (used in configurations). private boolean checkCPP = true; /** Parsed comment regexp that marks checkstyle suppression region. */ - private Pattern commentRegexp; + private Pattern commentFormat = Pattern.compile(DEFAULT_COMMENT_FORMAT); /** The comment pattern that triggers suppression. */ - private String checkFormat; + private String checkFormat = DEFAULT_CHECK_FORMAT; /** The message format to suppress. */ private String messageFormat; /** The influence of the suppression comment. */ - private String influenceFormat; + private String influenceFormat = DEFAULT_INFLUENCE_FORMAT; /** * References the current FileContents for this filter. * Since this is a weak reference to the FileContents, the FileContents * can be reclaimed as soon as the strong references in TreeWalker - * and FileContentsHolder are reassigned to the next FileContents, - * at which time filtering for the current FileContents is finished. + * are reassigned to the next FileContents, at which time filtering for + * the current FileContents is finished. */ private WeakReference fileContentsReference = new WeakReference<>(null); /** - * Constructs a SuppressionCommentFilter. - * Initializes comment on, comment off, and check formats - * to defaults. - */ - public SuppressWithNearbyCommentFilter() { - setCommentFormat(DEFAULT_COMMENT_FORMAT); - checkFormat = DEFAULT_CHECK_FORMAT; - influenceFormat = DEFAULT_INFLUENCE_FORMAT; - } - - /** * Set the format for a comment that turns off reporting. - * @param format a {@code String} value. - * @throws ConversionException if unable to create Pattern object. + * @param pattern a pattern. */ - public final void setCommentFormat(String format) { - commentRegexp = CommonUtils.createPattern(format); + public final void setCommentFormat(Pattern pattern) { + commentFormat = pattern; } /** + * Returns FileContents for this filter. * @return the FileContents for this filter. */ - public FileContents getFileContents() { + private FileContents getFileContents() { return fileContentsReference.get(); } /** * Set the FileContents for this filter. * @param fileContents the FileContents for this filter. + * @noinspection WeakerAccess */ public void setFileContents(FileContents fileContents) { fileContentsReference = new WeakReference<>(fileContents); @@ -180,6 +169,8 @@ * Set whether to look in C++ comments. * @param checkCpp {@code true} if C++ comments are checked. */ + // -@cs[AbbreviationAsWordInName] We can not change it as, + // check's property is a part of API (used in configurations). public void setCheckCPP(boolean checkCpp) { checkCPP = checkCpp; } @@ -193,22 +184,25 @@ } @Override - public boolean accept(AuditEvent event) { + protected void finishLocalSetup() throws CheckstyleException { + // No code by default + } + + @Override + public boolean accept(TreeWalkerAuditEvent event) { boolean accepted = true; if (event.getLocalizedMessage() != null) { // Lazy update. If the first event for the current file, update file // contents and tag suppressions - final FileContents currentContents = FileContentsHolder.getContents(); + final FileContents currentContents = event.getFileContents(); - if (currentContents != null) { - if (getFileContents() != currentContents) { - setFileContents(currentContents); - tagSuppressions(); - } - if (matchesTag(event)) { - accepted = false; - } + if (getFileContents() != currentContents) { + setFileContents(currentContents); + tagSuppressions(); + } + if (matchesTag(event)) { + accepted = false; } } return accepted; @@ -216,16 +210,18 @@ /** * Whether current event matches any tag from {@link #tags}. - * @param event AuditEvent to test match on {@link #tags}. + * @param event TreeWalkerAuditEvent to test match on {@link #tags}. * @return true if event matches any tag from {@link #tags}, false otherwise. */ - private boolean matchesTag(AuditEvent event) { + private boolean matchesTag(TreeWalkerAuditEvent event) { + boolean result = false; for (final Tag tag : tags) { if (tag.isMatch(event)) { - return true; + result = true; + break; } } - return false; + return result; } /** @@ -236,16 +232,13 @@ tags.clear(); final FileContents contents = getFileContents(); if (checkCPP) { - tagSuppressions(contents.getCppComments().values()); + tagSuppressions(contents.getSingleLineComments().values()); } if (checkC) { final Collection> cComments = - contents.getCComments().values(); - for (final List element : cComments) { - tagSuppressions(element); - } + contents.getBlockComments().values(); + cComments.forEach(this::tagSuppressions); } - Collections.sort(tags); } /** @@ -271,7 +264,7 @@ * @param line the line number of text. */ private void tagCommentLine(String text, int line) { - final Matcher matcher = commentRegexp.matcher(text); + final Matcher matcher = commentFormat.matcher(text); if (matcher.find()) { addTag(matcher.group(0), line); } @@ -290,7 +283,8 @@ /** * A Tag holds a suppression comment and its location. */ - public static class Tag implements Comparable { + public static class Tag { + /** The text of the tag. */ private final String text; @@ -311,7 +305,7 @@ * @param text the text of the suppression. * @param line the line number. * @param filter the {@code SuppressWithNearbyCommentFilter} with the context - * @throws ConversionException if unable to parse expanded text. + * @throws IllegalArgumentException if unable to parse expanded text. */ public Tag(String text, int line, SuppressWithNearbyCommentFilter filter) { this.text = text; @@ -321,31 +315,25 @@ String format = ""; try { format = CommonUtils.fillTemplateWithStringsByRegexp( - filter.checkFormat, text, filter.commentRegexp); + filter.checkFormat, text, filter.commentFormat); tagCheckRegexp = Pattern.compile(format); if (filter.messageFormat == null) { tagMessageRegexp = null; } else { format = CommonUtils.fillTemplateWithStringsByRegexp( - filter.messageFormat, text, filter.commentRegexp); + filter.messageFormat, text, filter.commentFormat); tagMessageRegexp = Pattern.compile(format); } format = CommonUtils.fillTemplateWithStringsByRegexp( - filter.influenceFormat, text, filter.commentRegexp); - final int influence; - try { - if (CommonUtils.startsWithChar(format, '+')) { - format = format.substring(1); - } - influence = Integer.parseInt(format); - } - catch (final NumberFormatException ex) { - throw new ConversionException( - "unable to parse influence from '" + text - + "' using " + filter.influenceFormat, ex); + filter.influenceFormat, text, filter.commentFormat); + + if (CommonUtils.startsWithChar(format, '+')) { + format = format.substring(1); } - if (influence >= 0) { + final int influence = parseInfluence(format, filter.influenceFormat, text); + + if (influence >= 1) { firstLine = line; lastLine = line + influence; } @@ -355,27 +343,27 @@ } } catch (final PatternSyntaxException ex) { - throw new ConversionException( - "unable to parse expanded comment " + format, - ex); + throw new IllegalArgumentException( + "unable to parse expanded comment " + format, ex); } } /** - * Compares the position of this tag in the file - * with the position of another tag. - * @param other the tag to compare with this one. - * @return a negative number if this tag is before the other tag, - * 0 if they are at the same position, and a positive number if this - * tag is after the other tag. + * Gets influence from suppress filter influence format param. + * + * @param format influence format to parse + * @param influenceFormat raw influence format + * @param text text of the suppression + * @return parsed influence */ - @Override - public int compareTo(Tag other) { - if (firstLine == other.firstLine) { - return Integer.compare(lastLine, other.lastLine); + private static int parseInfluence(String format, String influenceFormat, String text) { + try { + return Integer.parseInt(format); + } + catch (final NumberFormatException ex) { + throw new IllegalArgumentException("unable to parse influence from '" + text + + "' using " + influenceFormat, ex); } - - return Integer.compare(firstLine, other.firstLine); } @Override @@ -402,10 +390,10 @@ /** * Determines whether the source of an audit event * matches the text of this tag. - * @param event the {@code AuditEvent} to check. + * @param event the {@code TreeWalkerAuditEvent} to check. * @return true if the source of event matches the text of this tag. */ - public boolean isMatch(AuditEvent event) { + public boolean isMatch(TreeWalkerAuditEvent event) { final int line = event.getLine(); boolean match = false; @@ -430,9 +418,15 @@ } @Override - public final String toString() { - return "Tag[lines=[" + firstLine + " to " + lastLine - + "]; text='" + text + "']"; + public String toString() { + return "Tag[text='" + text + '\'' + + ", firstLine=" + firstLine + + ", lastLine=" + lastLine + + ", tagCheckRegexp=" + tagCheckRegexp + + ", tagMessageRegexp=" + tagMessageRegexp + + ']'; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWithPlainTextCommentFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWithPlainTextCommentFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWithPlainTextCommentFilter.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressWithPlainTextCommentFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,350 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.filters; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import com.puppycrawl.tools.checkstyle.api.AuditEvent; +import com.puppycrawl.tools.checkstyle.api.AutomaticBean; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.api.FileText; +import com.puppycrawl.tools.checkstyle.api.Filter; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; + +/** + *

    + * A filter that uses comments to suppress audit events. + * The filter can be used only to suppress audit events received from + * {@link com.puppycrawl.tools.checkstyle.api.FileSetCheck} checks. + * SuppressWithPlainTextCommentFilter knows nothing about AST, + * it treats only plain text comments and extracts the information required for suppression from + * the plain text comments. Currently the filter supports only single line comments. + *

    + *

    + * Rationale: + * Sometimes there are legitimate reasons for violating a check. When + * this is a matter of the code in question and not personal + * preference, the best place to override the policy is in the code + * itself. Semi-structured comments can be associated with the check. + * This is sometimes superior to a separate suppressions file, which + * must be kept up-to-date as the source file is edited. + *

    + * @author Andrei Selkin + */ +public class SuppressWithPlainTextCommentFilter extends AutomaticBean implements Filter { + + /** Comment format which turns checkstyle reporting off. */ + private static final String DEFAULT_OFF_FORMAT = "// CHECKSTYLE:OFF"; + + /** Comment format which turns checkstyle reporting on. */ + private static final String DEFAULT_ON_FORMAT = "// CHECKSTYLE:ON"; + + /** Default check format to suppress. By default the filter suppress all checks. */ + private static final String DEFAULT_CHECK_FORMAT = ".*"; + + /** Regexp which turns checkstyle reporting off. */ + private Pattern offCommentFormat = CommonUtils.createPattern(DEFAULT_OFF_FORMAT); + + /** Regexp which turns checkstyle reporting on. */ + private Pattern onCommentFormat = CommonUtils.createPattern(DEFAULT_ON_FORMAT); + + /** The check format to suppress. */ + private String checkFormat = DEFAULT_CHECK_FORMAT; + + /** The message format to suppress.*/ + private String messageFormat; + + /** + * Sets an off comment format pattern. + * @param pattern off comment format pattern. + */ + public final void setOffCommentFormat(Pattern pattern) { + offCommentFormat = pattern; + } + + /** + * Sets an on comment format pattern. + * @param pattern on comment format pattern. + */ + public final void setOnCommentFormat(Pattern pattern) { + onCommentFormat = pattern; + } + + /** + * Sets a pattern for check format. + * @param format pattern for check format. + */ + public final void setCheckFormat(String format) { + checkFormat = format; + } + + /** + * Sets a pattern for message format. + * @param format pattern for message format. + */ + public final void setMessageFormat(String format) { + messageFormat = format; + } + + @Override + public boolean accept(AuditEvent event) { + boolean accepted = true; + if (event.getLocalizedMessage() != null) { + final FileText fileText = getFileText(event.getFileName()); + if (fileText != null) { + final List suppressions = getSuppressions(fileText); + accepted = getNearestSuppression(suppressions, event) == null; + } + } + return accepted; + } + + @Override + protected void finishLocalSetup() throws CheckstyleException { + // No code by default + } + + /** + * Returns {@link FileText} instance created based on the given file name. + * @param fileName the name of the file. + * @return {@link FileText} instance. + */ + private static FileText getFileText(String fileName) { + final File file = new File(fileName); + FileText result = null; + + // some violations can be on a directory, instead of a file + if (!file.isDirectory()) { + try { + result = new FileText(file, StandardCharsets.UTF_8.name()); + } + catch (IOException ex) { + throw new IllegalStateException("Cannot read source file: " + fileName, ex); + } + } + + return result; + } + + /** + * Returns the list of {@link Suppression} instances retrieved from the given {@link FileText}. + * @param fileText {@link FileText} instance. + * @return list of {@link Suppression} instances. + */ + private List getSuppressions(FileText fileText) { + final List suppressions = new ArrayList<>(); + for (int lineNo = 0; lineNo < fileText.size(); lineNo++) { + final Optional suppression = getSuppression(fileText, lineNo); + suppression.ifPresent(suppressions::add); + } + return suppressions; + } + + /** + * Tries to extract the suppression from the given line. + * @param fileText {@link FileText} instance. + * @param lineNo line number. + * @return {@link Optional} of {@link Suppression}. + */ + private Optional getSuppression(FileText fileText, int lineNo) { + final String line = fileText.get(lineNo); + final Matcher onCommentMatcher = onCommentFormat.matcher(line); + final Matcher offCommentMatcher = offCommentFormat.matcher(line); + + Suppression suppression = null; + if (onCommentMatcher.find()) { + suppression = new Suppression(onCommentMatcher.group(0), + lineNo + 1, onCommentMatcher.start(), SuppressionType.ON, this); + } + if (offCommentMatcher.find()) { + suppression = new Suppression(offCommentMatcher.group(0), + lineNo + 1, offCommentMatcher.start(), SuppressionType.OFF, this); + } + + return Optional.ofNullable(suppression); + } + + /** + * Finds the nearest {@link Suppression} instance which can suppress + * the given {@link AuditEvent}. The nearest suppression is the suppression which scope + * is before the line and column of the event. + * @param suppressions {@link Suppression} instance. + * @param event {@link AuditEvent} instance. + * @return {@link Suppression} instance. + */ + private static Suppression getNearestSuppression(List suppressions, + AuditEvent event) { + return suppressions + .stream() + .filter(suppression -> suppression.isMatch(event)) + .reduce((first, second) -> second) + .filter(suppression -> suppression.suppressionType != SuppressionType.ON) + .orElse(null); + } + + /** Enum which represents the type of the suppression. */ + private enum SuppressionType { + + /** On suppression type. */ + ON, + /** Off suppression type. */ + OFF + + } + + /** The class which represents the suppression. */ + public static class Suppression { + + /** The regexp which is used to match the event source.*/ + private final Pattern eventSourceRegexp; + /** The regexp which is used to match the event message.*/ + private final Pattern eventMessageRegexp; + + /** Suppression text.*/ + private final String text; + /** Suppression line.*/ + private final int lineNo; + /** Suppression column number.*/ + private final int columnNo; + /** Suppression type. */ + private final SuppressionType suppressionType; + + /** + * Creates new suppression instance. + * @param text suppression text. + * @param lineNo suppression line number. + * @param columnNo suppression column number. + * @param suppressionType suppression type. + * @param filter the {@link SuppressWithPlainTextCommentFilter} with the context. + */ + protected Suppression( + String text, + int lineNo, + int columnNo, + SuppressionType suppressionType, + SuppressWithPlainTextCommentFilter filter + ) { + this.text = text; + this.lineNo = lineNo; + this.columnNo = columnNo; + this.suppressionType = suppressionType; + + //Expand regexp for check and message + //Does not intern Patterns with Utils.getPattern() + String format = ""; + try { + if (this.suppressionType == SuppressionType.ON) { + format = CommonUtils.fillTemplateWithStringsByRegexp( + filter.checkFormat, text, filter.onCommentFormat); + eventSourceRegexp = Pattern.compile(format); + if (filter.messageFormat == null) { + eventMessageRegexp = null; + } + else { + format = CommonUtils.fillTemplateWithStringsByRegexp( + filter.messageFormat, text, filter.onCommentFormat); + eventMessageRegexp = Pattern.compile(format); + } + } + else { + format = CommonUtils.fillTemplateWithStringsByRegexp( + filter.checkFormat, text, filter.offCommentFormat); + eventSourceRegexp = Pattern.compile(format); + if (filter.messageFormat == null) { + eventMessageRegexp = null; + } + else { + format = CommonUtils.fillTemplateWithStringsByRegexp( + filter.messageFormat, text, filter.offCommentFormat); + eventMessageRegexp = Pattern.compile(format); + } + } + } + catch (final PatternSyntaxException ex) { + throw new IllegalArgumentException( + "unable to parse expanded comment " + format, ex); + } + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + final Suppression suppression = (Suppression) other; + return Objects.equals(lineNo, suppression.lineNo) + && Objects.equals(columnNo, suppression.columnNo) + && Objects.equals(suppressionType, suppression.suppressionType) + && Objects.equals(text, suppression.text) + && Objects.equals(eventSourceRegexp, suppression.eventSourceRegexp) + && Objects.equals(eventMessageRegexp, suppression.eventMessageRegexp); + } + + @Override + public int hashCode() { + return Objects.hash( + text, lineNo, columnNo, suppressionType, eventSourceRegexp, eventMessageRegexp); + } + + /** + * Checks whether the suppression matches the given {@link AuditEvent}. + * @param event {@link AuditEvent} instance. + * @return true if the suppression matches {@link AuditEvent}. + */ + private boolean isMatch(AuditEvent event) { + boolean match = false; + if (isInScopeOfSuppression(event)) { + final Matcher sourceNameMatcher = eventSourceRegexp.matcher(event.getSourceName()); + if (sourceNameMatcher.find()) { + match = eventMessageRegexp == null + || eventMessageRegexp.matcher(event.getMessage()).find(); + } + else { + match = event.getModuleId() != null + && eventSourceRegexp.matcher(event.getModuleId()).find(); + } + } + return match; + } + + /** + * Checks whether {@link AuditEvent} is in the scope of the suppression. + * @param event {@link AuditEvent} instance. + * @return true if {@link AuditEvent} is in the scope of the suppression. + */ + private boolean isInScopeOfSuppression(AuditEvent event) { + return lineNo <= event.getLine(); + } + + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/XpathFilter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/XpathFilter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/filters/XpathFilter.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/filters/XpathFilter.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,221 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.filters; + +import java.util.List; +import java.util.Objects; +import java.util.regex.Pattern; + +import com.puppycrawl.tools.checkstyle.TreeWalkerAuditEvent; +import com.puppycrawl.tools.checkstyle.TreeWalkerFilter; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; +import com.puppycrawl.tools.checkstyle.xpath.AbstractNode; +import com.puppycrawl.tools.checkstyle.xpath.RootNode; +import net.sf.saxon.om.Item; +import net.sf.saxon.sxpath.XPathDynamicContext; +import net.sf.saxon.sxpath.XPathEvaluator; +import net.sf.saxon.sxpath.XPathExpression; +import net.sf.saxon.trans.XPathException; + +/** + * This filter processes {@link TreeWalkerAuditEvent} + * objects based on the criteria of file, check, module id, xpathQuery. + * + * @author Timur Tibeyev. + */ +public class XpathFilter implements TreeWalkerFilter { + + /** The regexp to match file names against. */ + private final Pattern fileRegexp; + + /** The pattern for file names. */ + private final String filePattern; + + /** The regexp to match check names against. */ + private final Pattern checkRegexp; + + /** The pattern for check class names. */ + private final String checkPattern; + + /** The regexp to match message names against. */ + private final Pattern messageRegexp; + + /** The pattern for message names. */ + private final String messagePattern; + + /** Module id filter. */ + private final String moduleId; + + /** Xpath expression. */ + private final XPathExpression xpathExpression; + + /** Xpath query. */ + private final String xpathQuery; + + /** + * Creates a {@code XpathElement} instance. + * @param files regular expression for names of filtered files + * @param checks regular expression for filtered check classes + * @param message regular expression for messages. + * @param moduleId the module id + * @param query the xpath query + */ + public XpathFilter(String files, String checks, + String message, String moduleId, String query) { + filePattern = files; + if (files == null) { + fileRegexp = null; + } + else { + fileRegexp = Pattern.compile(files); + } + checkPattern = checks; + if (checks == null) { + checkRegexp = null; + } + else { + checkRegexp = CommonUtils.createPattern(checks); + } + messagePattern = message; + if (message == null) { + messageRegexp = null; + } + else { + messageRegexp = Pattern.compile(message); + } + this.moduleId = moduleId; + xpathQuery = query; + if (xpathQuery == null) { + xpathExpression = null; + } + else { + final XPathEvaluator xpathEvaluator = new XPathEvaluator(); + try { + xpathExpression = xpathEvaluator.createExpression(xpathQuery); + } + catch (XPathException ex) { + throw new IllegalStateException("Unexpected xpath query: " + xpathQuery, ex); + } + } + } + + @Override + public boolean accept(TreeWalkerAuditEvent event) { + return !isFileNameAndModuleAndCheckNameMatching(event) + || !isMessageNameMatching(event) + || !isXpathQueryMatching(event); + } + + /** + * Is matching by file name, moduleId and Check name. + * @param event event + * @return true if it is matching + */ + private boolean isFileNameAndModuleAndCheckNameMatching(TreeWalkerAuditEvent event) { + return event.getFileName() != null + && (fileRegexp == null || fileRegexp.matcher(event.getFileName()).find()) + && event.getLocalizedMessage() != null + && (moduleId == null || moduleId.equals(event.getModuleId())) + && (checkRegexp == null || checkRegexp.matcher(event.getSourceName()).find()); + } + + /** + * Is matching by message. + * @param event event + * @return true is matching or not set. + */ + private boolean isMessageNameMatching(TreeWalkerAuditEvent event) { + return messageRegexp == null || messageRegexp.matcher(event.getMessage()).find(); + } + + /** + * Is matching by xpath query. + * @param event event + * @return true is matching + */ + private boolean isXpathQueryMatching(TreeWalkerAuditEvent event) { + boolean isMatching; + if (xpathExpression == null) { + isMatching = true; + } + else { + isMatching = false; + final List items = getItems(event); + for (Item item : items) { + final AbstractNode abstractNode = (AbstractNode) item; + isMatching = abstractNode.getTokenType() == event.getTokenType() + && abstractNode.getLineNumber() == event.getLine() + && abstractNode.getColumnNumber() == event.getColumnCharIndex(); + if (isMatching) { + break; + } + } + } + return isMatching; + } + + /** + * Returns list of nodes matching xpath expression given event. + * @param event {@code TreeWalkerAuditEvent} object + * @return list of nodes matching xpath expression given event + */ + private List getItems(TreeWalkerAuditEvent event) { + final RootNode rootNode; + if (event.getRootAst() == null) { + rootNode = null; + } + else { + rootNode = new RootNode(event.getRootAst()); + } + final List items; + try { + final XPathDynamicContext xpathDynamicContext = + xpathExpression.createDynamicContext(rootNode); + items = xpathExpression.evaluate(xpathDynamicContext); + } + catch (XPathException ex) { + throw new IllegalStateException("Cannot initialize context and evaluate query: " + + xpathQuery, ex); + } + return items; + } + + @Override + public int hashCode() { + return Objects.hash(filePattern, checkPattern, messagePattern, moduleId, xpathQuery); + } + + @Override + public boolean equals(Object other) { + if (this == other) { + return true; + } + if (other == null || getClass() != other.getClass()) { + return false; + } + final XpathFilter xpathFilter = (XpathFilter) other; + return Objects.equals(filePattern, xpathFilter.filePattern) + && Objects.equals(checkPattern, xpathFilter.checkPattern) + && Objects.equals(messagePattern, xpathFilter.messagePattern) + && Objects.equals(moduleId, xpathFilter.moduleId) + && Objects.equals(xpathQuery, xpathFilter.xpathQuery); + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/GlobalStatefulCheck.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/GlobalStatefulCheck.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/GlobalStatefulCheck.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/GlobalStatefulCheck.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,50 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * This annotation means that the check contains global context, + * which will be updated while Checkstyle processes files. This also means, + * that all files will be processed by the same check instance. + * This annotation should be used, if a check accumulates some information during the audit, + * and processed only once at the end of the audit (however, the check still + * can produce some messages, while collecting information). + * The check methods and fields should be thread safe, because they may be accessed from others + * threads at the same time. + * Checker guarantees that there will be exactly one check instance + * This is similar to multi-file validation, which checkstyle does not support fully yet. + * Please refer to https://github.com/checkstyle/checkstyle/issues/3540 for details. + * @author Andrew Kuchev + * @noinspection AnnotationClass, ClassIndependentOfModule, unused + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Inherited +public @interface GlobalStatefulCheck { + + // this annotation does not have properties + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/grammars/CommentListener.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/grammars/CommentListener.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/grammars/CommentListener.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/grammars/CommentListener.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,8 +24,10 @@ * in the parsed code. * * @author o_sukhodolsky + * @noinspection ClassOnlyUsedInOnePackage */ public interface CommentListener { + /** * Report the location of a single line comment that extends from the * given point to the end of the line. The type of comment is identified @@ -54,4 +56,5 @@ void reportBlockComment(String type, int startLineNo, int startColNo, int endLineNo, int endColNo); + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/grammars/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/grammars/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/grammars/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/grammars/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/BaseCellEditor.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/BaseCellEditor.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/BaseCellEditor.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/BaseCellEditor.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -112,4 +112,5 @@ } } } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/CodeSelector.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/CodeSelector.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/CodeSelector.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/CodeSelector.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -26,66 +26,47 @@ import com.google.common.collect.ImmutableList; import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.utils.TokenUtils; +import com.puppycrawl.tools.checkstyle.api.DetailNode; /** * Helper class to select a code. * @author unknown */ public class CodeSelector { - /** DetailAST node. */ - private final DetailAST ast; + /** Editor. */ private final JTextArea editor; - /** Mapping. */ - private final List lines2position; + /** Presentation model. */ + private final CodeSelectorPresentation pModel; /** * Constructor. - * @param ast ast node. + * @param node ast node. * @param editor text area editor. * @param lines2position list to map lines. */ - public CodeSelector(final DetailAST ast, final JTextArea editor, + public CodeSelector(final Object node, final JTextArea editor, final List lines2position) { - this.ast = ast; this.editor = editor; - this.lines2position = ImmutableList.copyOf(lines2position); + if (node instanceof DetailAST) { + pModel = new CodeSelectorPresentation((DetailAST) node, + ImmutableList.copyOf(lines2position)); + } + else { + pModel = new CodeSelectorPresentation((DetailNode) node, + ImmutableList.copyOf(lines2position)); + } } /** - * Set a selection position from AST line and Column. + * Set selection. */ public void select() { - final int start = lines2position.get(ast.getLineNo()) + ast.getColumnNo(); - final int end; - - if (ast.getChildCount() == 0 - && TokenUtils.getTokenName(ast.getType()).equals(ast.getText())) { - end = start; - } - else { - end = findLastPosition(ast); - } - + pModel.findSelectionPositions(); editor.setSelectedTextColor(Color.blue); editor.requestFocusInWindow(); - editor.setCaretPosition(start); - editor.moveCaretPosition(end); + editor.setCaretPosition(pModel.getSelectionStart()); + editor.moveCaretPosition(pModel.getSelectionEnd()); } - /** - * Finds the last position of node without children. - * @param astNode DetailAST node. - * @return Last position of node without children. - */ - private int findLastPosition(final DetailAST astNode) { - if (astNode.getChildCount() == 0) { - return lines2position.get(astNode.getLineNo()) + astNode.getColumnNo() - + astNode.getText().length(); - } - else { - return findLastPosition(astNode.getLastChild()); - } - } } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/CodeSelectorPresentation.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/CodeSelectorPresentation.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/CodeSelectorPresentation.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/CodeSelectorPresentation.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,157 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.gui; + +import java.util.List; + +import com.google.common.collect.ImmutableList; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.DetailNode; +import com.puppycrawl.tools.checkstyle.utils.TokenUtils; + +/** + * Presentation model for CodeSelector. + * @author unknown + */ +public class CodeSelectorPresentation { + + /** DetailAST or DetailNode node. */ + private final Object node; + /** Mapping. */ + private final List lines2position; + /** Selection start position. */ + private int selectionStart; + /** Selection end position. */ + private int selectionEnd; + + /** + * Constructor. + * @param ast ast node. + * @param lines2position list to map lines. + * @noinspection AssignmentToCollectionOrArrayFieldFromParameter + */ + public CodeSelectorPresentation(DetailAST ast, ImmutableList lines2position) { + node = ast; + this.lines2position = lines2position; + } + + /** + * Constructor. + * @param node DetailNode node. + * @param lines2position list to map lines. + * @noinspection AssignmentToCollectionOrArrayFieldFromParameter + */ + public CodeSelectorPresentation(DetailNode node, ImmutableList lines2position) { + this.node = node; + this.lines2position = lines2position; + } + + /** + * Returns selection start position. + * @return selection start position. + */ + public int getSelectionStart() { + return selectionStart; + } + + /** + * Returns selection end position. + * @return selection end position. + */ + public int getSelectionEnd() { + return selectionEnd; + } + + /** + * Find start and end selection positions from AST line and Column. + */ + public void findSelectionPositions() { + if (node instanceof DetailAST) { + findSelectionPositions((DetailAST) node); + } + else { + findSelectionPositions((DetailNode) node); + } + } + + /** + * Find start and end selection positions from AST line and Column. + * @param ast DetailAST node for which selection finds + */ + private void findSelectionPositions(DetailAST ast) { + selectionStart = lines2position.get(ast.getLineNo()) + ast.getColumnNo(); + + if (ast.getChildCount() == 0 + && TokenUtils.getTokenName(ast.getType()).equals(ast.getText())) { + selectionEnd = selectionStart; + } + else { + selectionEnd = findLastPosition(ast); + } + } + + /** + * Find start and end selection positions from DetailNode line and Column. + * @param detailNode DetailNode node for which selection finds + */ + private void findSelectionPositions(DetailNode detailNode) { + selectionStart = lines2position.get(detailNode.getLineNumber()) + + detailNode.getColumnNumber(); + + selectionEnd = findLastPosition(detailNode); + } + + /** + * Finds the last position of node without children. + * @param astNode DetailAST node. + * @return Last position of node without children. + */ + private int findLastPosition(final DetailAST astNode) { + final int lastPosition; + if (astNode.getChildCount() == 0) { + lastPosition = lines2position.get(astNode.getLineNo()) + astNode.getColumnNo() + + astNode.getText().length(); + } + else { + lastPosition = findLastPosition(astNode.getLastChild()); + } + return lastPosition; + } + + /** + * Finds the last position of node without children. + * @param detailNode DetailNode node. + * @return Last position of node without children. + */ + private int findLastPosition(final DetailNode detailNode) { + final int lastPosition; + if (detailNode.getChildren().length == 0) { + lastPosition = lines2position.get(detailNode.getLineNumber()) + + detailNode.getColumnNumber() + detailNode.getText().length(); + } + else { + final DetailNode lastChild = + detailNode.getChildren()[detailNode.getChildren().length - 1]; + lastPosition = findLastPosition(lastChild); + } + return lastPosition; + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/JTreeTable.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/JTreeTable.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/JTreeTable.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/JTreeTable.java 1970-01-01 00:00:00.000000000 +0000 @@ -1,308 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//////////////////////////////////////////////////////////////////////////////// - -package com.puppycrawl.tools.checkstyle.gui; - -import java.awt.Component; -import java.awt.Dimension; -import java.awt.FontMetrics; -import java.awt.event.ActionEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.util.EventObject; -import java.util.List; - -import javax.swing.AbstractAction; -import javax.swing.Action; -import javax.swing.JTable; -import javax.swing.JTextArea; -import javax.swing.JTree; -import javax.swing.KeyStroke; -import javax.swing.LookAndFeel; -import javax.swing.table.TableCellEditor; -import javax.swing.tree.TreePath; - -import com.google.common.collect.ImmutableList; -import com.google.common.primitives.Ints; -import com.puppycrawl.tools.checkstyle.api.DetailAST; - -/** - * This example shows how to create a simple JTreeTable component, - * by using a JTree as a renderer (and editor) for the cells in a - * particular column in the JTable. - * - * - * Original Source Location - * - * @author Philip Milne - * @author Scott Violet - * @author Lars Kühne - */ -public class JTreeTable extends JTable { - private static final long serialVersionUID = -8493693409423365387L; - /** A subclass of JTree. */ - private final TreeTableCellRenderer tree; - /** JTextArea editor. */ - private JTextArea editor; - /** Line position map. */ - private List linePositionMap; - - /** - * Creates JTreeTable base on TreeTableModel. - * @param treeTableModel Tree table model - */ - public JTreeTable(ParseTreeTableModel treeTableModel) { - - // Create the tree. It will be used as a renderer and editor. - tree = new TreeTableCellRenderer(this, treeTableModel); - - // Install a tableModel representing the visible rows in the tree. - setModel(new TreeTableModelAdapter(treeTableModel, tree)); - - // Force the JTable and JTree to share their row selection models. - final ListToTreeSelectionModelWrapper selectionWrapper = new - ListToTreeSelectionModelWrapper(this); - tree.setSelectionModel(selectionWrapper); - setSelectionModel(selectionWrapper.getListSelectionModel()); - - // Install the tree editor renderer and editor. - setDefaultRenderer(ParseTreeTableModel.class, tree); - setDefaultEditor(ParseTreeTableModel.class, new TreeTableCellEditor()); - - // No grid. - setShowGrid(false); - - // No intercell spacing - setIntercellSpacing(new Dimension(0, 0)); - - // And update the height of the trees row to match that of - // the table. - if (tree.getRowHeight() < 1) { - // Metal looks better like this. - setRowHeight(getRowHeight()); - } - - setColumnsInitialWidth(); - - final Action expand = new AbstractAction() { - private static final long serialVersionUID = -5859674518660156121L; - - @Override - public void actionPerformed(ActionEvent event) { - doExpandByEnter(); - } - }; - final KeyStroke stroke = KeyStroke.getKeyStroke("ENTER"); - final String command = "expand/collapse"; - getInputMap().put(stroke, command); - getActionMap().put(command, expand); - - addMouseListener(new MouseAdapter() { - @Override - public void mouseClicked(MouseEvent event) { - if (event.getClickCount() == 2) { - makeCodeSelection(); - } - } - }); - } - - /** - * Do expansion of a tree node after pressing ENTER. - */ - private void doExpandByEnter() { - final TreePath selected = makeCodeSelection(); - - if (tree.isExpanded(selected)) { - tree.collapsePath(selected); - } - else { - tree.expandPath(selected); - } - tree.setSelectionPath(selected); - } - - /** - * Make selection of code in a text area. - * @return selected TreePath. - */ - private TreePath makeCodeSelection() { - final TreePath selected = tree.getSelectionPath(); - final DetailAST ast = (DetailAST) selected.getLastPathComponent(); - new CodeSelector(ast, editor, linePositionMap).select(); - return selected; - } - - /** - * Set initial value of width for columns in table. - */ - private void setColumnsInitialWidth() { - final FontMetrics fontMetrics = getFontMetrics(getFont()); - // Six character string to contain "Column" column. - final int widthOfSixCharacterString = fontMetrics.stringWidth("XXXXXX"); - // Padding must be added to width for columns to make them fully - // visible in table header. - final int padding = 10; - final int widthOfColumnContainingSixCharacterString = - widthOfSixCharacterString + padding; - getColumn("Line").setMaxWidth(widthOfColumnContainingSixCharacterString); - getColumn("Column").setMaxWidth(widthOfColumnContainingSixCharacterString); - final int preferredTreeColumnWidth = - Ints.checkedCast(Math.round(getPreferredSize().getWidth() * 0.6)); - getColumn("Tree").setPreferredWidth(preferredTreeColumnWidth); - // Twenty eight character string to contain "Type" column - final int widthOfTwentyEightCharacterString = - fontMetrics.stringWidth("XXXXXXXXXXXXXXXXXXXXXXXXXXXX"); - final int preferredTypeColumnWidth = widthOfTwentyEightCharacterString + padding; - getColumn("Type").setPreferredWidth(preferredTypeColumnWidth); - } - - /** - * Overridden to message super and forward the method to the tree. - * Since the tree is not actually in the component hierarchy it will - * never receive this unless we forward it in this manner. - */ - @Override - public void updateUI() { - super.updateUI(); - if (tree != null) { - tree.updateUI(); - } - // Use the tree's default foreground and background colors in the - // table. - LookAndFeel.installColorsAndFont(this, "Tree.background", - "Tree.foreground", "Tree.font"); - } - - /* Workaround for BasicTableUI anomaly. Make sure the UI never tries to - * paint the editor. The UI currently uses different techniques to - * paint the renderers and editors and overriding setBounds() below - * is not the right thing to do for an editor. Returning -1 for the - * editing row in this case, ensures the editor is never painted. - */ - @Override - public int getEditingRow() { - final Class editingClass = getColumnClass(editingColumn); - - if (editingClass == ParseTreeTableModel.class) { - return -1; - } - else { - return editingRow; - } - } - - /** - * Overridden to pass the new rowHeight to the tree. - * - * @param newRowHeight new row height - */ - @Override - public final void setRowHeight(int newRowHeight) { - super.setRowHeight(newRowHeight); - if (tree != null && tree.getRowHeight() != newRowHeight) { - tree.setRowHeight(getRowHeight()); - } - } - - /** - * @return the tree that is being shared between the model. - */ - public JTree getTree() { - return tree; - } - - /** - * Sets text area editor. - * @param textArea JTextArea component. - */ - public void setEditor(JTextArea textArea) { - editor = textArea; - } - - /** - * Sets line position map. - * @param linePositionMap Line position map. - */ - public void setLinePositionMap(List linePositionMap) { - this.linePositionMap = ImmutableList.copyOf(linePositionMap); - } - - /** - * TreeTableCellEditor implementation. Component returned is the - * JTree. - */ - private class TreeTableCellEditor extends BaseCellEditor implements - TableCellEditor { - @Override - public Component getTableCellEditorComponent(JTable table, - Object value, - boolean isSelected, - int row, int column) { - return tree; - } - - /** - * Overridden to return false, and if the event is a mouse event - * it is forwarded to the tree. - * - *

    The behavior for this is debatable, and should really be offered - * as a property. By returning false, all keyboard actions are - * implemented in terms of the table. By returning true, the - * tree would get a chance to do something with the keyboard - * events. For the most part this is ok. But for certain keys, - * such as left/right, the tree will expand/collapse where as - * the table focus should really move to a different column. Page - * up/down should also be implemented in terms of the table. - * By returning false this also has the added benefit that clicking - * outside of the bounds of the tree node, but still in the tree - * column will select the row, whereas if this returned true - * that wouldn't be the case. - * - *

    By returning false we are also enforcing the policy that - * the tree will never be editable (at least by a key sequence). - * - * @param event the event the editor should use to consider - * whether to begin editing or not - * @return true if editing can be started - * @see TableCellEditor - */ - @Override - public boolean isCellEditable(EventObject event) { - if (event instanceof MouseEvent) { - for (int counter = getColumnCount() - 1; counter >= 0; - counter--) { - if (getColumnClass(counter) == ParseTreeTableModel.class) { - final MouseEvent mouseEvent = (MouseEvent) event; - final MouseEvent newMouseEvent = new MouseEvent(tree, mouseEvent.getID(), - mouseEvent.getWhen(), mouseEvent.getModifiers(), - mouseEvent.getX() - getCellRect(0, counter, true).x, - mouseEvent.getY(), mouseEvent.getClickCount(), - mouseEvent.isPopupTrigger()); - tree.dispatchEvent(newMouseEvent); - break; - } - } - } - - return false; - } - } -} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/ListToTreeSelectionModelWrapper.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/ListToTreeSelectionModelWrapper.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/ListToTreeSelectionModelWrapper.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/ListToTreeSelectionModelWrapper.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -20,8 +20,6 @@ package com.puppycrawl.tools.checkstyle.gui; import javax.swing.ListSelectionModel; -import javax.swing.event.ListSelectionEvent; -import javax.swing.event.ListSelectionListener; import javax.swing.tree.DefaultTreeSelectionModel; import javax.swing.tree.TreePath; @@ -34,18 +32,22 @@ * @author unknown */ class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel { + private static final long serialVersionUID = 2267930983939339510L; - /** JTreeTable to perform updates on. */ - private final JTreeTable treeTable; + /** TreeTable to perform updates on. */ + private final TreeTable treeTable; /** Set to true when we are updating the ListSelectionModel. */ private boolean updatingListSelectionModel; /** + * Constructor to initialise treeTable. * @param jTreeTable TreeTable to perform updates on. */ - ListToTreeSelectionModelWrapper(JTreeTable jTreeTable) { + ListToTreeSelectionModelWrapper(TreeTable jTreeTable) { treeTable = jTreeTable; - getListSelectionModel().addListSelectionListener(createListSelectionListener()); + getListSelectionModel().addListSelectionListener(event -> { + updateSelectedPathsFromSelectedRows(); + }); } /** @@ -55,7 +57,7 @@ * * @return the list selection model */ - final ListSelectionModel getListSelectionModel() { + protected final ListSelectionModel getListSelectionModel() { return listSelectionModel; } @@ -83,15 +85,6 @@ } /** - * Creates an instance of ListSelectionHandler. - * - * @return An instance of ListSelectionHandler - */ - private ListSelectionListener createListSelectionListener() { - return new ListSelectionHandler(); - } - - /** * If {@code updatingListSelectionModel} is false, this will * reset the selected paths from the selected rows in the list * selection model. @@ -132,14 +125,4 @@ } } - /** - * Class responsible for calling updateSelectedPathsFromSelectedRows - * when the selection of the list changes. - */ - private class ListSelectionHandler implements ListSelectionListener { - @Override - public void valueChanged(ListSelectionEvent event) { - updateSelectedPathsFromSelectedRows(); - } - } } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/MainFrame.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/MainFrame.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/MainFrame.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/MainFrame.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -24,21 +24,24 @@ import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.io.File; -import java.io.IOException; import javax.swing.AbstractAction; +import javax.swing.BorderFactory; import javax.swing.JButton; +import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JFrame; +import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTextArea; +import javax.swing.SwingConstants; import javax.swing.filechooser.FileFilter; -import antlr.ANTLRException; -import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.gui.MainFrameModel.ParseMode; /** * Displays information about a parse tree. @@ -47,20 +50,20 @@ * * @author Lars Kühne * @author Vladislav Lisetskiy + * @noinspection MagicNumber */ public class MainFrame extends JFrame { private static final long serialVersionUID = 7970053543351871890L; + /** Checkstyle frame model. */ private final transient MainFrameModel model = new MainFrameModel(); /** Reload action. */ private final ReloadAction reloadAction = new ReloadAction(); - /** Parse tree model. */ - private transient ParseTreeTableModel parseTreeTableModel; /** Code text area. */ private JTextArea textArea; /** Tree table. */ - private JTreeTable treeTable; + private TreeTable treeTable; /** Create a new MainFrame. */ public MainFrame() { @@ -75,8 +78,7 @@ textArea.setEditable(false); final JScrollPane textAreaScrollPane = new JScrollPane(textArea); - parseTreeTableModel = new ParseTreeTableModel(null); - treeTable = new JTreeTable(parseTreeTableModel); + treeTable = new TreeTable(model.getParseTreeTableModel()); treeTable.setEditor(textArea); treeTable.setLinePositionMap(model.getLinesToPosition()); final JScrollPane treeTableScrollPane = new JScrollPane(treeTable); @@ -105,12 +107,32 @@ reloadFileButton.setMnemonic(KeyEvent.VK_R); reloadFileButton.setText("Reload File"); + final JComboBox modesCombobox = new JComboBox<>(ParseMode.values()); + modesCombobox.setSelectedIndex(0); + modesCombobox.addActionListener(e -> { + model.setParseMode((ParseMode) modesCombobox.getSelectedItem()); + reloadAction.actionPerformed(null); + }); + + final JLabel modesLabel = new JLabel("Modes:", SwingConstants.RIGHT); + final int leftIndentation = 10; + modesLabel.setBorder(BorderFactory.createEmptyBorder(0, leftIndentation, 0, 0)); + final JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout(1, 2)); buttonPanel.add(openFileButton); buttonPanel.add(reloadFileButton); - return buttonPanel; + final JPanel modesPanel = new JPanel(); + modesPanel.add(modesLabel); + modesPanel.add(modesCombobox); + + final JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + mainPanel.add(buttonPanel); + mainPanel.add(modesPanel, BorderLayout.LINE_END); + + return mainPanel; } /** @@ -118,35 +140,15 @@ * @param sourceFile the file to open. */ public void openFile(File sourceFile) { - if (sourceFile != null) { - try { - setTitle("Checkstyle : " + sourceFile.getName()); - final DetailAST parseTree = model.parseFile(sourceFile); - parseTreeTableModel.setParseTree(parseTree); - reloadAction.setEnabled(true); - - final String[] sourceLines = model.getFileText(sourceFile).toLinesArray(); - - // clear for each new file - model.clearLinesToPosition(); - // starts line counting at 1 - model.addLineToPosition(0); - - // clean the text area before inserting the lines of the new file - textArea.setText(""); - - // insert the contents of the file to the text area - for (final String element : sourceLines) { - model.addLineToPosition(textArea.getText().length()); - textArea.append(element + System.lineSeparator()); - } - - treeTable.setLinePositionMap(model.getLinesToPosition()); - } - catch (final IOException | ANTLRException ex) { - JOptionPane.showMessageDialog(this, - "Could not parse" + sourceFile + ": " + ex.getMessage()); - } + try { + model.openFile(sourceFile); + setTitle(model.getTitle()); + reloadAction.setEnabled(model.isReloadActionEnabled()); + textArea.setText(model.getText()); + treeTable.setLinePositionMap(model.getLinesToPosition()); + } + catch (final CheckstyleException ex) { + JOptionPane.showMessageDialog(this, ex.getMessage()); } } @@ -154,6 +156,7 @@ * Handler for file selection action events. */ private class FileSelectionAction extends AbstractAction { + private static final long serialVersionUID = 1762396148873280589L; @Override @@ -168,32 +171,38 @@ openFile(file); } } + } /** * Handler for reload action events. */ private class ReloadAction extends AbstractAction { + private static final long serialVersionUID = -890320994114628011L; @Override public void actionPerformed(ActionEvent event) { openFile(model.getCurrentFile()); } + } /** * Filter for Java files. */ private static class JavaFileFilter extends FileFilter { + @Override public boolean accept(File file) { - return file.isDirectory() || file.getName().endsWith(".java"); + return MainFrameModel.shouldAcceptFile(file); } @Override public String getDescription() { return "Java Source File"; } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/MainFrameModel.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/MainFrameModel.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/MainFrameModel.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/MainFrameModel.java 2018-01-28 04:16:51.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -21,15 +21,15 @@ import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; - -import antlr.ANTLRException; +import java.util.Locale; import com.google.common.collect.ImmutableList; -import com.puppycrawl.tools.checkstyle.TreeWalker; +import com.puppycrawl.tools.checkstyle.JavaParser; +import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.api.FileContents; import com.puppycrawl.tools.checkstyle.api.FileText; /** @@ -38,35 +38,116 @@ */ public class MainFrameModel { + /** + * Parsing modes which available in GUI. + */ + public enum ParseMode { + + /** Only Java tokens without comments. */ + PLAIN_JAVA("Plain Java"), + + /** Java tokens and comment nodes (singleline comments and block comments). */ + JAVA_WITH_COMMENTS("Java with comments"), + + /** + * Java tokens, comments and Javadoc comments nodes + * (which are parsed from block comments). + */ + JAVA_WITH_JAVADOC_AND_COMMENTS("Java with comments and Javadocs"); + + /** + * Mode's short description. + */ + private final String description; + + /** + * Provides description. + * @param descr description + */ + ParseMode(String descr) { + description = descr; + } + + @Override + public String toString() { + return description; + } + + } + + /** Parse tree model. */ + private final ParseTreeTableModel parseTreeTableModel; + /** Lines to position map. */ - private final List linesToPosition = new ArrayList<>(); + private ImmutableList linesToPosition = ImmutableList.of(); + + /** Current mode. */ + private ParseMode parseMode = ParseMode.PLAIN_JAVA; /** The file which is being parsed. */ private File currentFile; + /** Text for a frame's text area. */ + private String text; + + /** Title for the main frame. */ + private String title = "Checkstyle GUI"; + + /** Whether the reload action is enabled. */ + private boolean reloadActionEnabled; + + /** Instantiate the model. */ + public MainFrameModel() { + parseTreeTableModel = new ParseTreeTableModel(null); + } + /** - * Parse a file and return the parse tree. - * @param file the file to parse. - * @return the root node of the parse tree. - * @throws IOException if the file could not be read. - * @throws ANTLRException if the file is not a Java source. + * Set current parse mode. + * @param mode ParseMode enum. */ - public DetailAST parseFile(File file) throws IOException, ANTLRException { - currentFile = file; - final FileText text = getFileText(file); - final FileContents contents = new FileContents(text); - return TreeWalker.parse(contents); + public void setParseMode(ParseMode mode) { + parseMode = mode; } /** - * Get FileText from a file. - * @param file the file to get the FileText from. - * @return the FileText. - * @throws IOException if the file could not be read. + * Get parse tree table model. + * @return parse tree table model. */ - public FileText getFileText(File file) throws IOException { - return new FileText(file.getAbsoluteFile(), - System.getProperty("file.encoding", "UTF-8")); + public ParseTreeTableModel getParseTreeTableModel() { + return parseTreeTableModel; + } + + /** + * Get text to display in a text area. + * @return text to display in a text area. + */ + public String getText() { + return text; + } + + /** + * Returns title for the main frame. + * @return title for the main frame. + */ + public String getTitle() { + return title; + } + + /** + * Returns true if the reload action is enabled, false otherwise. + * @return true if the reload action is enabled. + */ + public boolean isReloadActionEnabled() { + return reloadActionEnabled; + } + + /** + * Whether a file chooser should accept the file as a source file. + * @param file the file to check. + * @return true if the file should be accepted. + */ + public static boolean shouldAcceptFile(File file) { + return file.isDirectory() || file.getName().endsWith(".java"); } /** @@ -91,23 +172,76 @@ /** * Get lines to position map. + * It returns unmodifiable collection to + * prevent additional overhead of copying + * and possible state modifications. * @return lines to position map. + * @noinspection ReturnOfCollectionOrArrayField */ - public List getLinesToPosition() { - return ImmutableList.copyOf(linesToPosition); + public ImmutableList getLinesToPosition() { + return linesToPosition; } /** - * Add a new value into lines to position map. - * @param value Value to be added into position map. - */ - public void addLineToPosition(int value) { - linesToPosition.add(value); + * Open file and load the file. + * @param file the file to open. + * @throws CheckstyleException if the file can not be parsed. + */ + public void openFile(File file) throws CheckstyleException { + if (file != null) { + try { + currentFile = file; + title = "Checkstyle GUI : " + file.getName(); + reloadActionEnabled = true; + final DetailAST parseTree; + + switch (parseMode) { + case PLAIN_JAVA: + parseTree = JavaParser.parseFile(file, JavaParser.Options.WITHOUT_COMMENTS); + break; + case JAVA_WITH_COMMENTS: + case JAVA_WITH_JAVADOC_AND_COMMENTS: + parseTree = JavaParser.parseFile(file, JavaParser.Options.WITH_COMMENTS); + break; + default: + throw new IllegalArgumentException("Unknown mode: " + parseMode); + } + + parseTreeTableModel.setParseTree(parseTree); + parseTreeTableModel.setParseMode(parseMode); + final String[] sourceLines = getFileText(file).toLinesArray(); + + final List linesToPositionTemp = new ArrayList<>(); + // starts line counting at 1 + linesToPositionTemp.add(0); + + final StringBuilder sb = new StringBuilder(1024); + // insert the contents of the file to the text area + for (final String element : sourceLines) { + linesToPositionTemp.add(sb.length()); + sb.append(element).append(System.lineSeparator()); + } + linesToPosition = ImmutableList.copyOf(linesToPositionTemp); + text = sb.toString(); + } + catch (IOException ex) { + final String exceptionMsg = String.format(Locale.ROOT, + "%s occurred while opening file %s.", + ex.getClass().getSimpleName(), file.getPath()); + throw new CheckstyleException(exceptionMsg, ex); + } + } } - /** Clear lines to position map. */ - public void clearLinesToPosition() { - linesToPosition.clear(); + /** + * Get FileText from a file. + * @param file the file to get the FileText from. + * @return the FileText. + * @throws IOException if the file could not be read. + */ + private static FileText getFileText(File file) throws IOException { + return new FileText(file.getAbsoluteFile(), + System.getProperty("file.encoding", StandardCharsets.UTF_8.name())); } } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/Main.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/Main.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/Main.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/Main.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -41,19 +41,17 @@ * @param args the command line arguments. */ public static void main(final String... args) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - final MainFrame mainFrame = new MainFrame(); - - if (args.length > 0) { - final File sourceFile = new File(args[0]); - mainFrame.openFile(sourceFile); - } - mainFrame.setTitle("Checkstyle"); - mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); - mainFrame.setVisible(true); + SwingUtilities.invokeLater(() -> { + final MainFrame mainFrame = new MainFrame(); + + if (args.length > 0) { + final File sourceFile = new File(args[0]); + mainFrame.openFile(sourceFile); } + mainFrame.setTitle("Checkstyle GUI"); + mainFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + mainFrame.setVisible(true); }); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/package-info.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/package-info.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/package-info.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/package-info.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/ParseTreeTableModel.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/ParseTreeTableModel.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/ParseTreeTableModel.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/ParseTreeTableModel.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -25,12 +25,8 @@ import javax.swing.tree.TreeModel; import javax.swing.tree.TreePath; -import antlr.ASTFactory; -import antlr.collections.AST; - import com.puppycrawl.tools.checkstyle.api.DetailAST; -import com.puppycrawl.tools.checkstyle.api.TokenTypes; -import com.puppycrawl.tools.checkstyle.utils.TokenUtils; +import com.puppycrawl.tools.checkstyle.gui.MainFrameModel.ParseMode; /** * The model that backs the parse tree in the GUI. @@ -39,15 +35,8 @@ */ public class ParseTreeTableModel implements TreeModel { - /** Column names. */ - private static final String[] COLUMN_NAMES = { - "Tree", "Type", "Line", "Column", "Text", - }; - - /** - * The root node of the tree table model. - */ - private final Object root; + /** Presentation model. */ + private final ParseTreeTablePresentation pModel; /** * A list of event listeners for the tree model. @@ -55,150 +44,102 @@ private final EventListenerList listenerList = new EventListenerList(); /** + * Initialise pModel. * @param parseTree DetailAST parse tree. */ public ParseTreeTableModel(DetailAST parseTree) { - root = createArtificialTreeRoot(); + pModel = new ParseTreeTablePresentation(parseTree); setParseTree(parseTree); } /** - * Creates artificial tree root. - * @return Artificial tree root. - */ - private static DetailAST createArtificialTreeRoot() { - final ASTFactory factory = new ASTFactory(); - factory.setASTNodeClass(DetailAST.class.getName()); - return (DetailAST) factory.create(TokenTypes.EOF, "ROOT"); - } - - /** * Sets parse tree. * @param parseTree DetailAST parse tree. */ - final void setParseTree(DetailAST parseTree) { - ((AST) root).setFirstChild(parseTree); - final Object[] path = {root}; + protected final void setParseTree(DetailAST parseTree) { + pModel.setParseTree(parseTree); + final Object[] path = {pModel.getRoot()}; // no need to setup remaining info, as the call results in a // table structure changed event anyway - we just pass nulls fireTreeStructureChanged(this, path, null, (Object[]) null); } /** + * Set parse mode. + * @param mode ParseMode enum + */ + protected void setParseMode(ParseMode mode) { + pModel.setParseMode(mode); + } + + /** + * Returns number of available column. * @return the number of available column. */ public int getColumnCount() { - return COLUMN_NAMES.length; + return pModel.getColumnCount(); } /** + * Returns column name of specified column number. * @param column the column number * @return the name for column number {@code column}. */ public String getColumnName(int column) { - return COLUMN_NAMES[column]; + return pModel.getColumnName(column); } /** + * Returns type of specified column number. * @param column the column number * @return the type for column number {@code column}. */ + // -@cs[ForbidWildcardAsReturnType] We need to satisfy javax.swing.table.AbstractTableModel + // public Class getColumnClass(int columnIndex) {...} public Class getColumnClass(int column) { - final Class columnClass; - - switch (column) { - case 0: - columnClass = ParseTreeTableModel.class; - break; - case 1: - columnClass = String.class; - break; - case 2: - columnClass = Integer.class; - break; - case 3: - columnClass = Integer.class; - break; - case 4: - columnClass = String.class; - break; - default: - columnClass = Object.class; - } - return columnClass; + return pModel.getColumnClass(column); } /** + * Returns the value to be displayed for node at column number. * @param node the node * @param column the column number * @return the value to be displayed for node {@code node}, * at column number {@code column}. */ public Object getValueAt(Object node, int column) { - final DetailAST ast = (DetailAST) node; - final Object value; - - switch (column) { - case 1: - value = TokenUtils.getTokenName(ast.getType()); - break; - case 2: - value = ast.getLineNo(); - break; - case 3: - value = ast.getColumnNo(); - break; - case 4: - value = ast.getText(); - break; - default: - value = null; - } - return value; + return pModel.getValueAt(node, column); } @Override public Object getChild(Object parent, int index) { - final DetailAST ast = (DetailAST) parent; - int currentIndex = 0; - AST child = ast.getFirstChild(); - while (currentIndex < index) { - child = child.getNextSibling(); - currentIndex++; - } - return child; + return pModel.getChild(parent, index); } @Override public int getChildCount(Object parent) { - final DetailAST ast = (DetailAST) parent; - return ast.getChildCount(); + return pModel.getChildCount(parent); } @Override public void valueForPathChanged(TreePath path, Object newValue) { - //No Code, as tree is read-only + // No Code, as tree is read-only } @Override public Object getRoot() { - return root; + return pModel.getRoot(); } @Override public boolean isLeaf(Object node) { - return getChildCount(node) == 0; + return pModel.isLeaf(node); } // This is not called in the JTree's default mode: use a naive implementation. @Override public int getIndexOfChild(Object parent, Object child) { - for (int i = 0; i < getChildCount(parent); i++) { - if (getChild(parent, i).equals(child)) { - return i; - } - } - return -1; + return pModel.getIndexOfChild(parent, child); } @Override @@ -222,7 +163,7 @@ * @param children An array of Object containing the inserted, removed, or changed objects. * @see EventListenerList */ - final void fireTreeStructureChanged(Object source, Object[] path, + private void fireTreeStructureChanged(Object source, Object[] path, int[] childIndices, Object... children) { // Guaranteed to return a non-null array @@ -250,6 +191,7 @@ * @return true if editable */ public boolean isCellEditable(int column) { - return getColumnClass(column) == ParseTreeTableModel.class; + return pModel.isCellEditable(column); } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/ParseTreeTablePresentation.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/ParseTreeTablePresentation.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/ParseTreeTablePresentation.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/ParseTreeTablePresentation.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,370 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.gui; + +import java.util.HashMap; +import java.util.Map; + +import antlr.ASTFactory; +import antlr.collections.AST; +import com.puppycrawl.tools.checkstyle.JavadocDetailNodeParser; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.DetailNode; +import com.puppycrawl.tools.checkstyle.api.TokenTypes; +import com.puppycrawl.tools.checkstyle.gui.MainFrameModel.ParseMode; +import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; +import com.puppycrawl.tools.checkstyle.utils.TokenUtils; + +/** + * The model that backs the parse tree in the GUI. + * + * @author Lars Kühne + */ +public class ParseTreeTablePresentation { + + /** Exception message. */ + private static final String UNKNOWN_COLUMN_MSG = "Unknown column"; + + /** Column names. */ + private static final String[] COLUMN_NAMES = { + "Tree", + "Type", + "Line", + "Column", + "Text", + }; + + /** + * The root node of the tree table model. + */ + private final Object root; + + /** Cache to store already parsed Javadoc comments. Used for optimisation purposes. */ + private final Map blockCommentToJavadocTree = new HashMap<>(); + + /** Parsing mode. */ + private ParseMode parseMode; + + /** + * Constructor initialise root node. + * @param parseTree DetailAST parse tree. + */ + public ParseTreeTablePresentation(DetailAST parseTree) { + root = createArtificialTreeRoot(); + setParseTree(parseTree); + } + + /** + * Set parse tree. + * @param parseTree DetailAST parse tree. + */ + protected final void setParseTree(DetailAST parseTree) { + ((AST) root).setFirstChild(parseTree); + } + + /** + * Set parse mode. + * @param mode ParseMode enum + */ + protected void setParseMode(ParseMode mode) { + parseMode = mode; + } + + /** + * Returns number of available columns. + * @return the number of available columns. + */ + public int getColumnCount() { + return COLUMN_NAMES.length; + } + + /** + * Returns name for specified column number. + * @param column the column number + * @return the name for column number {@code column}. + */ + public String getColumnName(int column) { + return COLUMN_NAMES[column]; + } + + /** + * Returns type of specified column number. + * @param column the column number + * @return the type for column number {@code column}. + */ + // -@cs[ForbidWildcardAsReturnType] We need to satisfy javax.swing.table.AbstractTableModel + // public Class getColumnClass(int columnIndex) {...} + public Class getColumnClass(int column) { + final Class columnClass; + + switch (column) { + case 0: + columnClass = ParseTreeTableModel.class; + break; + case 1: + columnClass = String.class; + break; + case 2: + columnClass = Integer.class; + break; + case 3: + columnClass = Integer.class; + break; + case 4: + columnClass = String.class; + break; + default: + throw new IllegalStateException(UNKNOWN_COLUMN_MSG); + } + return columnClass; + } + + /** + * Returns the value to be displayed for node at column number. + * @param node the node + * @param column the column number + * @return the value to be displayed for node {@code node}, at column number {@code column}. + */ + public Object getValueAt(Object node, int column) { + final Object result; + + if (node instanceof DetailNode) { + result = getValueAtDetailNode((DetailNode) node, column); + } + else { + result = getValueAtDetailAST((DetailAST) node, column); + } + + return result; + } + + /** + * Returns the child of parent at index. + * @param parent the node to get a child from. + * @param index the index of a child. + * @return the child of parent at index. + */ + public Object getChild(Object parent, int index) { + final Object result; + + if (parent instanceof DetailNode) { + result = ((DetailNode) parent).getChildren()[index]; + } + else { + result = getChildAtDetailAst((DetailAST) parent, index); + } + + return result; + } + + /** + * Returns the number of children of parent. + * @param parent the node to count children for. + * @return the number of children of the node parent. + */ + public int getChildCount(Object parent) { + final int result; + + if (parent instanceof DetailNode) { + result = ((DetailNode) parent).getChildren().length; + } + else { + if (parseMode == ParseMode.JAVA_WITH_JAVADOC_AND_COMMENTS + && ((AST) parent).getType() == TokenTypes.COMMENT_CONTENT + && JavadocUtils.isJavadocComment(((DetailAST) parent).getParent())) { + //getChildCount return 0 on COMMENT_CONTENT, + //but we need to attach javadoc tree, that is separate tree + result = 1; + } + else { + result = ((DetailAST) parent).getChildCount(); + } + } + + return result; + } + + /** + * Returns value of root. + * @return the root. + */ + public Object getRoot() { + return root; + } + + /** + * Whether the node is a leaf. + * @param node the node to check. + * @return true if the node is a leaf. + */ + public boolean isLeaf(Object node) { + return getChildCount(node) == 0; + } + + /** + * Return the index of child in parent. If either {@code parent} + * or {@code child} is {@code null}, returns -1. + * If either {@code parent} or {@code child} don't + * belong to this tree model, returns -1. + * + * @param parent a node in the tree, obtained from this data source. + * @param child the node we are interested in. + * @return the index of the child in the parent, or -1 if either + * {@code child} or {@code parent} are {@code null} + * or don't belong to this tree model. + */ + public int getIndexOfChild(Object parent, Object child) { + int index = -1; + for (int i = 0; i < getChildCount(parent); i++) { + if (getChild(parent, i).equals(child)) { + index = i; + break; + } + } + return index; + } + + /** + * Indicates whether the the value for node {@code node}, at column number {@code column} is + * editable. + * @param column the column number + * @return true if editable + */ + public boolean isCellEditable(int column) { + return false; + } + + /** + * Creates artificial tree root. + * @return artificial tree root. + */ + private static DetailAST createArtificialTreeRoot() { + final ASTFactory factory = new ASTFactory(); + factory.setASTNodeClass(DetailAST.class.getName()); + return (DetailAST) factory.create(TokenTypes.EOF, "ROOT"); + } + + /** + * Gets child of DetailAST node at specified index. + * @param parent DetailAST node + * @param index child index + * @return child DetailsAST or DetailNode if child is Javadoc node + * and parseMode is JAVA_WITH_JAVADOC_AND_COMMENTS. + */ + private Object getChildAtDetailAst(DetailAST parent, int index) { + final Object result; + if (parseMode == ParseMode.JAVA_WITH_JAVADOC_AND_COMMENTS + && parent.getType() == TokenTypes.COMMENT_CONTENT + && JavadocUtils.isJavadocComment(parent.getParent())) { + result = getJavadocTree(parent.getParent()); + } + else { + int currentIndex = 0; + DetailAST child = parent.getFirstChild(); + while (currentIndex < index) { + child = child.getNextSibling(); + currentIndex++; + } + result = child; + } + + return result; + } + + /** + * Gets a value for DetailNode object. + * @param node DetailNode(Javadoc) node. + * @param column column index. + * @return value at specified column. + */ + private static Object getValueAtDetailNode(DetailNode node, int column) { + final Object value; + + switch (column) { + case 0: + // first column is tree model. no value needed + value = null; + break; + case 1: + value = JavadocUtils.getTokenName(node.getType()); + break; + case 2: + value = node.getLineNumber(); + break; + case 3: + value = node.getColumnNumber(); + break; + case 4: + value = node.getText(); + break; + default: + throw new IllegalStateException(UNKNOWN_COLUMN_MSG); + } + return value; + } + + /** + * Gets a value for DetailAST object. + * @param ast DetailAST node. + * @param column column index. + * @return value at specified column. + */ + private static Object getValueAtDetailAST(DetailAST ast, int column) { + final Object value; + + switch (column) { + case 0: + // first column is tree model. no value needed + value = null; + break; + case 1: + value = TokenUtils.getTokenName(ast.getType()); + break; + case 2: + value = ast.getLineNo(); + break; + case 3: + value = ast.getColumnNo(); + break; + case 4: + value = ast.getText(); + break; + default: + throw new IllegalStateException(UNKNOWN_COLUMN_MSG); + } + return value; + } + + /** + * Gets Javadoc (DetailNode) tree of specified block comments. + * @param blockComment Javadoc comment as a block comment + * @return DetailNode tree + */ + private DetailNode getJavadocTree(DetailAST blockComment) { + DetailNode javadocTree = blockCommentToJavadocTree.get(blockComment); + if (javadocTree == null) { + javadocTree = new JavadocDetailNodeParser().parseJavadocAsDetailNode(blockComment) + .getTree(); + blockCommentToJavadocTree.put(blockComment, javadocTree); + } + return javadocTree; + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTableCellRenderer.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTableCellRenderer.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTableCellRenderer.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTableCellRenderer.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -36,13 +36,14 @@ */ class TreeTableCellRenderer extends JTree implements TableCellRenderer { + /** * Serial ID. */ private static final long serialVersionUID = 4324031590789321581L; /** Tree table to render. */ - private final JTreeTable treeTable; + private final TreeTable treeTable; /** Last table/tree row asked to renderer. */ private int visibleRow; @@ -52,7 +53,7 @@ * @param treeTable tree table to render. * @param model Tree model. */ - TreeTableCellRenderer(JTreeTable treeTable, TreeModel model) { + TreeTableCellRenderer(TreeTable treeTable, TreeModel model) { super(model); this.treeTable = treeTable; } @@ -81,8 +82,6 @@ /** * Sets the row height of the tree, and forwards the row height to * the table. - * - * @param newRowHeight the height of each cell, in pixels */ @Override public void setRowHeight(int newRowHeight) { @@ -97,11 +96,6 @@ /** * This is overridden to set the height to match that of the JTable. - * - * @param x the new x-coordinate of this component - * @param y the new y-coordinate of this component - * @param w the new width of this component - * @param h the new height of this component */ @Override public void setBounds(int x, int y, int w, int h) { @@ -111,8 +105,6 @@ /** * Subclassed to translate the graphics such that the last visible * row will be drawn at 0,0. - * - * @param graph the Graphics context in which to paint */ @Override public void paint(Graphics graph) { @@ -122,16 +114,6 @@ /** * TreeCellRenderer method. Overridden to update the visible row. - * - * @param table the JTable that is asking the - * renderer to draw; can be null - * @param value the value of the cell to be rendered. - * @param isSelected true if the cell is to be rendered with the - * selection highlighted; otherwise false - * @param hasFocus if true, render cell appropriately. - * @param row the row index of the cell being drawn. - * @param column the column index of the cell being drawn - * @return The component used for drawing the cell. * @see TableCellRenderer */ @Override @@ -150,4 +132,5 @@ visibleRow = row; return this; } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTable.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTable.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTable.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTable.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,302 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle.gui; + +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.event.ActionEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.util.EventObject; +import java.util.List; + +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JTable; +import javax.swing.JTextArea; +import javax.swing.JTree; +import javax.swing.KeyStroke; +import javax.swing.LookAndFeel; +import javax.swing.table.TableCellEditor; +import javax.swing.tree.TreePath; + +import com.google.common.collect.ImmutableList; + +/** + * This example shows how to create a simple TreeTable component, + * by using a JTree as a renderer (and editor) for the cells in a + * particular column in the JTable. + * + * + * Original Source Location + * + * @author Philip Milne + * @author Scott Violet + * @author Lars Kühne + * @noinspection ThisEscapedInObjectConstruction + */ +public final class TreeTable extends JTable { + + private static final long serialVersionUID = -8493693409423365387L; + /** A subclass of JTree. */ + private final TreeTableCellRenderer tree; + /** JTextArea editor. */ + private JTextArea editor; + /** Line position map. */ + private List linePositionMap; + + /** + * Creates TreeTable base on TreeTableModel. + * @param treeTableModel Tree table model + */ + public TreeTable(ParseTreeTableModel treeTableModel) { + // Create the tree. It will be used as a renderer and editor. + tree = new TreeTableCellRenderer(this, treeTableModel); + + // Install a tableModel representing the visible rows in the tree. + setModel(new TreeTableModelAdapter(treeTableModel, tree)); + + // Force the JTable and JTree to share their row selection models. + final ListToTreeSelectionModelWrapper selectionWrapper = new + ListToTreeSelectionModelWrapper(this); + tree.setSelectionModel(selectionWrapper); + setSelectionModel(selectionWrapper.getListSelectionModel()); + + // Install the tree editor renderer and editor. + setDefaultRenderer(ParseTreeTableModel.class, tree); + setDefaultEditor(ParseTreeTableModel.class, new TreeTableCellEditor()); + + // No grid. + setShowGrid(false); + + // No intercell spacing + setIntercellSpacing(new Dimension(0, 0)); + + // And update the height of the trees row to match that of + // the table. + if (tree.getRowHeight() < 1) { + // Metal looks better like this. + setRowHeight(getRowHeight()); + } + + setColumnsInitialWidth(); + + final Action expand = new AbstractAction() { + private static final long serialVersionUID = -5859674518660156121L; + + @Override + public void actionPerformed(ActionEvent event) { + expandSelectedNode(); + } + }; + final KeyStroke stroke = KeyStroke.getKeyStroke("ENTER"); + final String command = "expand/collapse"; + getInputMap().put(stroke, command); + getActionMap().put(command, expand); + + addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent event) { + if (event.getClickCount() == 2) { + expandSelectedNode(); + } + } + }); + } + + /** + * Do expansion of a tree node. + */ + private void expandSelectedNode() { + final TreePath selected = tree.getSelectionPath(); + makeCodeSelection(); + + if (tree.isExpanded(selected)) { + tree.collapsePath(selected); + } + else { + tree.expandPath(selected); + } + tree.setSelectionPath(selected); + } + + /** + * Make selection of code in a text area. + */ + private void makeCodeSelection() { + new CodeSelector(tree.getLastSelectedPathComponent(), editor, linePositionMap).select(); + } + + /** + * Set initial value of width for columns in table. + */ + private void setColumnsInitialWidth() { + final FontMetrics fontMetrics = getFontMetrics(getFont()); + // Six character string to contain "Column" column. + final int widthOfSixCharacterString = fontMetrics.stringWidth("XXXXXX"); + // Padding must be added to width for columns to make them fully + // visible in table header. + final int padding = 10; + final int widthOfColumnContainingSixCharacterString = + widthOfSixCharacterString + padding; + getColumn("Line").setMaxWidth(widthOfColumnContainingSixCharacterString); + getColumn("Column").setMaxWidth(widthOfColumnContainingSixCharacterString); + final int preferredTreeColumnWidth = + Math.toIntExact(Math.round(getPreferredSize().getWidth() * 0.6)); + getColumn("Tree").setPreferredWidth(preferredTreeColumnWidth); + // Twenty eight character string to contain "Type" column + final int widthOfTwentyEightCharacterString = + fontMetrics.stringWidth("XXXXXXXXXXXXXXXXXXXXXXXXXXXX"); + final int preferredTypeColumnWidth = widthOfTwentyEightCharacterString + padding; + getColumn("Type").setPreferredWidth(preferredTypeColumnWidth); + } + + /** + * Overridden to message super and forward the method to the tree. + * Since the tree is not actually in the component hierarchy it will + * never receive this unless we forward it in this manner. + */ + @Override + public void updateUI() { + super.updateUI(); + if (tree != null) { + tree.updateUI(); + } + // Use the tree's default foreground and background colors in the + // table. + LookAndFeel.installColorsAndFont(this, "Tree.background", + "Tree.foreground", "Tree.font"); + } + + /* Workaround for BasicTableUI anomaly. Make sure the UI never tries to + * paint the editor. The UI currently uses different techniques to + * paint the renderers and editors and overriding setBounds() below + * is not the right thing to do for an editor. Returning -1 for the + * editing row in this case, ensures the editor is never painted. + */ + @Override + public int getEditingRow() { + int rowIndex = -1; + final Class editingClass = getColumnClass(editingColumn); + if (editingClass != ParseTreeTableModel.class) { + rowIndex = editingRow; + } + return rowIndex; + } + + /** + * Overridden to pass the new rowHeight to the tree. + */ + @Override + public void setRowHeight(int newRowHeight) { + super.setRowHeight(newRowHeight); + if (tree != null && tree.getRowHeight() != newRowHeight) { + tree.setRowHeight(getRowHeight()); + } + } + + /** + * Returns tree. + * @return the tree that is being shared between the model. + */ + public JTree getTree() { + return tree; + } + + /** + * Sets text area editor. + * @param textArea JTextArea component. + */ + public void setEditor(JTextArea textArea) { + editor = textArea; + } + + /** + * Sets line position map. + * @param linePositionMap Line position map. + * @noinspection AssignmentToCollectionOrArrayFieldFromParameter + */ + public void setLinePositionMap(ImmutableList linePositionMap) { + this.linePositionMap = linePositionMap; + } + + /** + * TreeTableCellEditor implementation. Component returned is the + * JTree. + */ + private class TreeTableCellEditor extends BaseCellEditor implements + TableCellEditor { + + @Override + public Component getTableCellEditorComponent(JTable table, + Object value, + boolean isSelected, + int row, int column) { + return tree; + } + + /** + * Overridden to return false, and if the event is a mouse event + * it is forwarded to the tree. + * + *

    The behavior for this is debatable, and should really be offered + * as a property. By returning false, all keyboard actions are + * implemented in terms of the table. By returning true, the + * tree would get a chance to do something with the keyboard + * events. For the most part this is ok. But for certain keys, + * such as left/right, the tree will expand/collapse where as + * the table focus should really move to a different column. Page + * up/down should also be implemented in terms of the table. + * By returning false this also has the added benefit that clicking + * outside of the bounds of the tree node, but still in the tree + * column will select the row, whereas if this returned true + * that wouldn't be the case. + * + *

    By returning false we are also enforcing the policy that + * the tree will never be editable (at least by a key sequence). + * + * @see TableCellEditor + */ + @Override + public boolean isCellEditable(EventObject event) { + if (event instanceof MouseEvent) { + for (int counter = getColumnCount() - 1; counter >= 0; + counter--) { + if (getColumnClass(counter) == ParseTreeTableModel.class) { + final MouseEvent mouseEvent = (MouseEvent) event; + final MouseEvent newMouseEvent = new MouseEvent(tree, mouseEvent.getID(), + mouseEvent.getWhen(), mouseEvent.getModifiers(), + mouseEvent.getX() - getCellRect(0, counter, true).x, + mouseEvent.getY(), mouseEvent.getClickCount(), + mouseEvent.isPopupTrigger()); + tree.dispatchEvent(newMouseEvent); + break; + } + } + } + + return false; + } + + } + +} diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTableModelAdapter.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTableModelAdapter.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTableModelAdapter.java 2016-01-30 23:19:28.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/gui/TreeTableModelAdapter.java 2018-01-14 13:38:20.000000000 +0000 @@ -1,6 +1,6 @@ //////////////////////////////////////////////////////////////////////////////// // checkstyle: Checks Java source code for adherence to a set of rules. -// Copyright (C) 2001-2016 the original author or authors. +// Copyright (C) 2001-2018 the original author or authors. // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -42,6 +42,7 @@ * @author Scott Violet */ public class TreeTableModelAdapter extends AbstractTableModel { + private static final long serialVersionUID = 8269213416115369275L; /** JTree component. */ @@ -50,6 +51,7 @@ private final transient ParseTreeTableModel treeTableModel; /** + * Initialise tree and treeTableModel class attributes. * @param treeTableModel Tree table model. * @param tree JTree component. */ @@ -113,18 +115,14 @@ * processed. SwingUtilities.invokeLater is used to handle this. */ private void delayedFireTableDataChanged() { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - fireTableDataChanged(); - } - }); + SwingUtilities.invokeLater(this::fireTableDataChanged); } /** * TreeExpansionListener that can update the table when tree changes. */ private class UpdatingTreeExpansionListener implements TreeExpansionListener { + // Don't use fireTableRowsInserted() here; the selection model // would get updated twice. @Override @@ -136,12 +134,14 @@ public void treeCollapsed(TreeExpansionEvent event) { fireTableDataChanged(); } + } /** * TreeModelListener that can update the table when tree changes. */ private class UpdatingTreeModelListener implements TreeModelListener { + @Override public void treeNodesChanged(TreeModelEvent event) { delayedFireTableDataChanged(); @@ -161,5 +161,7 @@ public void treeStructureChanged(TreeModelEvent event) { delayedFireTableDataChanged(); } + } + } diff -Nru checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/JavadocDetailNodeParser.java checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/JavadocDetailNodeParser.java --- checkstyle-6.15/src/main/java/com/puppycrawl/tools/checkstyle/JavadocDetailNodeParser.java 1970-01-01 00:00:00.000000000 +0000 +++ checkstyle-8.8/src/main/java/com/puppycrawl/tools/checkstyle/JavadocDetailNodeParser.java 2018-01-14 13:38:20.000000000 +0000 @@ -0,0 +1,770 @@ +//////////////////////////////////////////////////////////////////////////////// +// checkstyle: Checks Java source code for adherence to a set of rules. +// Copyright (C) 2001-2018 the original author or authors. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//////////////////////////////////////////////////////////////////////////////// + +package com.puppycrawl.tools.checkstyle; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; + +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.BailErrorStrategy; +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.BufferedTokenStream; +import org.antlr.v4.runtime.CommonToken; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.FailedPredicateException; +import org.antlr.v4.runtime.InputMismatchException; +import org.antlr.v4.runtime.NoViableAltException; +import org.antlr.v4.runtime.Parser; +import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; +import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.misc.Interval; +import org.antlr.v4.runtime.misc.ParseCancellationException; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.TerminalNode; + +import com.google.common.base.CaseFormat; +import com.puppycrawl.tools.checkstyle.api.DetailAST; +import com.puppycrawl.tools.checkstyle.api.DetailNode; +import com.puppycrawl.tools.checkstyle.api.JavadocTokenTypes; +import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocNodeImpl; +import com.puppycrawl.tools.checkstyle.grammars.javadoc.JavadocLexer; +import com.puppycrawl.tools.checkstyle.grammars.javadoc.JavadocParser; +import com.puppycrawl.tools.checkstyle.utils.JavadocUtils; + +/** + * Used for parsing Javadoc comment as DetailNode tree. + * @author bizmailov + * + */ +public class JavadocDetailNodeParser { + + /** + * Message key of error message. Missed close HTML tag breaks structure + * of parse tree, so parser stops parsing and generates such error + * message. This case is special because parser prints error like + * {@code "no viable alternative at input 'b \n *\n'"} and it is not + * clear that error is about missed close HTML tag. + */ + public static final String MSG_JAVADOC_MISSED_HTML_CLOSE = "javadoc.missed.html.close"; + + /** + * Message key of error message. + */ + public static final String MSG_JAVADOC_WRONG_SINGLETON_TAG = + "javadoc.wrong.singleton.html.tag"; + + /** + * Parse error while rule recognition. + */ + public static final String MSG_JAVADOC_PARSE_RULE_ERROR = "javadoc.parse.rule.error"; + + /** + * Message property key for the Unclosed HTML message. + */ + public static final String MSG_UNCLOSED_HTML_TAG = "javadoc.unclosedHtml"; + + /** Symbols with which javadoc starts. */ + private static final String JAVADOC_START = "/**"; + + /** + * Line number of the Block comment AST that is being parsed. + */ + private int blockCommentLineNumber; + + /** + * Custom error listener. + */ + private DescriptiveErrorListener errorListener; + + /** + * Parses Javadoc comment as DetailNode tree. + * @param javadocCommentAst + * DetailAST of Javadoc comment + * @return DetailNode tree of Javadoc comment + */ + public ParseStatus parseJavadocAsDetailNode(DetailAST javadocCommentAst) { + blockCommentLineNumber = javadocCommentAst.getLineNo(); + + final String javadocComment = JavadocUtils.getJavadocCommentContent(javadocCommentAst); + + // Use a new error listener each time to be able to use + // one check instance for multiple files to be checked + // without getting side effects. + errorListener = new DescriptiveErrorListener(); + + // Log messages should have line number in scope of file, + // not in scope of Javadoc comment. + // Offset is line number of beginning of Javadoc comment. + errorListener.setOffset(javadocCommentAst.getLineNo() - 1); + + final ParseStatus result = new ParseStatus(); + + try { + final JavadocParser javadocParser = createJavadocParser(javadocComment); + + final ParseTree javadocParseTree = javadocParser.javadoc(); + + final DetailNode tree = convertParseTreeToDetailNode(javadocParseTree); + // adjust first line to indent of /** + adjustFirstLineToJavadocIndent(tree, + javadocCommentAst.getColumnNo() + + JAVADOC_START.length()); + result.setTree(tree); + result.firstNonTightHtmlTag = getFirstNonTightHtmlTag(javadocParser); + } + catch (ParseCancellationException | IllegalArgumentException ex) { + ParseErrorMessage parseErrorMessage = null; + + if (ex.getCause() instanceof FailedPredicateException + || ex.getCause() instanceof NoViableAltException) { + final RecognitionException recognitionEx = (RecognitionException) ex.getCause(); + if (recognitionEx.getCtx() instanceof JavadocParser.HtmlTagContext) { + final Token htmlTagNameStart = getMissedHtmlTag(recognitionEx); + parseErrorMessage = new ParseErrorMessage( + errorListener.offset + htmlTagNameStart.getLine(), + MSG_JAVADOC_MISSED_HTML_CLOSE, + htmlTagNameStart.getCharPositionInLine(), + htmlTagNameStart.getText()); + } + } + + if (parseErrorMessage == null) { + // If syntax error occurs then message is printed by error listener + // and parser throws this runtime exception to stop parsing. + // Just stop processing current Javadoc comment. + parseErrorMessage = errorListener.getErrorMessage(); + } + + result.setParseErrorMessage(parseErrorMessage); + } + + return result; + } + + /** + * Parses block comment content as javadoc comment. + * @param blockComment + * block comment content. + * @return parse tree + * @noinspection deprecation + */ + private JavadocParser createJavadocParser(String blockComment) { + final ANTLRInputStream input = new ANTLRInputStream(blockComment); + + final JavadocLexer lexer = new JavadocLexer(input); + + final CommonTokenStream tokens = new CommonTokenStream(lexer); + + final JavadocParser parser = new JavadocParser(tokens); + + // remove default error listeners + parser.removeErrorListeners(); + + // add custom error listener that logs syntax errors + parser.addErrorListener(errorListener); + + // JavadocParserErrorStrategy stops parsing on first parse error encountered unlike the + // DefaultErrorStrategy used by ANTLR which rather attempts error recovery. + parser.setErrorHandler(new JavadocParserErrorStrategy()); + + return parser; + } + + /** + * Converts ParseTree (that is generated by ANTLRv4) to DetailNode tree. + * + * @param parseTreeNode root node of ParseTree + * @return root of DetailNode tree + * @noinspection SuspiciousArrayCast + */ + private DetailNode convertParseTreeToDetailNode(ParseTree parseTreeNode) { + final JavadocNodeImpl rootJavadocNode = createRootJavadocNode(parseTreeNode); + + JavadocNodeImpl currentJavadocParent = rootJavadocNode; + ParseTree parseTreeParent = parseTreeNode; + + while (currentJavadocParent != null) { + // remove unnecessary children tokens + if (currentJavadocParent.getType() == JavadocTokenTypes.TEXT) { + currentJavadocParent + .setChildren((DetailNode[]) JavadocNodeImpl.EMPTY_DETAIL_NODE_ARRAY); + } + + final JavadocNodeImpl[] children = + (JavadocNodeImpl[]) currentJavadocParent.getChildren(); + + insertChildrenNodes(children, parseTreeParent); + + if (children.length > 0) { + currentJavadocParent = children[0]; + parseTreeParent = parseTreeParent.getChild(0); + } + else { + JavadocNodeImpl nextJavadocSibling = (JavadocNodeImpl) JavadocUtils + .getNextSibling(currentJavadocParent); + + ParseTree nextParseTreeSibling = getNextSibling(parseTreeParent); + + if (nextJavadocSibling == null) { + JavadocNodeImpl tempJavadocParent = + (JavadocNodeImpl) currentJavadocParent.getParent(); + + ParseTree tempParseTreeParent = parseTreeParent.getParent(); + + while (nextJavadocSibling == null && tempJavadocParent != null) { + nextJavadocSibling = (JavadocNodeImpl) JavadocUtils + .getNextSibling(tempJavadocParent); + + nextParseTreeSibling = getNextSibling(tempParseTreeParent); + + tempJavadocParent = (JavadocNodeImpl) tempJavadocParent.getParent(); + tempParseTreeParent = tempParseTreeParent.getParent(); + } + } + currentJavadocParent = nextJavadocSibling; + parseTreeParent = nextParseTreeSibling; + } + } + + return rootJavadocNode; + } + + /** + * Creates child nodes for each node from 'nodes' array. + * @param parseTreeParent original ParseTree parent node + * @param nodes array of JavadocNodeImpl nodes + */ + private void insertChildrenNodes(final JavadocNodeImpl[] nodes, ParseTree parseTreeParent) { + for (int i = 0; i < nodes.length; i++) { + final JavadocNodeImpl currentJavadocNode = nodes[i]; + final ParseTree currentParseTreeNodeChild = parseTreeParent.getChild(i); + final JavadocNodeImpl[] subChildren = + createChildrenNodes(currentJavadocNode, currentParseTreeNodeChild); + currentJavadocNode.setChildren((DetailNode[]) subChildren); + } + } + + /** + * Creates children Javadoc nodes base on ParseTree node's children. + * @param parentJavadocNode node that will be parent for created children + * @param parseTreeNode original ParseTree node + * @return array of Javadoc nodes + */ + private JavadocNodeImpl[] + createChildrenNodes(JavadocNodeImpl parentJavadocNode, ParseTree parseTreeNode) { + final JavadocNodeImpl[] children = + new JavadocNodeImpl[parseTreeNode.getChildCount()]; + + for (int j = 0; j < children.length; j++) { + final JavadocNodeImpl child = + createJavadocNode(parseTreeNode.getChild(j), parentJavadocNode, j); + + children[j] = child; + } + return children; + } + + /** + * Creates root JavadocNodeImpl node base on ParseTree root node. + * @param parseTreeNode ParseTree root node + * @return root Javadoc node + */ + private JavadocNodeImpl createRootJavadocNode(ParseTree parseTreeNode) { + final JavadocNodeImpl rootJavadocNode = createJavadocNode(parseTreeNode, null, -1); + + final int childCount = parseTreeNode.getChildCount(); + final DetailNode[] children = rootJavadocNode.getChildren(); + + for (int i = 0; i < childCount; i++) { + final JavadocNodeImpl child = createJavadocNode(parseTreeNode.getChild(i), + rootJavadocNode, i); + children[i] = child; + } + rootJavadocNode.setChildren(children); + return rootJavadocNode; + } + + /** + * Creates JavadocNodeImpl node on base of ParseTree node. + * + * @param parseTree ParseTree node + * @param parent DetailNode that will be parent of new node + * @param index child index that has new node + * @return JavadocNodeImpl node on base of ParseTree node. + */ + private JavadocNodeImpl createJavadocNode(ParseTree parseTree, DetailNode parent, int index) { + final JavadocNodeImpl node = new JavadocNodeImpl(); + if (parseTree.getChildCount() == 0 + || "Text".equals(getNodeClassNameWithoutContext(parseTree))) { + node.setText(parseTree.getText()); + } + else { + node.setText(getFormattedNodeClassNameWithoutContext(parseTree)); + } + node.setColumnNumber(getColumn(parseTree)); + node.setLineNumber(getLine(parseTree) + blockCommentLineNumber); + node.setIndex(index); + node.setType(getTokenType(parseTree)); + node.setParent(parent); + node.setChildren((DetailNode[]) new JavadocNodeImpl[parseTree.getChildCount()]); + return node; + } + + /** + * Adjust first line nodes to javadoc indent. + * @param tree DetailNode tree root + * @param javadocColumnNumber javadoc indent + */ + private void adjustFirstLineToJavadocIndent(DetailNode tree, int javadocColumnNumber) { + if (tree.getLineNumber() == blockCommentLineNumber) { + ((JavadocNodeImpl) tree).setColumnNumber(tree.getColumnNumber() + javadocColumnNumber); + final DetailNode[] children = tree.getChildren(); + for (DetailNode child : children) { + adjustFirstLineToJavadocIndent(child, javadocColumnNumber); + } + } + } + + /** + * Gets line number from ParseTree node. + * @param tree + * ParseTree node + * @return line number + */ + private static int getLine(ParseTree tree) { + final int line; + if (tree instanceof TerminalNode) { + line = ((TerminalNode) tree).getSymbol().getLine() - 1; + } + else { + final ParserRuleContext rule = (ParserRuleContext) tree; + line = rule.start.getLine() - 1; + } + return line; + } + + /** + * Gets column number from ParseTree node. + * @param tree + * ParseTree node + * @return column number + */ + private static int getColumn(ParseTree tree) { + final int column; + if (tree instanceof TerminalNode) { + column = ((TerminalNode) tree).getSymbol().getCharPositionInLine(); + } + else { + final ParserRuleContext rule = (ParserRuleContext) tree; + column = rule.start.getCharPositionInLine(); + } + return column; + } + + /** + * Gets next sibling of ParseTree node. + * @param node ParseTree node + * @return next sibling of ParseTree node. + */ + private static ParseTree getNextSibling(ParseTree node) { + ParseTree nextSibling = null; + + if (node.getParent() != null) { + final ParseTree parent = node.getParent(); + int index = 0; + while (true) { + final ParseTree currentNode = parent.getChild(index); + if (currentNode.equals(node)) { + nextSibling = parent.getChild(index + 1); + break; + } + index++; + } + } + return nextSibling; + } + + /** + * Gets token type of ParseTree node from JavadocTokenTypes class. + * @param node ParseTree node. + * @return token type from JavadocTokenTypes + */ + private static int getTokenType(ParseTree node) { + final int tokenType; + + if (node.getChildCount() == 0) { + tokenType = ((TerminalNode) node).getSymbol().getType(); + } + else { + final String className = getNodeClassNameWithoutContext(node); + final String typeName = + CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, className); + tokenType = JavadocUtils.getTokenId(typeName); + } + + return tokenType; + } + + /** + * Gets class name of ParseTree node and removes 'Context' postfix at the + * end and formats it. + * @param node {@code ParseTree} node whose class name is to be formatted and returned + * @return uppercased class name without the word 'Context' and with appropriately + * inserted underscores + */ + private static String getFormattedNodeClassNameWithoutContext(ParseTree node) { + final String classNameWithoutContext = getNodeClassNameWithoutContext(node); + return CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, classNameWithoutContext); + } + + /** + * Gets class name of ParseTree node and removes 'Context' postfix at the + * end. + * @param node + * ParseTree node. + * @return class name without 'Context' + */ + private static String getNodeClassNameWithoutContext(ParseTree node) { + final String className = node.getClass().getSimpleName(); + // remove 'Context' at the end + final int contextLength = 7; + return className.substring(0, className.length() - contextLength); + } + + /** + * Method to get the missed HTML tag to generate more informative error message for the user. + * This method doesn't concern itself with + * void elements + * since it is forbidden to close them. + * Missed HTML tags for the following tags will not generate an error message from ANTLR: + * {@code + *

    + *

  • + * + * + * + * + * + *
    + *
    + * + * + *