Merge branch 'master' into uselessoverridingmethod-false-negative
This commit is contained in:
commit
6c51cec444
224 files changed
+653
-94
No files matched your search
@@ -48,7 +48,7 @@ function pmd_code_uploadJavadoc() {
|
||||
|
||||
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"
|
||||
done
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
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 "* Update **../pmd.github.io/_config.yml** to mention the new release"
|
||||
echo
|
||||
|
||||
@@ -226,6 +226,11 @@ class JavadocTag < Liquid::Tag
|
||||
def self.fqcn_type(artifact_id, fqcn)
|
||||
|
||||
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 = [
|
||||
File.join(artifact_dir, "src", "main", "java"),
|
||||
File.join(artifact_dir, "target", "generated-sources", "javacc")
|
||||
|
||||
@@ -86,9 +86,14 @@ class JDocNamespaceDeclaration < Liquid::Tag
|
||||
expanded_fqcn += "." + fqcn_suffix
|
||||
end
|
||||
|
||||
artifactId = resolved_nspace.first
|
||||
|
||||
if artifactId =~ /scala/
|
||||
artifactId = "pmd-scala_2.13"
|
||||
end
|
||||
|
||||
# Return the resolved artifactId + the expanded FQCN
|
||||
[resolved_nspace.first, expanded_fqcn]
|
||||
[artifactId, expanded_fqcn]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -4,17 +4,69 @@ permalink: pmd_next_major_development.html
|
||||
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)!
|
||||
|
||||
## 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
|
||||
@@ -878,14 +930,18 @@ large projects, with many duplications, it was causing `OutOfMemoryError`s (see
|
||||
and {% rule "java/bestpractices/PositionLiteralsFirstInCaseInsensitiveComparisons" %} (ruleset `java-bestpractices`)
|
||||
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
|
||||
|
||||
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
|
||||
public Object someParameterizedFactoryMethod(int x) throws Exception {
|
||||
|
||||
@@ -14,14 +14,58 @@ This is a {{ site.pmd.release_type }} release.
|
||||
|
||||
### 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
|
||||
|
||||
* c#
|
||||
* [#2551](https://github.com/pmd/pmd/issues/2551): \[c#] CPD suppression with comments doesn't work
|
||||
* java-design
|
||||
* [#2563](https://github.com/pmd/pmd/pull/2563): \[java] UselessOverridingMethod false negative with already public methods
|
||||
* scala
|
||||
* [#2547](https://github.com/pmd/pmd/pull/2547): \[scala] Add cross compilation for scala 2.12 and 2.13
|
||||
|
||||
### 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
|
||||
|
||||
* [#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 %}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -77,7 +77,7 @@ public class AntlrToken implements GenericToken {
|
||||
}
|
||||
|
||||
public boolean isHidden() {
|
||||
return token.getChannel() == Lexer.HIDDEN;
|
||||
return !isDefault();
|
||||
}
|
||||
|
||||
public boolean isDefault() {
|
||||
|
||||
@@ -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>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -78,6 +78,18 @@ public class CsTokenizerTest {
|
||||
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
|
||||
public void testCommentsIgnored3() {
|
||||
tokenizer.tokenize(toSourceCode("class Foo { /// class X /* aaa */ \n }"), tokens);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
+2
-1
@@ -9,6 +9,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
@@ -199,7 +200,7 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd-scala</artifactId>
|
||||
<artifactId>pmd-scala_2.13</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
+49
-16
@@ -1,11 +1,12 @@
|
||||
/**
|
||||
/*
|
||||
* 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.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
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.ASTFieldDeclaration;
|
||||
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.rule.AbstractJavaRule;
|
||||
import net.sourceforge.pmd.lang.java.typeresolution.TypeHelper;
|
||||
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
|
||||
@@ -34,7 +37,6 @@ import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
|
||||
* "http://sourceforge.net/p/pmd/discussion/188192/thread/276fd6f0">Java 5
|
||||
* rules: Unnecessary casts/Iterators</a>
|
||||
*/
|
||||
// TODO This is not referenced by any RuleSet?
|
||||
public class UnnecessaryCastRule extends AbstractJavaRule {
|
||||
|
||||
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.TreeMap");
|
||||
implClassNames.add("java.util.Vector");
|
||||
implClassNames.add("Iterator");
|
||||
implClassNames.add("java.util.Iterator");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTLocalVariableDeclaration node, Object data) {
|
||||
return process(node, data);
|
||||
process(node, data);
|
||||
return super.visit(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
ASTClassOrInterfaceType cit = node.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
|
||||
if (cit == null || !implClassNames.contains(cit.getImage())) {
|
||||
return data;
|
||||
private void process(Node node, Object data) {
|
||||
ASTClassOrInterfaceType collectionType = node.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
|
||||
if (collectionType == null || !implClassNames.contains(collectionType.getImage())) {
|
||||
return;
|
||||
}
|
||||
cit = cit.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
|
||||
ASTClassOrInterfaceType cit = getCollectionItemType(collectionType);
|
||||
if (cit == null) {
|
||||
return data;
|
||||
return;
|
||||
}
|
||||
ASTVariableDeclaratorId decl = node.getFirstDescendantOfType(ASTVariableDeclaratorId.class);
|
||||
List<NameOccurrence> usages = decl.getUsages();
|
||||
for (NameOccurrence no : usages) {
|
||||
ASTName name = (ASTName) no.getLocation();
|
||||
Node n = name.getParent().getParent().getParent();
|
||||
if (n instanceof ASTCastExpression) {
|
||||
addViolation(data, n);
|
||||
ASTCastExpression castExpression = findCastExpression(no.getLocation());
|
||||
if (castExpression != null) {
|
||||
ASTClassOrInterfaceType castTarget = castExpression.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1855,6 +1855,30 @@ public class Foo {
|
||||
</example>
|
||||
</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"
|
||||
language="java"
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
<!-- <rule ref="category/java/codestyle.xml/SuspiciousConstantFieldName" /> -->
|
||||
<!-- <rule ref="category/java/codestyle.xml/TooManyStaticImports" /> -->
|
||||
<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/UnnecessaryFullyQualifiedName"/>
|
||||
<rule ref="category/java/codestyle.xml/UnnecessaryLocalBeforeReturn"/>
|
||||
|
||||
+12
@@ -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
|
||||
}
|
||||
+157
@@ -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>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<groupId>net.sourceforge.pmd</groupId>
|
||||
<artifactId>pmd</artifactId>
|
||||
<version>6.25.0-SNAPSHOT</version>
|
||||
<relativePath>../</relativePath>
|
||||
</parent>
|
||||
|
||||
<build>
|
||||
|
||||
Loaded 30 of 224 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user