Merge branch 'master' into pmd/7.0.x

This commit is contained in:
Andreas Dangel
2020-06-12 14:21:10 +02:00
222 changed files with 653 additions and 94 deletions

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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).

View File

@ -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 {

View File

@ -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 %}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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() {

View 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>

View File

@ -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>

View File

@ -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>

View File

@ -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);

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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;
} }
} }

View File

@ -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"

View File

@ -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"/>

View File

@ -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
}

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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