Merge branch 'master' into issue-4176-NonSerializableClass
This commit is contained in:
42 files changed
+1006
-309
No files matched your search
@@ -6988,6 +6988,24 @@
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "jvwilge",
|
||||
"name": "Jeroen van Wilgenburg",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/251901?v=4",
|
||||
"profile": "https://vanwilgenburg.wordpress.com/",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"login": "Eldrick19",
|
||||
"name": "Eldrick Wega",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/26189114?v=4",
|
||||
"profile": "https://github.com/Eldrick19",
|
||||
"contributions": [
|
||||
"doc"
|
||||
]
|
||||
}
|
||||
],
|
||||
"contributorsPerLine": 7,
|
||||
|
||||
@@ -15,7 +15,8 @@ It uses JavaCC and Antlr to parse source files into abstract syntax trees (AST)
|
||||
Rules can be written in Java or using a XPath query.
|
||||
|
||||
It supports Java, JavaScript, Salesforce.com Apex and Visualforce,
|
||||
Modelica, PLSQL, Apache Velocity, XML, XSL, Scala.
|
||||
Modelica, PLSQL, Apache Velocity, XML, XSL.
|
||||
Scala is supported, but there are currently no Scala rules available.
|
||||
|
||||
Additionally it includes **CPD**, the copy-paste-detector. CPD finds duplicated code in
|
||||
C/C++, C#, Dart, Fortran, Go, Groovy, Java, JavaScript, JSP, Kotlin, Lua, Matlab, Modelica,
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -87,6 +87,8 @@ The tool comes with a rather extensive help text, simply running with `--help`!
|
||||
the given language `<lang>`. Parsing errors are ignored and unparsable files
|
||||
are skipped.
|
||||
|
||||
<p>Use `--use-version` to specify the language version to use, if it is not the default.</p>
|
||||
|
||||
<p>This option allows to use the xml language for files, that don't
|
||||
use xml as extension. See [example](#analyze-other-xml-formats) below.</p>"
|
||||
%}
|
||||
@@ -99,6 +101,16 @@ The tool comes with a rather extensive help text, simply running with `--help`!
|
||||
{% include custom/cli_option_row.html options="--help,-h,-H"
|
||||
description="Display help on usage."
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--use-version"
|
||||
option_arg="lang-version"
|
||||
description="The specific language version PMD should use when parsing source code for a given language.
|
||||
<p>Values are in the format of *language-version*.</p>
|
||||
<p>This option can be repeated to configure several languages for the same run.</p>
|
||||
<p>Note that this option does not change how languages are assigned to files.
|
||||
It only changes something if the project you analyze contains some files that PMD detects as the given language.
|
||||
Language detection is only influenced by file extensions and the `--force-language` option.</p>
|
||||
<p>See also [Supported Languages](#supported-languages).</p>"
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="-language,-l"
|
||||
option_arg="lang"
|
||||
description="Specify the language PMD should use. Used together with `-version`. See also [Supported Languages](#supported-languages)."
|
||||
@@ -184,16 +196,16 @@ This behavior has been introduced to ease PMD integration into scripts or hooks,
|
||||
|
||||
The language is determined automatically by PMD from the file extensions. Some languages such as "Java"
|
||||
however support multiple versions. The default version will be used, which is usually the latest supported
|
||||
version. If you want to use an older version, so that e.g. rules, that suggest usage of language features,
|
||||
that are not available yet, won't be executed, you need to specify a specific version via the `-language`
|
||||
and `-version` parameter.
|
||||
non-preview version. If you want to use an older version, so that e.g. rules that suggest usage of language features
|
||||
that are not available yet won't be executed, you need to specify a specific version via the `--use-version`
|
||||
parameter.
|
||||
|
||||
These parameters are irrelevant for languages that don't support different versions.
|
||||
|
||||
Example:
|
||||
|
||||
``` shell
|
||||
./run.sh pmd -d src/main/java -f text -R rulesets/java/quickstart.xml -language java -version 8
|
||||
./run.sh pmd -d src/main/java -f text -R rulesets/java/quickstart.xml --use-version java-1.8
|
||||
```
|
||||
|
||||
* [apex](pmd_rules_apex.html) (Salesforce Apex)
|
||||
|
||||
@@ -62,7 +62,7 @@ Novice as much as advanced readers may want to [read on on Refactoring Guru](htt
|
||||
description="The minimum token length which should be reported as a duplicate."
|
||||
required="yes"
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--files"
|
||||
{% include custom/cli_option_row.html options="--files,--dir,-d"
|
||||
description="List of files and directories to process"
|
||||
required="yes"
|
||||
%}
|
||||
@@ -73,10 +73,10 @@ Novice as much as advanced readers may want to [read on on Refactoring Guru](htt
|
||||
description="Sources code language."
|
||||
default="java"
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--debug,--verbose"
|
||||
{% include custom/cli_option_row.html options="--debug,--verbose,-v,-D"
|
||||
description="Debug mode. Prints more log output."
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--encoding"
|
||||
{% include custom/cli_option_row.html options="--encoding,-e"
|
||||
description="Character encoding to use when processing files. If not specified, CPD uses the system default encoding."
|
||||
%}
|
||||
{% include custom/cli_option_row.html options="--skip-duplicate-files"
|
||||
@@ -220,8 +220,10 @@ This behavior has been introduced to ease CPD integration into scripts or hooks,
|
||||
* Dart
|
||||
* EcmaScript (JavaScript)
|
||||
* Fortran
|
||||
* Gherkin (Cucumber)
|
||||
* Go
|
||||
* Groovy
|
||||
* Html
|
||||
* Java
|
||||
* Jsp
|
||||
* Kotlin
|
||||
@@ -368,7 +370,7 @@ For Windows:
|
||||
|
||||
For Linux:
|
||||
|
||||
./run.sh cpdgui
|
||||
./run.sh cpd-gui
|
||||
|
||||
Here's a screenshot of CPD after running on the JDK 8 java.lang package:
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ sidebar: pmd_sidebar
|
||||
* For Windows: [Winzip](http://winzip.com) or the free [7-zip](http://www.7-zip.org/)
|
||||
* For Linux / Unix: [InfoZip](http://infozip.sourceforge.net/)
|
||||
|
||||
{% include note.html content="For executing the Designer (./run.sh designer) using [OpenJDK](http://jdk.java.net) or Java 11, you need additionally [OpenJFX](https://openjfx.io/). Download it, extract it and set the environment variable JAVAFX_HOME." %}
|
||||
{% include note.html content="For executing the Designer (./run.sh designer) using [OpenJDK](http://jdk.java.net) or Java 11, you need additionally [JavaFX](https://gluonhq.com/products/javafx/). Download it, extract it and set the environment variable JAVAFX_HOME pointing at that directory." %}
|
||||
|
||||
|
||||
### Installation
|
||||
|
||||
@@ -23,15 +23,80 @@ This is a {{ site.pmd.release_type }} release.
|
||||
The property `prefix` has been deprecated, since in a serializable class all fields have to be
|
||||
serializable regardless of the name.
|
||||
|
||||
#### Modified rules
|
||||
|
||||
* The rule {% rule java/codestyle/ClassNamingConventions %} has a new property `testClassPattern`, which is applied
|
||||
to test classes. By default, test classes should end with the suffix "Test". Test classes are top-level classes, that
|
||||
either inherit from JUnit 3 TestCase or have at least one method annotated with the Test annotations from
|
||||
JUnit4/5 or TestNG.
|
||||
|
||||
### Fixed Issues
|
||||
* cli
|
||||
* [#4215](https://github.com/pmd/pmd/discussions/4215): NullPointerException when trying to open designer
|
||||
* java
|
||||
* [#3643](https://github.com/pmd/pmd/issues/3643): \[java] More parser edge cases
|
||||
* [#4152](https://github.com/pmd/pmd/issues/4152): \[java] Parse error on array type annotations
|
||||
* java-codestyle
|
||||
* [#2867](https://github.com/pmd/pmd/issues/2867): \[java] Separate pattern for test classes in ClassNamingConventions rule for Java
|
||||
* [#4201](https://github.com/pmd/pmd/issues/4201): \[java] CommentDefaultAccessModifier should consider lombok's @<!-- -->Value
|
||||
* java-design
|
||||
* [#4200](https://github.com/pmd/pmd/issues/4200): \[java] ClassWithOnlyPrivateConstructorsShouldBeFinal should consider lombok's @<!-- -->Value
|
||||
* java-errorprone
|
||||
* [#1668](https://github.com/pmd/pmd/issues/1668): \[java] BeanMembersShouldSerialize is extremely noisy
|
||||
* [#4176](https://github.com/pmd/pmd/issues/4176): \[java] Rename BeanMembersShouldSerialize to NonSerializableClass
|
||||
* [#4185](https://github.com/pmd/pmd/issues/4185): \[java] InvalidLogMessageFormat rule produces a NPE
|
||||
|
||||
### API Changes
|
||||
|
||||
#### PMD CLI
|
||||
|
||||
* PMD now supports a new `--use-version` flag, which receives a language-version pair (such as `java-8` or `apex-54`).
|
||||
This supersedes the usage of `-language` / `-l` and `-version` / `-v`, allowing for multiple versions to be set in a single run.
|
||||
PMD 7 will completely remove support for `-language` and `-version` in favor of this new flag.
|
||||
|
||||
* Support for `-V` is being deprecated in favor of `--verbose` in preparation for PMD 7.
|
||||
In PMD 7, `-v` will enable verbose mode and `-V` will show the PMD version for consistency with most Unix/Linux tools.
|
||||
|
||||
* Support for `-min` is being deprecated in favor of `--minimum-priority` for consistency with most Unix/Linux tools, where `-min` would be equivalent to `-m -i -n`.
|
||||
|
||||
#### CPD CLI
|
||||
|
||||
* CPD now supports using `-d` or `--dir` as an alias to `--files`, in favor of consistency with PMD.
|
||||
PMD 7 will remove support for `--files` in favor of these new flags.
|
||||
|
||||
#### Linux run.sh parameters
|
||||
|
||||
* Using `run.sh cpdgui` will now warn about it being deprecated. Use `run.sh cpd-gui` instead.
|
||||
|
||||
* The old designer (`run.sh designerold`) is completely deprecated and will be removed in PMD 7. Switch to the new JavaFX designer: `run.sh designer`.
|
||||
|
||||
* The old visual AST viewer (`run.sh bgastviewer`) is completely deprecated and will be removed in PMD 7. Switch to the new JavaFX designer: `run.sh designer` for a visual tool, or use `run.sh ast-dump` for a text-based aleternative.
|
||||
|
||||
#### Deprecated API
|
||||
|
||||
The following APIs have been marked as deprecated for removal in PMD 7:
|
||||
|
||||
- {% jdoc core::PMD %} and {% jdoc core::PMD.StatusCode %} - PMD 7 will ship with a revamped CLI split from pmd-core. To programatically launch analysis you can use {% jdoc core::PmdAnalysis %}.
|
||||
- {% jdoc !!core::PMDConfiguration#getAllInputPaths() %} - It is now superceded by {% jdoc !!core::PMDConfiguration#getInputPathList() %}
|
||||
- {% jdoc !!core::PMDConfiguration#setInputPaths(List) %} - It is now superceded by {% jdoc !!core::PMDConfiguration#setInputPathList(List) %}
|
||||
- {% jdoc !!core::PMDConfiguration#addInputPath(String) %} - It is now superceded by {% jdoc !!core::PMDConfiguration#addInputPath(Path) %}
|
||||
- {% jdoc !!core::PMDConfiguration#getInputFilePath() %} - It is now superceded by {% jdoc !!core::PMDConfiguration#getInputFile() %}
|
||||
- {% jdoc !!core::PMDConfiguration#getIgnoreFilePath() %} - It is now superceded by {% jdoc !!core::PMDConfiguration#getIgnoreFile() %}
|
||||
- {% jdoc !!core::PMDConfiguration#setInputFilePath(String) %} - It is now superceded by {% jdoc !!core::PMDConfiguration#setInputFilePath(Path) %}
|
||||
- {% jdoc !!core::PMDConfiguration#setIgnoreFilePath(String) %} - It is now superceded by {% jdoc !!core::PMDConfiguration#setIgnoreFilePath(Path) %}
|
||||
- {% jdoc !!core::PMDConfiguration#getInputUri() %} - It is now superceded by {% jdoc !!core::PMDConfiguration#getUri() %}
|
||||
- {% jdoc !!core::PMDConfiguration#setInputUri(String) %} - It is now superceded by {% jdoc !!core::PMDConfiguration#setInputUri(URI) %}
|
||||
- {% jdoc !!core::PMDConfiguration#getReportFile() %} - It is now superceded by {% jdoc !!core::PMDConfiguration#getReportFilePath() %}
|
||||
- {% jdoc !!core::PMDConfiguration#setReportFile(String) %} - It is now superceded by {% jdoc !!core::PMDConfiguration#setReportFile(Path) %}
|
||||
- {% jdoc !!core::PMDConfiguration#isStressTest() %} and {% jdoc !!core::PMDConfiguration#setStressTest(boolean) %} - Will be removed with no replacement.
|
||||
- {% jdoc !!core::PMDConfiguration#isBenchmark() %} and {% jdoc !!core::PMDConfiguration#setBenchmark(boolean) %} - Will be removed with no replacement, the CLI will still support it.
|
||||
- {% jdoc core::cpd.CPD %} and {% jdoc core::cpd.CPD.StatusCode %} - PMD 7 will ship with a revamped CLI split from pmd-core. An alterative to programatically launch CPD analysis will be added in due time.
|
||||
|
||||
### External Contributions
|
||||
* [#4184](https://github.com/pmd/pmd/pull/4184): \[java]\[doc] TestClassWithoutTestCases - fix small typo in description - [Valery Yatsynovich](https://github.com/valfirst) (@valfirst)
|
||||
* [#4198](https://github.com/pmd/pmd/pull/4198): \[doc] Add supported CPD languages - [Jeroen van Wilgenburg](https://github.com/jvwilge) (@jvwilge)
|
||||
* [#4202](https://github.com/pmd/pmd/pull/4202): \[java] Fix #4200 and #4201: ClassWithOnlyPrivateConstructorsShouldBeFinal, CommentDefaultAccessModifier: Exclude lombok @<!-- -->Value annotation - [Lynn](https://github.com/LynnBroe) (@LynnBroe)
|
||||
* [#4205](https://github.com/pmd/pmd/pull/4205): \[doc] Clarify Scala support (no built-in rules) - [Eldrick Wega](https://github.com/Eldrick19) (@Eldrick19)
|
||||
|
||||
{% endtocmaker %}
|
||||
|
||||
@@ -60,7 +60,10 @@ import net.sourceforge.pmd.util.log.internal.SimpleMessageReporter;
|
||||
*
|
||||
* <p><strong>Warning:</strong> This class is not intended to be instantiated or subclassed. It will
|
||||
* be made final in PMD7.
|
||||
*
|
||||
* @deprecated This class is to be removed in PMD 7 in favor of a unified PmdCli entry point. {@link PmdAnalysis} should be used for non-CLI use-cases.
|
||||
*/
|
||||
@Deprecated
|
||||
public class PMD {
|
||||
|
||||
|
||||
@@ -539,7 +542,9 @@ public class PMD {
|
||||
* Represents status codes that are used as exit codes during CLI runs.
|
||||
*
|
||||
* @see #runPmd(String[])
|
||||
* @deprecated This class is to be removed in PMD 7 in favor of a unified PmdCli entry point.
|
||||
*/
|
||||
@Deprecated
|
||||
public enum StatusCode {
|
||||
/** No errors, no violations. This is exit code {@code 0}. */
|
||||
OK(0),
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -14,6 +14,7 @@ import net.sourceforge.pmd.PMD;
|
||||
import net.sourceforge.pmd.PMDConfiguration;
|
||||
import net.sourceforge.pmd.RulePriority;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
import net.sourceforge.pmd.lang.Language;
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
|
||||
@@ -163,6 +164,9 @@ public class PMDParameters {
|
||||
@Parameter(names = { "--no-cache", "-no-cache" }, description = "Explicitly disable incremental analysis. The '-cache' option is ignored if this switch is present in the command line.")
|
||||
private boolean noCache = false;
|
||||
|
||||
@Parameter(names = "--use-version", description = "The language version PMD should use when parsing source code in the language-version format, ie: 'java-1.8'")
|
||||
private List<String> languageVersions = new ArrayList<>();
|
||||
|
||||
// this has to be a public static class, so that JCommander can use it!
|
||||
public static class PropertyConverter implements IStringConverter<Properties> {
|
||||
|
||||
@@ -258,6 +262,24 @@ public class PMDParameters {
|
||||
configuration.getLanguageVersionDiscoverer().setDefaultLanguageVersion(languageVersion);
|
||||
}
|
||||
|
||||
for (String langVerStr : this.getLanguageVersions()) {
|
||||
int dashPos = langVerStr.indexOf('-');
|
||||
if (dashPos == -1) {
|
||||
throw new IllegalArgumentException("Invalid language version: " + langVerStr);
|
||||
}
|
||||
String langStr = langVerStr.substring(0, dashPos);
|
||||
String verStr = langVerStr.substring(dashPos + 1);
|
||||
Language lang = LanguageRegistry.findLanguageByTerseName(langStr);
|
||||
LanguageVersion langVer = null;
|
||||
if (lang != null) {
|
||||
langVer = lang.getVersion(verStr);
|
||||
}
|
||||
if (lang == null || langVer == null) {
|
||||
throw new IllegalArgumentException("Invalid language version: " + langVerStr);
|
||||
}
|
||||
configuration.getLanguageVersionDiscoverer().setDefaultLanguageVersion(langVer);
|
||||
}
|
||||
|
||||
try {
|
||||
configuration.prependAuxClasspath(this.getAuxclasspath());
|
||||
} catch (IllegalArgumentException e) {
|
||||
@@ -348,6 +370,10 @@ public class PMDParameters {
|
||||
return language != null ? language : LanguageRegistry.getDefaultLanguage().getTerseName();
|
||||
}
|
||||
|
||||
public List<String> getLanguageVersions() {
|
||||
return languageVersions;
|
||||
}
|
||||
|
||||
public String getForceLanguage() {
|
||||
return forceLanguage != null ? forceLanguage : "";
|
||||
}
|
||||
|
||||
@@ -166,6 +166,13 @@ public final class PmdParametersParseResult {
|
||||
m.put("-norulesetcompatibility", "--no-ruleset-compatibility");
|
||||
m.put("-cache", "--cache");
|
||||
m.put("-no-cache", "--no-cache");
|
||||
m.put("-v", "--use-version"); // In PMD 7, -v will enable verbose mode
|
||||
m.put("-V", "--verbose"); // In PMD 7, -V will show the tool version
|
||||
m.put("-min", "--minimum-priority");
|
||||
m.put("-version", "--use-version");
|
||||
m.put("-language", "--use-version");
|
||||
m.put("-l", "--use-version");
|
||||
|
||||
SUGGESTED_REPLACEMENT = Collections.unmodifiableMap(m);
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,10 @@ import net.sourceforge.pmd.util.database.DBURI;
|
||||
import net.sourceforge.pmd.util.database.SourceObject;
|
||||
import net.sourceforge.pmd.util.log.ScopedLogHandlersManager;
|
||||
|
||||
/**
|
||||
* @deprecated This class is to be removed in PMD 7 in favor of a unified PmdCli entry point.
|
||||
*/
|
||||
@Deprecated
|
||||
public class CPD {
|
||||
private static final Logger LOGGER = Logger.getLogger(CPD.class.getName());
|
||||
|
||||
@@ -257,6 +261,10 @@ public class CPD {
|
||||
return new CPDReport(matchAlgorithm.getMatches(), numberOfTokensPerFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated This class is to be removed in PMD 7 in favor of a unified PmdCli entry point.
|
||||
*/
|
||||
@Deprecated
|
||||
public enum StatusCode {
|
||||
OK(0),
|
||||
ERROR(1),
|
||||
|
||||
@@ -133,6 +133,7 @@ public final class CPDCommandLineInterface {
|
||||
m.put("--failOnViolation", "--fail-on-violation");
|
||||
m.put("-failOnViolation", "--fail-on-violation");
|
||||
m.put("--filelist", "--file-list");
|
||||
m.put("--files", "--dir");
|
||||
SUGGESTED_REPLACEMENT = Collections.unmodifiableMap(m);
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ public class CPDConfiguration extends AbstractConfiguration {
|
||||
required = false)
|
||||
private String skipBlocksPattern = Tokenizer.DEFAULT_SKIP_BLOCKS_PATTERN;
|
||||
|
||||
@Parameter(names = "--files", variableArity = true, description = "List of files and directories to process",
|
||||
@Parameter(names = { "--files", "-d", "--dir" }, variableArity = true, description = "List of files and directories to process",
|
||||
required = false, converter = FileConverter.class)
|
||||
private List<File> files;
|
||||
|
||||
@@ -141,7 +141,7 @@ public class CPDConfiguration extends AbstractConfiguration {
|
||||
description = "By default CPD exits with status 4 if code duplications are found. Disable this option with '-failOnViolation false' to exit with 0 instead and just write the report.")
|
||||
private boolean failOnViolation = true;
|
||||
|
||||
@Parameter(names = { "--debug", "--verbose" }, description = "Debug mode.")
|
||||
@Parameter(names = { "--debug", "--verbose", "-v", "-D" }, description = "Debug mode.")
|
||||
private boolean debug = false;
|
||||
|
||||
// this has to be a public static class, so that JCommander can use it!
|
||||
@@ -156,7 +156,7 @@ public class CPDConfiguration extends AbstractConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
@Parameter(names = "--encoding", description = "Character encoding to use when processing files", required = false)
|
||||
@Parameter(names = { "--encoding", "-e" }, description = "Character encoding to use when processing files", required = false)
|
||||
public void setEncoding(String encoding) {
|
||||
this.encoding = encoding;
|
||||
setSourceEncoding(encoding);
|
||||
|
||||
@@ -10,7 +10,7 @@ usage() {
|
||||
}
|
||||
|
||||
valid_app_options () {
|
||||
echo "pmd, cpd, cpdgui, designer, bgastviewer, designerold, ast-dump"
|
||||
echo "pmd, cpd, cpd-gui, designer, bgastviewer, designerold, ast-dump"
|
||||
}
|
||||
|
||||
is_cygwin() {
|
||||
@@ -159,10 +159,12 @@ function add_openjfx_classpath() {
|
||||
then
|
||||
script_exit "The environment variable JAVAFX_HOME is missing."
|
||||
else
|
||||
# The wildcard will include only jar files, but we need to access also
|
||||
# property files such as javafx.properties that lay bare in the dir
|
||||
if [ -n "$classpath" ]; then
|
||||
classpath="$classpath:${JAVAFX_HOME}/lib/*"
|
||||
classpath="$classpath:${JAVAFX_HOME}/lib/*:${JAVAFX_HOME}/lib/"
|
||||
else
|
||||
classpath="${JAVAFX_HOME}/lib/*"
|
||||
classpath="${JAVAFX_HOME}/lib/*:${JAVAFX_HOME}/lib/"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -187,12 +189,18 @@ case "${APPNAME}" in
|
||||
readonly CLASSNAME="net.sourceforge.pmd.util.fxdesigner.DesignerStarter"
|
||||
;;
|
||||
"designerold")
|
||||
echo "'designerold' is deprecated and will be removed in PMD 7.0.0, try the new 'designer' instead."
|
||||
readonly CLASSNAME="net.sourceforge.pmd.util.designer.Designer"
|
||||
;;
|
||||
"bgastviewer")
|
||||
echo "'bgastviewer' is deprecated and will be removed in PMD 7.0.0, try the new 'designer' instead."
|
||||
readonly CLASSNAME="net.sourceforge.pmd.util.viewer.Viewer"
|
||||
;;
|
||||
"cpdgui")
|
||||
echo "'cpdgui' is deprecated and will be removed in PMD 7.0.0, use 'cpd-gui' instead."
|
||||
readonly CLASSNAME="net.sourceforge.pmd.cpd.GUI"
|
||||
;;
|
||||
"cpd-gui")
|
||||
readonly CLASSNAME="net.sourceforge.pmd.cpd.GUI"
|
||||
;;
|
||||
"ast-dump")
|
||||
|
||||
@@ -736,6 +736,12 @@ public class JavaParser {
|
||||
token_source.setSuppressMarker(marker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps track during tree construction, whether we are currently building an
|
||||
* explicit constructor invocation. Then the PrimaryExpression that may prefix
|
||||
* a qualified super constructor call may not consume "super" tokens.
|
||||
*/
|
||||
private boolean inExplicitConstructorInvoc = false;
|
||||
|
||||
}
|
||||
PARSER_END(JavaParser)
|
||||
@@ -1377,7 +1383,7 @@ void RecordComponent():
|
||||
{
|
||||
(RecordComponentModifier())*
|
||||
Type()
|
||||
[ "..." {jjtThis.setVarargs();} ]
|
||||
[ (TypeAnnotation())* "..." {jjtThis.setVarargs();} ]
|
||||
VariableDeclaratorId()
|
||||
}
|
||||
|
||||
@@ -1454,7 +1460,7 @@ void ClassOrInterfaceBodyDeclaration():
|
||||
| LOOKAHEAD({isKeyword("enum")}) EnumDeclaration(modifiers)
|
||||
| LOOKAHEAD({isKeyword("record")}) RecordDeclaration(modifiers)
|
||||
| LOOKAHEAD( [ TypeParameters() ] <IDENTIFIER> "(" ) ConstructorDeclaration(modifiers)
|
||||
| LOOKAHEAD( Type() <IDENTIFIER> ( "[" "]" )* ( "," | "=" | ";" ) ) FieldDeclaration(modifiers)
|
||||
| LOOKAHEAD( Type() <IDENTIFIER> ( (Annotation())* "[" "]" )* ( "," | "=" | ";" ) ) FieldDeclaration(modifiers)
|
||||
| LOOKAHEAD(2) MethodDeclaration(modifiers)
|
||||
| LOOKAHEAD(2) AnnotationTypeDeclaration(modifiers)
|
||||
)
|
||||
@@ -1483,7 +1489,7 @@ void VariableDeclaratorId() :
|
||||
{
|
||||
(LOOKAHEAD(2) t=<IDENTIFIER> "." <THIS> { checkforBadExplicitReceiverParameter(); jjtThis.setExplicitReceiverParameter(); image=t.image + ".this"; }
|
||||
| t=<THIS> { checkforBadExplicitReceiverParameter(); jjtThis.setExplicitReceiverParameter(); image = t.image;}
|
||||
| t=<IDENTIFIER> { image = t.image; } ( "[" "]" { jjtThis.bumpArrayDepth(); })*
|
||||
| t=<IDENTIFIER> { image = t.image; } ( (TypeAnnotation())* "[" "]" { jjtThis.bumpArrayDepth(); })*
|
||||
)
|
||||
{
|
||||
checkForBadAssertUsage(image, "a variable name");
|
||||
@@ -1526,7 +1532,7 @@ void MethodDeclarator() :
|
||||
checkForBadEnumUsage(t.image, "a method name");
|
||||
jjtThis.setImage( t.image );
|
||||
}
|
||||
FormalParameters() ( "[" "]" )*
|
||||
FormalParameters() ( (TypeAnnotation())* "[" "]" )*
|
||||
}
|
||||
|
||||
|
||||
@@ -1541,8 +1547,8 @@ void FormalParameter() :
|
||||
}
|
||||
{
|
||||
( "final" {jjtThis.setFinal(true);} | Annotation() )*
|
||||
Type() ("|" {checkForBadMultipleExceptionsCatching();} Type())*
|
||||
[ "..." {checkForBadVariableArgumentsUsage();} {jjtThis.setVarargs();} ]
|
||||
Type() ("|" {checkForBadMultipleExceptionsCatching();} (TypeAnnotation())* Type())*
|
||||
[ (TypeAnnotation())* "..." {checkForBadVariableArgumentsUsage();} {jjtThis.setVarargs();} ]
|
||||
VariableDeclaratorId()
|
||||
}
|
||||
|
||||
@@ -1559,13 +1565,14 @@ Token t;}
|
||||
}
|
||||
|
||||
void ExplicitConstructorInvocation() :
|
||||
{}
|
||||
{
|
||||
LOOKAHEAD("this" Arguments() ";") "this" {jjtThis.setIsThis();} Arguments() ";"
|
||||
{boolean prev = inExplicitConstructorInvoc; inExplicitConstructorInvoc = true;}
|
||||
{ (
|
||||
LOOKAHEAD([TypeArguments()] "this" Arguments() ";") [TypeArguments()] "this" {jjtThis.setIsThis();}
|
||||
|
|
||||
LOOKAHEAD(TypeArguments() "this" Arguments() ";") TypeArguments() "this" {jjtThis.setIsThis();} Arguments() ";"
|
||||
|
|
||||
[ LOOKAHEAD(PrimaryExpression() ".") PrimaryExpression() "." ] [ TypeArguments() ] "super" {jjtThis.setIsSuper();} Arguments() ";"
|
||||
[ LOOKAHEAD(PrimaryExpression() "." [TypeArguments()] "super" ) PrimaryExpression() "." ] [ TypeArguments() ] "super" {jjtThis.setIsSuper();}
|
||||
)
|
||||
{inExplicitConstructorInvoc = prev;}
|
||||
Arguments() ";"
|
||||
}
|
||||
|
||||
void Initializer() :
|
||||
@@ -1586,18 +1593,16 @@ void Type():
|
||||
Token t;
|
||||
}
|
||||
{
|
||||
LOOKAHEAD(2) ReferenceType()
|
||||
LOOKAHEAD(<IDENTIFIER> | PrimitiveType() (TypeAnnotation())* "[" "]" ) ReferenceType()
|
||||
| PrimitiveType()
|
||||
}
|
||||
|
||||
void ReferenceType():
|
||||
{}
|
||||
{
|
||||
// The grammar here is mildly wrong, the annotations can be before each []
|
||||
// This will wait for #997
|
||||
PrimitiveType() (TypeAnnotation())* ( LOOKAHEAD(2) "[" "]" { jjtThis.bumpArrayDepth(); })+
|
||||
PrimitiveType() (LOOKAHEAD((TypeAnnotation())* "[" "]") (TypeAnnotation())* "[" "]" { jjtThis.bumpArrayDepth(); })+
|
||||
|
|
||||
( ClassOrInterfaceType()) (TypeAnnotation())* ( LOOKAHEAD(2) "[" "]" { jjtThis.bumpArrayDepth(); })*
|
||||
ClassOrInterfaceType() (LOOKAHEAD((TypeAnnotation())* "[" "]") (TypeAnnotation())* "[" "]" { jjtThis.bumpArrayDepth(); })*
|
||||
}
|
||||
|
||||
void ClassOrInterfaceType():
|
||||
@@ -1608,7 +1613,7 @@ void ClassOrInterfaceType():
|
||||
{
|
||||
t=<IDENTIFIER> {s.append(t.image);}
|
||||
[ LOOKAHEAD(2) TypeArguments() ]
|
||||
( LOOKAHEAD(2) "." t=<IDENTIFIER> {s.append('.').append(t.image);} [ LOOKAHEAD(2) TypeArguments() ] )*
|
||||
( LOOKAHEAD(2) "." (TypeAnnotation())* t=<IDENTIFIER> {s.append('.').append(t.image);} [ LOOKAHEAD(2) TypeArguments() ] )*
|
||||
{jjtThis.setImage(s.toString());}
|
||||
}
|
||||
|
||||
@@ -1740,8 +1745,6 @@ void AssignmentOperator() :
|
||||
| "|=" {jjtThis.setImage("|="); jjtThis.setCompound();}
|
||||
}
|
||||
|
||||
// TODO Setting isTernary is unnecessary, since the node is only pushed on the stack if there is at least one child,
|
||||
// ie if it's a ternary
|
||||
void ConditionalExpression() #ConditionalExpression(>1) :
|
||||
{}
|
||||
{
|
||||
@@ -1787,7 +1790,7 @@ void EqualityExpression() #EqualityExpression(>1):
|
||||
void Pattern() #void:
|
||||
{}
|
||||
{
|
||||
LOOKAHEAD(ReferenceType() "(") RecordPattern()
|
||||
LOOKAHEAD((Annotation())* ReferenceType() "(") RecordPattern()
|
||||
| LOOKAHEAD("(") ParenthesizedPattern()
|
||||
| TypePattern() [ GuardedPatternCondition() #GuardedPattern(2) {checkForGuardedPatterns();} ]
|
||||
}
|
||||
@@ -1815,7 +1818,7 @@ void TypePattern():
|
||||
void RecordPattern():
|
||||
{ checkForRecordPatterns(); }
|
||||
{
|
||||
ReferenceType() RecordStructurePattern() [ VariableDeclaratorId() ]
|
||||
(Annotation())* ReferenceType() RecordStructurePattern() [ VariableDeclaratorId() ]
|
||||
}
|
||||
|
||||
void RecordStructurePattern() #ComponentPatternList:
|
||||
@@ -1836,14 +1839,13 @@ void InstanceOfExpression() #InstanceOfExpression(>1):
|
||||
RelationalExpression()
|
||||
[ "instanceof"
|
||||
(
|
||||
LOOKAHEAD("final" | "@") {checkforBadInstanceOfPattern();} Pattern()
|
||||
|
|
||||
LOOKAHEAD("(") Pattern() {checkForParenthesizedInstanceOfPattern();}
|
||||
|
|
||||
LOOKAHEAD(ReferenceType() "(") RecordPattern()
|
||||
|
|
||||
Type()
|
||||
[ {checkforBadInstanceOfPattern();} VariableDeclaratorId() #TypePattern(2) ]
|
||||
// Note: this can be simplified when support for java 18 preview is removed.
|
||||
// Here the production Pattern is inlined to avoid that a following conditional &&
|
||||
// be parsed as a pattern guard.
|
||||
LOOKAHEAD("final" | (Annotation())* Type() <IDENTIFIER>) {checkforBadInstanceOfPattern();} TypePattern()
|
||||
| LOOKAHEAD((Annotation())* ReferenceType() "(") {checkForRecordPatterns();} RecordPattern()
|
||||
| LOOKAHEAD("(") {checkForParenthesizedInstanceOfPattern();} ParenthesizedPattern()
|
||||
| (Annotation())* Type()
|
||||
)
|
||||
]
|
||||
}
|
||||
@@ -1959,9 +1961,18 @@ void SwitchExpression() :
|
||||
void PrimaryExpression() :
|
||||
{}
|
||||
{
|
||||
PrimaryPrefix() ( LOOKAHEAD(2) PrimarySuffix() )*
|
||||
PrimaryPrefix() ( LOOKAHEAD(SuffixLAhead()) PrimarySuffix() )*
|
||||
}
|
||||
|
||||
private void SuffixLAhead() #void:
|
||||
{}
|
||||
{
|
||||
"::" | "[" | "("
|
||||
| LOOKAHEAD({!inExplicitConstructorInvoc}) "."
|
||||
| LOOKAHEAD({inExplicitConstructorInvoc}) "." (<IDENTIFIER> | TypeArguments() <IDENTIFIER> | "new") // not super or this in this case
|
||||
}
|
||||
|
||||
|
||||
void MemberSelector():
|
||||
{
|
||||
Token t;
|
||||
@@ -1989,8 +2000,8 @@ void PrimaryPrefix() :
|
||||
| LOOKAHEAD(3) "(" Expression() ")"
|
||||
| AllocationExpression()
|
||||
| LOOKAHEAD( ResultType() "." "class" ) ResultType() "." "class"
|
||||
| LOOKAHEAD( Name() "::" ) Name()
|
||||
| LOOKAHEAD( ReferenceType() MethodReference() ) ReferenceType() MethodReference()
|
||||
| LOOKAHEAD( Name() "::" ) Name() // followed by method reference in PrimarySuffix
|
||||
| LOOKAHEAD( "@" | Type() "::" ) (Annotation())* (LOOKAHEAD(2) ReferenceType()|PrimitiveType()) // followed by method reference in PrimarySuffix
|
||||
| Name()
|
||||
}
|
||||
|
||||
@@ -2019,7 +2030,7 @@ void LambdaParameter() #FormalParameter :
|
||||
{
|
||||
( "final" {jjtThis.setFinal(true);} | Annotation() )*
|
||||
LambdaParameterType()
|
||||
[ "..." {checkForBadVariableArgumentsUsage();} {jjtThis.setVarargs();} ]
|
||||
[(TypeAnnotation())* "..." {checkForBadVariableArgumentsUsage();} {jjtThis.setVarargs();} ]
|
||||
VariableDeclaratorId()
|
||||
}
|
||||
|
||||
@@ -2079,10 +2090,12 @@ void ArgumentList() :
|
||||
void AllocationExpression():
|
||||
{}
|
||||
{
|
||||
"new" (TypeAnnotation())*
|
||||
(LOOKAHEAD(2)
|
||||
PrimitiveType() ArrayDimsAndInits()
|
||||
"new"
|
||||
(LOOKAHEAD((TypeAnnotation())* PrimitiveType())
|
||||
(TypeAnnotation())* PrimitiveType() ArrayDimsAndInits()
|
||||
|
|
||||
[TypeArguments()]
|
||||
(TypeAnnotation())*
|
||||
ClassOrInterfaceType()
|
||||
(
|
||||
ArrayDimsAndInits()
|
||||
@@ -2105,11 +2118,10 @@ void AllocationExpression():
|
||||
void ArrayDimsAndInits() :
|
||||
{}
|
||||
{
|
||||
LOOKAHEAD((TypeAnnotation())* "[" "]") ((TypeAnnotation())* "[" "]" {jjtThis.bumpArrayDepth();})+ ArrayInitializer()
|
||||
| ( LOOKAHEAD((TypeAnnotation())* "[" UnaryExprNotPmStart() ) (TypeAnnotation())* "[" Expression() "]" {jjtThis.bumpArrayDepth();} )+
|
||||
( LOOKAHEAD((TypeAnnotation())* "[") (TypeAnnotation())* "[" "]" {jjtThis.bumpArrayDepth();} )*
|
||||
|
||||
LOOKAHEAD(2)
|
||||
( LOOKAHEAD(2) (TypeAnnotation())* "[" Expression() "]" {jjtThis.bumpArrayDepth();})+ ( LOOKAHEAD(2) "[" "]" {jjtThis.bumpArrayDepth();} )*
|
||||
|
|
||||
( "[" "]" {jjtThis.bumpArrayDepth();})+ ArrayInitializer()
|
||||
}
|
||||
|
||||
|
||||
@@ -2588,7 +2600,7 @@ void MemberValue():
|
||||
void MemberValueArrayInitializer():
|
||||
{}
|
||||
{
|
||||
"{" (MemberValue() ( LOOKAHEAD(2) "," MemberValue() )* [ "," ])? "}"
|
||||
"{" (MemberValue() ( LOOKAHEAD(2) "," MemberValue() )*)? [ "," ] "}"
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ public class ASTInstanceOfExpression extends AbstractJavaTypeNode {
|
||||
* Gets the type against which the expression is tested.
|
||||
*/
|
||||
public ASTType getTypeNode() {
|
||||
JavaNode child = getChild(1);
|
||||
JavaNode child = getChild(getNumChildren() - 1);
|
||||
return child instanceof ASTType ? (ASTType) child
|
||||
: ((ASTTypePattern) child).getTypeNode();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package net.sourceforge.pmd.lang.java.ast;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import net.sourceforge.pmd.annotation.Experimental;
|
||||
|
||||
@@ -48,7 +49,7 @@ public final class ASTTypePattern extends AbstractJavaAnnotatableNode implements
|
||||
* Gets the type against which the expression is tested.
|
||||
*/
|
||||
public ASTType getTypeNode() {
|
||||
return getFirstChildOfType(ASTType.class);
|
||||
return Objects.requireNonNull(getFirstChildOfType(ASTType.class));
|
||||
}
|
||||
|
||||
/** Returns the declared variable. */
|
||||
|
||||
@@ -111,7 +111,7 @@ public abstract class AbstractJUnitRule extends AbstractJavaRule {
|
||||
|
||||
public static boolean isTestClass(ASTClassOrInterfaceBody node) {
|
||||
return !isAbstractClass(node) && node.getParent() instanceof ASTClassOrInterfaceDeclaration
|
||||
&& (isTestClassJUnit3(node) || isTestClassJUnit4(node) || isTestClassJUnit5(node));
|
||||
&& (isTestClassJUnit3(node) || isTestClassJUnit4(node) || isTestClassJUnit5(node) || isTestClassTestNg(node));
|
||||
}
|
||||
|
||||
private static boolean isAbstractClass(ASTClassOrInterfaceBody node) {
|
||||
@@ -149,6 +149,14 @@ public abstract class AbstractJUnitRule extends AbstractJavaRule {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isTestClassTestNg(ASTClassOrInterfaceBody node) {
|
||||
Node parent = node.getParent();
|
||||
if (parent instanceof TypeNode) {
|
||||
TypeNode type = (TypeNode) parent;
|
||||
return doesNodeContainJUnitAnnotation(type, TESTNG_ANNOTATION);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isTestMethod(ASTMethodDeclaration method) {
|
||||
if (method.isAbstract() || method.isNative() || method.isStatic()) {
|
||||
|
||||
+11
@@ -11,12 +11,14 @@ import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeBodyDeclaration.DeclarationKind;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAnyTypeDeclaration.TypeKind;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceBody;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTEnumDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTInitializer;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
|
||||
import net.sourceforge.pmd.lang.java.ast.AccessNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.internal.PrettyPrintingUtil;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJUnitRule;
|
||||
import net.sourceforge.pmd.properties.PropertyDescriptor;
|
||||
|
||||
|
||||
@@ -31,6 +33,9 @@ public class ClassNamingConventionsRule extends AbstractNamingConventionRule<AST
|
||||
private final PropertyDescriptor<Pattern> enumerationRegex = defaultProp("enum").build();
|
||||
private final PropertyDescriptor<Pattern> annotationRegex = defaultProp("annotation").build();
|
||||
private final PropertyDescriptor<Pattern> utilityClassRegex = defaultProp("utility class").build();
|
||||
private final PropertyDescriptor<Pattern> testClassRegex = defaultProp("test class")
|
||||
.desc("Regex which applies to test class names. Since PMD 6.52.0.")
|
||||
.defaultValue("^Test.*$|^[A-Z][a-zA-Z0-9]*Test(s|Case)?$").build();
|
||||
|
||||
|
||||
public ClassNamingConventionsRule() {
|
||||
@@ -40,6 +45,7 @@ public class ClassNamingConventionsRule extends AbstractNamingConventionRule<AST
|
||||
definePropertyDescriptor(enumerationRegex);
|
||||
definePropertyDescriptor(annotationRegex);
|
||||
definePropertyDescriptor(utilityClassRegex);
|
||||
definePropertyDescriptor(testClassRegex);
|
||||
|
||||
addRuleChainVisit(ASTClassOrInterfaceDeclaration.class);
|
||||
addRuleChainVisit(ASTEnumDeclaration.class);
|
||||
@@ -108,12 +114,17 @@ public class ClassNamingConventionsRule extends AbstractNamingConventionRule<AST
|
||||
&& String[].class.equals(decl.getFormalParameters().iterator().next().getType());
|
||||
}
|
||||
|
||||
private boolean isTestClass(ASTClassOrInterfaceDeclaration node) {
|
||||
return !node.isNested() && AbstractJUnitRule.isTestClass(node.getFirstChildOfType(ASTClassOrInterfaceBody.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
|
||||
|
||||
if (node.isAbstract()) {
|
||||
checkMatches(node, abstractClassRegex, data);
|
||||
} else if (isTestClass(node)) {
|
||||
checkMatches(node, testClassRegex, data);
|
||||
} else if (isUtilityClass(node)) {
|
||||
checkMatches(node, utilityClassRegex, data);
|
||||
} else if (node.isInterface()) {
|
||||
|
||||
+2
-1
@@ -66,6 +66,7 @@ public class CommentDefaultAccessModifierRule extends AbstractIgnoredAnnotationR
|
||||
ignoredStrings.add("org.junit.jupiter.api.BeforeAll");
|
||||
ignoredStrings.add("org.junit.jupiter.api.AfterEach");
|
||||
ignoredStrings.add("org.junit.jupiter.api.AfterAll");
|
||||
ignoredStrings.add("lombok.Value");
|
||||
return ignoredStrings;
|
||||
}
|
||||
|
||||
@@ -140,7 +141,7 @@ public class CommentDefaultAccessModifierRule extends AbstractIgnoredAnnotationR
|
||||
boolean isConcreteClass = parentClassOrInterface.getTypeKind() == ASTAnyTypeDeclaration.TypeKind.CLASS;
|
||||
|
||||
// ignore if it's inside an interface / Annotation
|
||||
return isConcreteClass && isMissingComment(decl);
|
||||
return isConcreteClass && isMissingComment(decl) && !hasIgnoredAnnotation(parentClassOrInterface);
|
||||
}
|
||||
|
||||
protected boolean hasIgnoredAnnotation(AccessNode node) {
|
||||
|
||||
+6
-1
@@ -242,11 +242,16 @@ public class InvalidLogMessageFormatRule extends AbstractJavaRule {
|
||||
varName = name.getImage();
|
||||
}
|
||||
}
|
||||
if (varName == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Scope scope = prefix == null ? null : prefix.getScope();
|
||||
while (scope != null) {
|
||||
// Try recursively to find the expected NameDeclaration
|
||||
for (NameDeclaration decl : scope.getDeclarations().keySet()) {
|
||||
if (decl.getName().equals(varName)) {
|
||||
// anonymous classes have no names, so decl.getName() can be null
|
||||
if (varName.equals(decl.getName())) {
|
||||
// If the last parameter is a lambda parameter, then we also ignore it - regardless of the type.
|
||||
// This is actually a workaround, since type resolution doesn't resolve the types of lambda parameters.
|
||||
return decl.getNode().getParent() instanceof ASTLambdaExpression;
|
||||
|
||||
@@ -398,7 +398,7 @@ public class Foo extends Bar{
|
||||
specific kind (e.g. enum or interface). Each regex can be configured through
|
||||
properties.
|
||||
|
||||
By default this rule uses the standard Java naming convention (Pascal case).
|
||||
By default, this rule uses the standard Java naming convention (Pascal case).
|
||||
|
||||
The rule can detect utility classes and enforce a different naming convention
|
||||
on those. E.g. setting the property `utilityClassPattern` to
|
||||
@@ -408,6 +408,10 @@ public class Foo extends Bar{
|
||||
For this rule, a utility class is defined as: a concrete class that does not
|
||||
inherit from a super class or implement any interface and only has static fields
|
||||
or methods.
|
||||
|
||||
This rule detects test classes using the following convention: Test classes are top-level classes, that
|
||||
either inherit from JUnit 3 TestCase or have at least one method annotated with the Test annotations from
|
||||
JUnit4/5 or TestNG.
|
||||
</description>
|
||||
<priority>1</priority>
|
||||
<example>
|
||||
|
||||
@@ -339,6 +339,8 @@ is invoked by a inner class.
|
||||
<value>
|
||||
<![CDATA[
|
||||
//TypeDeclaration
|
||||
(: no lombok constructor annotations :)
|
||||
[not(Annotation[pmd-java:typeIs('lombok.Value')])]
|
||||
/ClassOrInterfaceDeclaration
|
||||
[@Final = false()]
|
||||
(: at least one private constructor :)
|
||||
|
||||
@@ -84,6 +84,21 @@ public class JDKVersionTest {
|
||||
java5.parseResource("jdk15_varargs.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericCtorCalls() {
|
||||
java5.parseResource("java5/generic_ctors.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenericSuperCtorCalls() {
|
||||
java5.parseResource("java5/generic_super_ctor.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotArrayInitializer() {
|
||||
java5.parseResource("java5/annotation_array_init.java");
|
||||
}
|
||||
|
||||
@Test(expected = ParseException.class)
|
||||
public void testVarargsShouldFailWith14() {
|
||||
java4.parseResource("jdk15_varargs.java");
|
||||
@@ -217,6 +232,11 @@ public class JDKVersionTest {
|
||||
java8.parse("public class Foo { private void bar() { } }");
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testTypeAnnotations() {
|
||||
java8.parseResource("java8/type_annotations.java");
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testNestedPrivateMethods() {
|
||||
java8.parse("public interface Baz { public static class Foo { private void bar() { } } }");
|
||||
|
||||
@@ -148,10 +148,10 @@ public class ParserCornersTest {
|
||||
public void testParsersCases18() throws Exception {
|
||||
ASTCompilationUnit cu = java8.parseResource("ParserCornerCases18.java");
|
||||
|
||||
Assert.assertEquals(21, cu.findChildNodesWithXPath("//FormalParameter").size());
|
||||
Assert.assertEquals(4,
|
||||
Assert.assertEquals(24, cu.findChildNodesWithXPath("//FormalParameter").size());
|
||||
Assert.assertEquals(5,
|
||||
cu.findChildNodesWithXPath("//FormalParameter[@ExplicitReceiverParameter='true']").size());
|
||||
Assert.assertEquals(17,
|
||||
Assert.assertEquals(19,
|
||||
cu.findChildNodesWithXPath("//FormalParameter[@ExplicitReceiverParameter='false']").size());
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class ASTCatchStatementTest : ParserTestSpec({
|
||||
}
|
||||
|
||||
child<ASTVariableDeclaratorId> {
|
||||
it.image shouldBe "e"
|
||||
it.name shouldBe "e"
|
||||
}
|
||||
|
||||
listOf(ioe, aerr)
|
||||
|
||||
@@ -5,10 +5,9 @@
|
||||
package net.sourceforge.pmd.lang.java.ast
|
||||
|
||||
import io.kotest.matchers.shouldBe
|
||||
import net.sourceforge.pmd.lang.ast.test.shouldBe as typeShouldBe
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion.*
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaVersion.J16
|
||||
import java.io.IOException
|
||||
import net.sourceforge.pmd.lang.ast.test.shouldBe as typeShouldBe
|
||||
|
||||
class ASTPatternTest : ParserTestSpec({
|
||||
val typePatternsVersions = JavaVersion.since(J16)
|
||||
|
||||
@@ -28,7 +28,7 @@ enum class JavaVersion : Comparable<JavaVersion> {
|
||||
J19, J19__PREVIEW;
|
||||
|
||||
/** Name suitable for use with e.g. [JavaParsingHelper.parse] */
|
||||
val pmdName: String = name.removePrefix("J").replaceFirst("__", "-").replace('_', '.').toLowerCase()
|
||||
val pmdName: String = name.removePrefix("J").replaceFirst("__", "-").replace('_', '.').lowercase()
|
||||
|
||||
val parser: JavaParsingHelper = JavaParsingHelper.WITH_PROCESSING.withDefaultVersion(pmdName)
|
||||
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
|
||||
package net.sourceforge.pmd.lang.java.ast
|
||||
|
||||
import io.kotest.core.config.configuration
|
||||
import io.kotest.core.names.TestName
|
||||
import io.kotest.core.source.sourceRef
|
||||
import io.kotest.core.spec.DslDrivenSpec
|
||||
import io.kotest.core.spec.style.scopes.Lifecycle
|
||||
import io.kotest.core.spec.style.scopes.RootScope
|
||||
import io.kotest.core.spec.style.scopes.RootTestRegistration
|
||||
import io.kotest.core.test.TestCaseConfig
|
||||
import io.kotest.core.test.TestContext
|
||||
import io.kotest.core.spec.style.scopes.addContainer
|
||||
import io.kotest.core.spec.style.scopes.addTest
|
||||
import io.kotest.core.test.NestedTest
|
||||
import io.kotest.core.test.TestScope
|
||||
import io.kotest.core.test.TestType
|
||||
import io.kotest.core.test.createTestName
|
||||
import net.sourceforge.pmd.lang.ast.test.Assertions
|
||||
import net.sourceforge.pmd.lang.ast.test.IntelliMarker
|
||||
import io.kotest.matchers.should as kotlintestShould
|
||||
@@ -31,22 +31,16 @@ abstract class ParserTestSpec(body: ParserTestSpec.() -> Unit) : DslDrivenSpec()
|
||||
body()
|
||||
}
|
||||
|
||||
override fun lifecycle(): Lifecycle = Lifecycle.from(this)
|
||||
override fun defaultConfig(): TestCaseConfig = actualDefaultConfig()
|
||||
override fun defaultTestCaseConfig(): TestCaseConfig? = defaultTestConfig
|
||||
override fun registration(): RootTestRegistration = RootTestRegistration.from(this)
|
||||
|
||||
private fun actualDefaultConfig() =
|
||||
defaultTestConfig ?: defaultTestCaseConfig() ?: configuration.defaultTestConfig
|
||||
|
||||
fun test(name: String, disabled: Boolean = false, test: suspend TestContext.() -> Unit) =
|
||||
registration().addTest(
|
||||
name = createTestName(name),
|
||||
xdisabled = disabled,
|
||||
test = test,
|
||||
config = actualDefaultConfig()
|
||||
fun test(name: String, disabled: Boolean = false, test: suspend TestScope.() -> Unit) =
|
||||
addTest(
|
||||
testName = TestName(name),
|
||||
disabled = disabled,
|
||||
config = null,
|
||||
type = TestType.Test,
|
||||
test = test
|
||||
)
|
||||
|
||||
|
||||
/**
|
||||
* Defines a group of tests that should be named similarly,
|
||||
* with separate tests for separate versions.
|
||||
@@ -66,10 +60,11 @@ abstract class ParserTestSpec(body: ParserTestSpec.() -> Unit) : DslDrivenSpec()
|
||||
fun parserTestGroup(name: String,
|
||||
disabled: Boolean = false,
|
||||
spec: suspend GroupTestCtx.() -> Unit) =
|
||||
registration().addContainerTest(
|
||||
name = createTestName(name),
|
||||
addContainer(
|
||||
testName = TestName(name),
|
||||
test = { GroupTestCtx(this).spec() },
|
||||
xdisabled = disabled
|
||||
disabled = disabled,
|
||||
config = null
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -117,37 +112,43 @@ abstract class ParserTestSpec(body: ParserTestSpec.() -> Unit) : DslDrivenSpec()
|
||||
}
|
||||
|
||||
private suspend fun containedParserTestImpl(
|
||||
context: TestContext,
|
||||
scope: TestScope,
|
||||
name: String,
|
||||
javaVersion: JavaVersion,
|
||||
assertions: ParserTestCtx.() -> Unit) {
|
||||
|
||||
context.registerTestCase(
|
||||
name = createTestName(name),
|
||||
test = { ParserTestCtx(javaVersion).assertions() },
|
||||
config = actualDefaultConfig(),
|
||||
type = TestType.Test
|
||||
val nested = NestedTest(
|
||||
name = TestName(name),
|
||||
test = { ParserTestCtx(javaVersion).assertions() },
|
||||
config = null,
|
||||
type = TestType.Test,
|
||||
disabled = false,
|
||||
source = sourceRef()
|
||||
)
|
||||
scope.registerTestCase(nested)
|
||||
}
|
||||
|
||||
inner class GroupTestCtx(private val context: TestContext) {
|
||||
inner class GroupTestCtx(private val scope: TestScope) {
|
||||
|
||||
suspend fun onVersions(javaVersions: List<JavaVersion>, spec: suspend VersionedTestCtx.() -> Unit) {
|
||||
javaVersions.forEach { javaVersion ->
|
||||
|
||||
context.registerTestCase(
|
||||
name = createTestName("Java ${javaVersion.pmdName}"),
|
||||
test = { VersionedTestCtx(this, javaVersion).spec() },
|
||||
config = actualDefaultConfig(),
|
||||
type = TestType.Container
|
||||
val nested = NestedTest(
|
||||
name = TestName("Java ${javaVersion.pmdName}"),
|
||||
test = { VersionedTestCtx(this, javaVersion).spec() },
|
||||
config = null,
|
||||
type = TestType.Container,
|
||||
disabled = false,
|
||||
source = sourceRef()
|
||||
)
|
||||
scope.registerTestCase(nested)
|
||||
}
|
||||
}
|
||||
|
||||
inner class VersionedTestCtx(private val context: TestContext, javaVersion: JavaVersion) : ParserTestCtx(javaVersion) {
|
||||
inner class VersionedTestCtx(private val scope: TestScope, javaVersion: JavaVersion) : ParserTestCtx(javaVersion) {
|
||||
|
||||
suspend infix fun String.should(matcher: Assertions<String>) {
|
||||
containedParserTestImpl(context, "'$this'", javaVersion = javaVersion) {
|
||||
containedParserTestImpl(scope, "'$this'", javaVersion = javaVersion) {
|
||||
this@should kotlintestShould matcher
|
||||
}
|
||||
}
|
||||
|
||||
Loaded 30 of 42 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user