forked from phoedos/pmd
Merge branch 'master' into pmd/7.0.x
This commit is contained in:
@ -48,7 +48,7 @@ function pmd_code_uploadJavadoc() {
|
|||||||
|
|
||||||
log_debug "$FUNCNAME pmdVersion=$pmdVersion basePath=$basePath"
|
log_debug "$FUNCNAME pmdVersion=$pmdVersion basePath=$basePath"
|
||||||
|
|
||||||
for i in ${basePath}/*/target/*-javadoc.jar; do
|
for i in ${basePath}/*/target/*-javadoc.jar */*/target/*-javadoc.jar; do
|
||||||
pmd_code_uploadJavadocModule "$pmdVersion" "$i"
|
pmd_code_uploadJavadocModule "$pmdVersion" "$i"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ echo "* Update **pmd-apex/src/main/resources/rulesets/apex/quickstart.xml** an
|
|||||||
echo " **pmd-java/src/main/resources/rulesets/java/quickstart.xml** with the new rules."
|
echo " **pmd-java/src/main/resources/rulesets/java/quickstart.xml** with the new rules."
|
||||||
echo
|
echo
|
||||||
echo "* Update **docs/pages/next_major_development.md** with the API changes for"
|
echo "* Update **docs/pages/next_major_development.md** with the API changes for"
|
||||||
echo " the new release based on the release notes"
|
echo " the new release based on the release notes. Also add any deprecated rules to the list."
|
||||||
echo
|
echo
|
||||||
echo "* Update **../pmd.github.io/_config.yml** to mention the new release"
|
echo "* Update **../pmd.github.io/_config.yml** to mention the new release"
|
||||||
echo
|
echo
|
||||||
|
@ -226,6 +226,11 @@ class JavadocTag < Liquid::Tag
|
|||||||
def self.fqcn_type(artifact_id, fqcn)
|
def self.fqcn_type(artifact_id, fqcn)
|
||||||
|
|
||||||
artifact_dir = File.join(BASE_PMD_DIR, artifact_id)
|
artifact_dir = File.join(BASE_PMD_DIR, artifact_id)
|
||||||
|
# special case for scala as we have a different directory structure there
|
||||||
|
if artifact_id =~ /scala/
|
||||||
|
artifact_dir = File.join(BASE_PMD_DIR, "pmd-scala-modules/pmd-scala-common")
|
||||||
|
end
|
||||||
|
|
||||||
src_dirs = [
|
src_dirs = [
|
||||||
File.join(artifact_dir, "src", "main", "java"),
|
File.join(artifact_dir, "src", "main", "java"),
|
||||||
File.join(artifact_dir, "target", "generated-sources", "javacc")
|
File.join(artifact_dir, "target", "generated-sources", "javacc")
|
||||||
|
@ -86,9 +86,14 @@ class JDocNamespaceDeclaration < Liquid::Tag
|
|||||||
expanded_fqcn += "." + fqcn_suffix
|
expanded_fqcn += "." + fqcn_suffix
|
||||||
end
|
end
|
||||||
|
|
||||||
|
artifactId = resolved_nspace.first
|
||||||
|
|
||||||
|
if artifactId =~ /scala/
|
||||||
|
artifactId = "pmd-scala_2.13"
|
||||||
|
end
|
||||||
|
|
||||||
# Return the resolved artifactId + the expanded FQCN
|
# Return the resolved artifactId + the expanded FQCN
|
||||||
[resolved_nspace.first, expanded_fqcn]
|
[artifactId, expanded_fqcn]
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
@ -4,17 +4,69 @@ permalink: pmd_next_major_development.html
|
|||||||
keywords: changelog, release notes, deprecation, api changes
|
keywords: changelog, release notes, deprecation, api changes
|
||||||
---
|
---
|
||||||
|
|
||||||
We're excited to bring you the next major version of PMD! Here are the major features and changes we're working on.
|
We're excited to bring you the next major version of PMD!
|
||||||
|
Here is a summary of what is planned for PMD 7.
|
||||||
|
|
||||||
To give us feedback or to suggest a new feature, drop us a line on [Gitter](https://gitter.im/pmd/pmd)!
|
To give us feedback or to suggest a new feature, drop us a line on [Gitter](https://gitter.im/pmd/pmd)!
|
||||||
|
|
||||||
## New Features
|
## Summary
|
||||||
|
|
||||||
TODO
|
### New Logo
|
||||||
|
|
||||||
## Java grammar changes
|
We decided it's time to have a modernized logo and get rid of the gun. This allows to include
|
||||||
|
the logo in anywhere without offense.
|
||||||
|
|
||||||
{% include note.html content="Current plans are listed [here](https://github.com/pmd/pmd/labels/in%3Aast) and in particular [here](https://github.com/pmd/pmd/issues/1019)" %}
|
The current tasks are listed here: [Integrate new PMD logo #1931](https://github.com/pmd/pmd/issues/1931)
|
||||||
|
|
||||||
|
### API
|
||||||
|
|
||||||
|
The API of PMD has been growing over the years and needs to be cleaned up. The goal is, to
|
||||||
|
have a clear separation between a well-defined API and the implementation, which is internal.
|
||||||
|
This should help us in future development. This however entails some incompatibilities and
|
||||||
|
deprecations, see also the sections [New API support guidelines](#new-api-support-guidelines) and
|
||||||
|
[Planned API removals](#planned-api-removals] below.
|
||||||
|
|
||||||
|
### Full Antlr Support
|
||||||
|
|
||||||
|
PMD 6 only supports JavaCC based grammars, but with [Antlr](https://www.antlr.org/) parsers
|
||||||
|
can be generated as well. PMD 7 adds full support for grammars written in Antlr, which allows
|
||||||
|
to leverage existing grammars.
|
||||||
|
|
||||||
|
The current tasks are listed here: [Support for ANTLR based grammars with Swift as an example language #2499](https://github.com/pmd/pmd/issues/2499)
|
||||||
|
|
||||||
|
### Documentation
|
||||||
|
|
||||||
|
We have quite some ideas how we want to improve the documentation. The goal is, that the documentation is
|
||||||
|
up to date and nearly complete. One big task is, how the built-in rules are presented, so that users
|
||||||
|
can easier see, what exactly is available and decide, which rules are useful for the project at hand.
|
||||||
|
|
||||||
|
The current tasks are listed here: [Documentations improvements tracker #1139](https://github.com/pmd/pmd/issues/1139)
|
||||||
|
|
||||||
|
### XPath
|
||||||
|
|
||||||
|
PMD 6 supports XPath 1.0 via the Jaxen library. This library is old and unmaintained creating some problems
|
||||||
|
(one of which is duplicated classes in the package `org.w3c.dom` which is a Java API actually).
|
||||||
|
Therefore XPath 1.0 support will be dropped and we upgrade our XPath 2.0 implementation with Saxon moving
|
||||||
|
on to Saxon HE. This will eventually add support in PMD for XPath 3.1.
|
||||||
|
|
||||||
|
The current tasks are listed here: [XPath Improvements for PMD 7 #2523](https://github.com/pmd/pmd/issues/2523)
|
||||||
|
|
||||||
|
### Java
|
||||||
|
|
||||||
|
Like the main PMD API, the Java AST has been growing over time and the grammar doesn't support
|
||||||
|
all edge cases (e.g. annotation are not supported everywhere). The goal is to simplify the AST by reducing
|
||||||
|
unnecessary nodes and abstractions and fix the parsing issues.
|
||||||
|
This helps in the end to provide a better type resolution implementation, but changing the AST is a breaking
|
||||||
|
API change.
|
||||||
|
|
||||||
|
Some first results of the Java AST changes are for now documented in the Wiki:
|
||||||
|
[Java clean changes](https://github.com/pmd/pmd/wiki/Java_clean_changes).
|
||||||
|
|
||||||
|
### Miscellaneous
|
||||||
|
|
||||||
|
There are also some small improvements, refactoring and internal tasks that are planned for PMD 7.
|
||||||
|
|
||||||
|
The current tasks are listed here: [PMD 7 Miscellaneous Tasks #2524](https://github.com/pmd/pmd/issues/2524)
|
||||||
|
|
||||||
|
|
||||||
## New API support guidelines
|
## New API support guidelines
|
||||||
@ -878,14 +930,18 @@ large projects, with many duplications, it was causing `OutOfMemoryError`s (see
|
|||||||
and {% rule "java/bestpractices/PositionLiteralsFirstInCaseInsensitiveComparisons" %} (ruleset `java-bestpractices`)
|
and {% rule "java/bestpractices/PositionLiteralsFirstInCaseInsensitiveComparisons" %} (ruleset `java-bestpractices`)
|
||||||
have been deprecated in favor of the new rule {% rule "java/bestpractices/LiteralsFirstInComparisons" %}.
|
have been deprecated in favor of the new rule {% rule "java/bestpractices/LiteralsFirstInComparisons" %}.
|
||||||
|
|
||||||
|
* The Java rule [`AvoidFinalLocalVariable`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_codestyle.html#avoidfinallocalvariable) (`java-codestyle`) has been deprecated
|
||||||
|
and will be removed with PMD 7.0.0. The rule is controversial and also contradicts other existing
|
||||||
|
rules such as [`LocalVariableCouldBeFinal`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_codestyle.html#localvariablecouldbefinal). If the goal is to avoid defining
|
||||||
|
constants in a scope smaller than the class, then the rule [`AvoidDuplicateLiterals`](https://pmd.github.io/pmd-6.16.0/pmd_rules_java_errorprone.html#avoidduplicateliterals)
|
||||||
|
should be used instead.
|
||||||
|
|
||||||
|
* The Apex rule [`VariableNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#variablenamingconventions) (`apex-codestyle`) has been deprecated and
|
||||||
|
will be removed with PMD 7.0.0. The rule is replaced by the more general rules
|
||||||
|
[`FieldNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#fieldnamingconventions),
|
||||||
|
[`FormalParameterNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#formalparameternamingconventions),
|
||||||
|
[`LocalVariableNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#localvariablenamingconventions), and
|
||||||
|
[`PropertyNamingConventions`](https://pmd.github.io/pmd-6.15.0/pmd_rules_apex_codestyle.html#propertynamingconventions).
|
||||||
|
|
||||||
|
* The Java rule [`LoggerIsNotStaticFinal`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_errorprone.html#loggerisnotstaticfinal) (`java-errorprone`) has been deprecated
|
||||||
|
and will be removed with PMD 7.0.0. The rule is replaced by [`ProperLogger`](https://pmd.github.io/pmd-6.15.0/pmd_rules_java_errorprone.html#properlogger).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ Here's a screenshot of CPD after running on the JDK 8 java.lang package:
|
|||||||
## Suppression
|
## Suppression
|
||||||
|
|
||||||
Arbitrary blocks of code can be ignored through comments on **Java**, **C/C++**, **Dart**, **Go**, **Javascript**,
|
Arbitrary blocks of code can be ignored through comments on **Java**, **C/C++**, **Dart**, **Go**, **Javascript**,
|
||||||
**Kotlin**, **Lua**, **Matlab**, **Objective-C**, **PL/SQL**, **Python** and **Swift** by including the keywords `CPD-OFF` and `CPD-ON`.
|
**Kotlin**, **Lua**, **Matlab**, **Objective-C**, **PL/SQL**, **Python**, **Swift** and **C#** by including the keywords `CPD-OFF` and `CPD-ON`.
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public Object someParameterizedFactoryMethod(int x) throws Exception {
|
public Object someParameterizedFactoryMethod(int x) throws Exception {
|
||||||
|
@ -19,11 +19,56 @@ This is a {{ site.pmd.release_type }} release.
|
|||||||
|
|
||||||
### New and noteworthy
|
### New and noteworthy
|
||||||
|
|
||||||
|
#### Scala cross compilation
|
||||||
|
|
||||||
|
Up until now the PMD Scala module has been compiled against scala 2.13 only by default.
|
||||||
|
However, this makes it impossible to use pmd as a library in scala projects,
|
||||||
|
that use scala 2.12, e.g. in sbt plugins. Therefore PMD now provides cross compiled pmd-scala
|
||||||
|
modules for both versions: **scala 2.12** and **scala 2.13**.
|
||||||
|
|
||||||
|
The new modules have new maven artifactIds. The old artifactId `net.sourceforge.pmd:pmd-scala:{{ site.pmd.version }}`
|
||||||
|
is still available, but is deprecated from now on. It has been demoted to be just a delegation to the new
|
||||||
|
`pmd-scala_2.13` module and will be removed eventually.
|
||||||
|
|
||||||
|
The coordinates for the new modules are:
|
||||||
|
|
||||||
|
```
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
|
<artifactId>pmd-scala_2.12</artifactId>
|
||||||
|
<version>{{ site.pmd.version }}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
|
<artifactId>pmd-scala_2.13</artifactId>
|
||||||
|
<version>{{ site.pmd.version }}</version>
|
||||||
|
</dependency>
|
||||||
|
```
|
||||||
|
|
||||||
|
The command line version of PMD continues to use **scala 2.13**.
|
||||||
|
|
||||||
|
#### New Rules
|
||||||
|
|
||||||
|
* The new Java Rule {% rule "java/codestyle/UnnecessaryCast" %} (`java-codestyle`)
|
||||||
|
finds casts that are unnecessary while accessing collection elements.
|
||||||
|
|
||||||
### Fixed Issues
|
### Fixed Issues
|
||||||
|
|
||||||
|
* c#
|
||||||
|
* [#2551](https://github.com/pmd/pmd/issues/2551): \[c#] CPD suppression with comments doesn't work
|
||||||
|
* scala
|
||||||
|
* [#2547](https://github.com/pmd/pmd/pull/2547): \[scala] Add cross compilation for scala 2.12 and 2.13
|
||||||
|
|
||||||
### API Changes
|
### API Changes
|
||||||
|
|
||||||
|
* The maven module `net.sourceforge.pmd:pmd-scala` is deprecated. Use `net.sourceforge.pmd:pmd-scala_2.13`
|
||||||
|
or `net.sourceforge.pmd:pmd-scala_2.12` instead.
|
||||||
|
|
||||||
### External Contributions
|
### External Contributions
|
||||||
|
|
||||||
|
* [#2547](https://github.com/pmd/pmd/pull/2547): \[scala] Add cross compilation for scala 2.12 and 2.13 - [João Ferreira](https://github.com/jtjeferreira)
|
||||||
|
* [#2567](https://github.com/pmd/pmd/pull/2567): \[c#] Fix CPD suppression with comments doesn't work - [Lixon Lookose](https://github.com/LixonLookose)
|
||||||
|
|
||||||
{% endtocmaker %}
|
{% endtocmaker %}
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -74,7 +74,7 @@ public class AntlrToken implements GenericToken<AntlrToken> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isHidden() {
|
public boolean isHidden() {
|
||||||
return token.getChannel() == Lexer.HIDDEN;
|
return !isDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isDefault() {
|
public boolean isDefault() {
|
||||||
|
13
pmd-core/src/main/resources/rulesets/releases/6250.xml
Normal file
13
pmd-core/src/main/resources/rulesets/releases/6250.xml
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
|
<ruleset name="6250"
|
||||||
|
xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||||
|
<description>
|
||||||
|
This ruleset contains links to rules that are new in PMD v6.25.0
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<rule ref="category/java/codestyle.xml/UnnecessaryCast" />
|
||||||
|
|
||||||
|
</ruleset>
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -78,6 +78,18 @@ public class CsTokenizerTest {
|
|||||||
assertEquals(5, tokens.size());
|
assertEquals(5, tokens.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIgnoreBetweenSpecialComments() {
|
||||||
|
tokenizer
|
||||||
|
.tokenize(
|
||||||
|
toSourceCode("// CPD-OFF\n" + "class Foo {\n" + " void bar() {\n" + " int a = 1 >> 2; \n"
|
||||||
|
+ " a += 1; \n" + " a++; \n" + " a /= 3e2; \n" + " float f = -3.1; \n"
|
||||||
|
+ " f *= 2; \n" + " bool b = ! (f == 2.0 || f >= 1.0 && f <= 2.0) \n"
|
||||||
|
+ " }\n" + "// CPD-ON\n" + "}"),
|
||||||
|
tokens);
|
||||||
|
assertEquals(2, tokens.size()); // "}" + EOF
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCommentsIgnored3() {
|
public void testCommentsIgnored3() {
|
||||||
tokenizer.tokenize(toSourceCode("class Foo { /// class X /* aaa */ \n }"), tokens);
|
tokenizer.tokenize(toSourceCode("class Foo { /// class X /* aaa */ \n }"), tokens);
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@ -199,7 +200,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd-scala</artifactId>
|
<artifactId>pmd-scala_2.13</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
/**
|
/*
|
||||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package net.sourceforge.pmd.lang.java.rule.migrating;
|
package net.sourceforge.pmd.lang.java.rule.codestyle;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import net.sourceforge.pmd.lang.ast.Node;
|
import net.sourceforge.pmd.lang.ast.Node;
|
||||||
@ -13,10 +14,12 @@ import net.sourceforge.pmd.lang.java.ast.ASTCastExpression;
|
|||||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
|
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
|
||||||
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
|
import net.sourceforge.pmd.lang.java.ast.ASTFieldDeclaration;
|
||||||
import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
|
import net.sourceforge.pmd.lang.java.ast.ASTLocalVariableDeclaration;
|
||||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
import net.sourceforge.pmd.lang.java.ast.ASTTypeArgument;
|
||||||
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
|
||||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
|
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
|
||||||
|
import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
|
||||||
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||||
|
import net.sourceforge.pmd.lang.symboltable.ScopedNode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a rule, that detects unnecessary casts when using Java 1.5 generics
|
* This is a rule, that detects unnecessary casts when using Java 1.5 generics
|
||||||
@ -34,7 +37,6 @@ import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
|||||||
* "http://sourceforge.net/p/pmd/discussion/188192/thread/276fd6f0">Java 5
|
* "http://sourceforge.net/p/pmd/discussion/188192/thread/276fd6f0">Java 5
|
||||||
* rules: Unnecessary casts/Iterators</a>
|
* rules: Unnecessary casts/Iterators</a>
|
||||||
*/
|
*/
|
||||||
// TODO This is not referenced by any RuleSet?
|
|
||||||
public class UnnecessaryCastRule extends AbstractJavaRule {
|
public class UnnecessaryCastRule extends AbstractJavaRule {
|
||||||
|
|
||||||
private static Set<String> implClassNames = new HashSet<>();
|
private static Set<String> implClassNames = new HashSet<>();
|
||||||
@ -62,36 +64,67 @@ public class UnnecessaryCastRule extends AbstractJavaRule {
|
|||||||
implClassNames.add("java.util.TreeSet");
|
implClassNames.add("java.util.TreeSet");
|
||||||
implClassNames.add("java.util.TreeMap");
|
implClassNames.add("java.util.TreeMap");
|
||||||
implClassNames.add("java.util.Vector");
|
implClassNames.add("java.util.Vector");
|
||||||
|
implClassNames.add("Iterator");
|
||||||
|
implClassNames.add("java.util.Iterator");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visit(ASTLocalVariableDeclaration node, Object data) {
|
public Object visit(ASTLocalVariableDeclaration node, Object data) {
|
||||||
return process(node, data);
|
process(node, data);
|
||||||
|
return super.visit(node, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visit(ASTFieldDeclaration node, Object data) {
|
public Object visit(ASTFieldDeclaration node, Object data) {
|
||||||
return process(node, data);
|
process(node, data);
|
||||||
|
return super.visit(node, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object process(Node node, Object data) {
|
private void process(Node node, Object data) {
|
||||||
ASTClassOrInterfaceType cit = node.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
|
ASTClassOrInterfaceType collectionType = node.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
|
||||||
if (cit == null || !implClassNames.contains(cit.getImage())) {
|
if (collectionType == null || !implClassNames.contains(collectionType.getImage())) {
|
||||||
return data;
|
return;
|
||||||
}
|
}
|
||||||
cit = cit.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
|
ASTClassOrInterfaceType cit = getCollectionItemType(collectionType);
|
||||||
if (cit == null) {
|
if (cit == null) {
|
||||||
return data;
|
return;
|
||||||
}
|
}
|
||||||
ASTVariableDeclaratorId decl = node.getFirstDescendantOfType(ASTVariableDeclaratorId.class);
|
ASTVariableDeclaratorId decl = node.getFirstDescendantOfType(ASTVariableDeclaratorId.class);
|
||||||
List<NameOccurrence> usages = decl.getUsages();
|
List<NameOccurrence> usages = decl.getUsages();
|
||||||
for (NameOccurrence no : usages) {
|
for (NameOccurrence no : usages) {
|
||||||
ASTName name = (ASTName) no.getLocation();
|
ASTCastExpression castExpression = findCastExpression(no.getLocation());
|
||||||
Node n = name.getParent().getParent().getParent();
|
if (castExpression != null) {
|
||||||
if (n instanceof ASTCastExpression) {
|
ASTClassOrInterfaceType castTarget = castExpression.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
|
||||||
addViolation(data, n);
|
if (castTarget != null
|
||||||
|
&& cit.getImage().equals(castTarget.getImage())
|
||||||
|
&& !castTarget.hasDescendantOfType(ASTTypeArgument.class)) {
|
||||||
|
addViolation(data, castExpression);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ASTClassOrInterfaceType getCollectionItemType(ASTClassOrInterfaceType collectionType) {
|
||||||
|
if (TypeHelper.isA(collectionType, Map.class)) {
|
||||||
|
List<ASTClassOrInterfaceType> types = collectionType.findDescendantsOfType(ASTClassOrInterfaceType.class);
|
||||||
|
if (types.size() >= 2) {
|
||||||
|
return types.get(1); // the value type of the map
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return collectionType.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ASTCastExpression findCastExpression(ScopedNode usage) {
|
||||||
|
Node n = usage.getNthParent(2);
|
||||||
|
if (n instanceof ASTCastExpression) {
|
||||||
|
return (ASTCastExpression) n;
|
||||||
|
}
|
||||||
|
n = n.getParent();
|
||||||
|
if (n instanceof ASTCastExpression) {
|
||||||
|
return (ASTCastExpression) n;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1512,6 +1512,30 @@ public class Foo {
|
|||||||
</example>
|
</example>
|
||||||
</rule>
|
</rule>
|
||||||
|
|
||||||
|
<rule name="UnnecessaryCast"
|
||||||
|
language="java"
|
||||||
|
minimumLanguageVersion="1.5"
|
||||||
|
since="6.24.0"
|
||||||
|
message="Avoid unnecessary casts"
|
||||||
|
class="net.sourceforge.pmd.lang.java.rule.codestyle.UnnecessaryCastRule"
|
||||||
|
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_codestyle.html#unnecessarycast">
|
||||||
|
<description>
|
||||||
|
This rule detects when a cast is unnecessary while accessing collection elements. This rule is mostly useful
|
||||||
|
for old java code before generics where introduced with java 1.5.
|
||||||
|
</description>
|
||||||
|
<priority>3</priority>
|
||||||
|
<example>
|
||||||
|
<![CDATA[
|
||||||
|
public class UnnecessaryCastSample {
|
||||||
|
public void method() {
|
||||||
|
List<String> stringList = Arrays.asList("a", "b");
|
||||||
|
String element = (String) stringList.get(0); // this cast is unnecessary
|
||||||
|
String element2 = stringList.get(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]>
|
||||||
|
</example>
|
||||||
|
</rule>
|
||||||
|
|
||||||
<rule name="UnnecessaryConstructor"
|
<rule name="UnnecessaryConstructor"
|
||||||
language="java"
|
language="java"
|
||||||
|
@ -103,6 +103,7 @@
|
|||||||
<!-- <rule ref="category/java/codestyle.xml/PrematureDeclaration" /> -->
|
<!-- <rule ref="category/java/codestyle.xml/PrematureDeclaration" /> -->
|
||||||
<!-- <rule ref="category/java/codestyle.xml/TooManyStaticImports" /> -->
|
<!-- <rule ref="category/java/codestyle.xml/TooManyStaticImports" /> -->
|
||||||
<rule ref="category/java/codestyle.xml/UnnecessaryAnnotationValueElement"/>
|
<rule ref="category/java/codestyle.xml/UnnecessaryAnnotationValueElement"/>
|
||||||
|
<!-- <rule ref="category/java/codestyle.xml/UnnecessaryCast" /> -->
|
||||||
<rule ref="category/java/codestyle.xml/UnnecessaryConstructor"/>
|
<rule ref="category/java/codestyle.xml/UnnecessaryConstructor"/>
|
||||||
<rule ref="category/java/codestyle.xml/UnnecessaryFullyQualifiedName"/>
|
<rule ref="category/java/codestyle.xml/UnnecessaryFullyQualifiedName"/>
|
||||||
<rule ref="category/java/codestyle.xml/UnnecessaryLocalBeforeReturn"/>
|
<rule ref="category/java/codestyle.xml/UnnecessaryLocalBeforeReturn"/>
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
package net.sourceforge.pmd.lang.java.rule.codestyle;
|
||||||
|
|
||||||
|
import net.sourceforge.pmd.testframework.PmdRuleTst;
|
||||||
|
|
||||||
|
public class UnnecessaryCastTest extends PmdRuleTst {
|
||||||
|
// no additional unit tests
|
||||||
|
}
|
@ -0,0 +1,157 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<test-data
|
||||||
|
xmlns="http://pmd.sourceforge.net/rule-tests"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
|
||||||
|
|
||||||
|
<test-code>
|
||||||
|
<description>Basic Violations</description>
|
||||||
|
<expected-problems>5</expected-problems>
|
||||||
|
<expected-linenumbers>12,15,18,23,28</expected-linenumbers>
|
||||||
|
<code><![CDATA[
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.uilt.HashMap;
|
||||||
|
|
||||||
|
public class UnnecessaryCastSample {
|
||||||
|
private Map<Integer, String> map = new HashMap<>();
|
||||||
|
|
||||||
|
public void localVars() {
|
||||||
|
List<String> stringList = Arrays.asList("a");
|
||||||
|
String element = (String) stringList.get(0);
|
||||||
|
|
||||||
|
List<Double> doubleList = new ArrayList<>();
|
||||||
|
Double number = (Double) doubleList.get(0);
|
||||||
|
|
||||||
|
Map<String, String> stringMap = new HashMap<>();
|
||||||
|
String mapData = (String) stringMap.get("a");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fields() {
|
||||||
|
map.put(1, "test");
|
||||||
|
String val = (String) map.get(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fields2() {
|
||||||
|
this.map.put(1, "test");
|
||||||
|
String val = (String) this.map.get(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></code>
|
||||||
|
</test-code>
|
||||||
|
|
||||||
|
<test-code>
|
||||||
|
<description>Without casts there should be no violation</description>
|
||||||
|
<expected-problems>0</expected-problems>
|
||||||
|
<code><![CDATA[
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.uilt.HashMap;
|
||||||
|
|
||||||
|
public class UnnecessaryCastSample {
|
||||||
|
private Map<Integer, String> map = new HashMap<>();
|
||||||
|
|
||||||
|
public void localVars() {
|
||||||
|
List<String> stringList = Arrays.asList("a");
|
||||||
|
String element = stringList.get(0);
|
||||||
|
|
||||||
|
List<Double> doubleList = new ArrayList<>();
|
||||||
|
Double number = doubleList.get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fields() {
|
||||||
|
map.put(1, "test");
|
||||||
|
String val = map.get(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fields2() {
|
||||||
|
this.map.put(1, "test");
|
||||||
|
String val = this.map.get(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></code>
|
||||||
|
</test-code>
|
||||||
|
|
||||||
|
<test-code>
|
||||||
|
<description>Unnecessary casts with iterator</description>
|
||||||
|
<expected-problems>2</expected-problems>
|
||||||
|
<expected-linenumbers>10,17</expected-linenumbers>
|
||||||
|
<code><![CDATA[
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class UnnecessaryCastSample {
|
||||||
|
public void localVars() {
|
||||||
|
List<String> stringList = Arrays.asList("a");
|
||||||
|
Iterator<String> stringIt = stringList.iterator();
|
||||||
|
while (stringIt.hasNext()) {
|
||||||
|
String element = (String) stringIt.next();
|
||||||
|
String element2 = stringIt.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Double> doubleList = new ArrayList<>();
|
||||||
|
Iterator<Double> doubleIt = doubleList.iterator();
|
||||||
|
while (doubleIt.hasNext()) {
|
||||||
|
Double number = (Double) doubleIt.next();
|
||||||
|
Double number2 = doubleIt.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></code>
|
||||||
|
</test-code>
|
||||||
|
|
||||||
|
<test-code>
|
||||||
|
<description>Avoid cast false-positives</description>
|
||||||
|
<expected-problems>0</expected-problems>
|
||||||
|
<code><![CDATA[
|
||||||
|
public class UnnecessaryCastSample {
|
||||||
|
public void localVars() {
|
||||||
|
List<Number> numbers = Arrays.asList(1, 2, 3);
|
||||||
|
Integer myInt = (Integer) numbers.get(0);
|
||||||
|
|
||||||
|
List<Object> data = new ArrayList<>();
|
||||||
|
String item = (String) data.get(0);
|
||||||
|
|
||||||
|
Map<String, ?> map = new HashMap<>();
|
||||||
|
String dataFromMap = (String) map.get("foo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></code>
|
||||||
|
</test-code>
|
||||||
|
|
||||||
|
<test-code>
|
||||||
|
<description>Avoid clone false-positive</description>
|
||||||
|
<expected-problems>0</expected-problems>
|
||||||
|
<code><![CDATA[
|
||||||
|
public class UnnecessaryCastSample {
|
||||||
|
public void localVars() {
|
||||||
|
List<String> strings = new ArrayList<>();
|
||||||
|
List<String> copy = (List<String>) strings.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></code>
|
||||||
|
</test-code>
|
||||||
|
|
||||||
|
<test-code>
|
||||||
|
<description>Necessary Map Cast (nested generics) false-positive</description>
|
||||||
|
<expected-problems>0</expected-problems>
|
||||||
|
<code><![CDATA[
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class MapCasts {
|
||||||
|
private final Map<Class<?>, Map<String, ?>> resourceCaches = new ConcurrentHashMap<>(4);
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> Map<String, T> getResourceCache(Class<T> valueType) {
|
||||||
|
return (Map<String, T>) this.resourceCaches.computeIfAbsent(valueType, key -> new ConcurrentHashMap<>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]]></code>
|
||||||
|
</test-code>
|
||||||
|
</test-data>
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<groupId>net.sourceforge.pmd</groupId>
|
<groupId>net.sourceforge.pmd</groupId>
|
||||||
<artifactId>pmd</artifactId>
|
<artifactId>pmd</artifactId>
|
||||||
<version>7.0.0-SNAPSHOT</version>
|
<version>7.0.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user