Merge branch 'pmd/7.0.x' into pmd7-issue-3366-support-jdk-17
This commit is contained in:
32 files changed
+2385
-75
No files matched your search
@@ -42,9 +42,11 @@
|
||||
<rule ref="category/java/bestpractices.xml/MissingOverride"/>
|
||||
<rule ref="category/java/bestpractices.xml/OneDeclarationPerLine"/>
|
||||
<rule ref="category/java/bestpractices.xml/PreserveStackTrace"/>
|
||||
<!-- <rule ref="category/java/bestpractices.xml/PrimitiveWrapperInstantiation"/> -->
|
||||
<rule ref="category/java/bestpractices.xml/ReplaceEnumerationWithIterator"/>
|
||||
<rule ref="category/java/bestpractices.xml/ReplaceHashtableWithMap"/>
|
||||
<rule ref="category/java/bestpractices.xml/ReplaceVectorWithList"/>
|
||||
<!-- <rule ref="category/java/bestpractices.xml/SimplifiableTestAssertion" /> -->
|
||||
<rule ref="category/java/bestpractices.xml/SwitchStmtsShouldHaveDefault"/>
|
||||
<rule ref="category/java/bestpractices.xml/SystemPrintln"/>
|
||||
<rule ref="category/java/bestpractices.xml/UnusedAssignment"/>
|
||||
@@ -106,6 +108,7 @@
|
||||
<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/UnnecessaryBoxing"/>
|
||||
<rule ref="category/java/codestyle.xml/UnnecessaryFullyQualifiedName"/>
|
||||
<!-- <rule ref="category/java/codestyle.xml/UnnecessaryImport"/> -->
|
||||
<rule ref="category/java/codestyle.xml/UnnecessaryLocalBeforeReturn"/>
|
||||
|
||||
@@ -74,8 +74,15 @@ The default version is always ES6.
|
||||
|
||||
#### New Rules
|
||||
|
||||
##### Apex
|
||||
|
||||
* The Apex rule {% rule "apex/design/UnusedMethod" %} finds unused methods in your code.
|
||||
|
||||
##### Java
|
||||
|
||||
* {% rule "java/codestyle/UnnecessaryBoxing" %} reports boxing and unboxing
|
||||
conversions that may be made implicit.
|
||||
|
||||
#### Changed Rules
|
||||
|
||||
##### Java
|
||||
|
||||
@@ -35,7 +35,25 @@ Note: Support for Java 15 preview language features have been removed. The versi
|
||||
|
||||
#### New rules
|
||||
|
||||
This release ships with 1 new Java rule.
|
||||
This release ships with 3 new Java rules.
|
||||
|
||||
* {% rule java/bestpractices/PrimitiveWrapperInstantiation %} reports usages of primitive wrapper
|
||||
constructors. They are deprecated since Java 9 and should not be used.
|
||||
|
||||
```xml
|
||||
<rule ref="category/java/bestpractices.xml/PrimitiveWrapperInstantiation" />
|
||||
```
|
||||
|
||||
The rule is part of the quickstart.xml ruleset.
|
||||
|
||||
* {% rule java/bestpractices/SimplifiableTestAssertion %} suggests rewriting
|
||||
some test assertions to be more readable.
|
||||
|
||||
```xml
|
||||
<rule ref="category/java/bestpractices.xml/SimplifiableTestAssertion" />
|
||||
```
|
||||
|
||||
The rule is part of the quickstart.xml ruleset.
|
||||
|
||||
* {% rule java/errorprone/ReturnEmptyCollectionRatherThanNull %} suggests returning empty collections / arrays
|
||||
instead of null.
|
||||
@@ -57,9 +75,33 @@ This release ships with 1 new Java rule.
|
||||
|
||||
#### Deprecated rules
|
||||
|
||||
The rule {% rule java/errorprone/ReturnEmptyArrayRatherThanNull %} is deprecated and removed from
|
||||
the quickstart ruleset, as the new rule {% rule java/errorprone/ReturnEmptyCollectionRatherThanNull %}
|
||||
supersedes it.
|
||||
* The following Java rules are deprecated and removed from the quickstart ruleset,
|
||||
as the new rule {% rule java/bestpractices/SimplifiableTestAssertion %} merges
|
||||
their functionality:
|
||||
* {% rule java/bestpractices/UseAssertEqualsInsteadOfAssertTrue %}
|
||||
* {% rule java/bestpractices/UseAssertNullInsteadOfAssertTrue %}
|
||||
* {% rule java/bestpractices/UseAssertSameInsteadOfAssertTrue %}
|
||||
* {% rule java/bestpractices/UseAssertTrueInsteadOfAssertEquals %}
|
||||
* {% rule java/design/SimplifyBooleanAssertion %}
|
||||
|
||||
* The Java rule {% rule java/errorprone/ReturnEmptyArrayRatherThanNull %} is deprecated and removed from
|
||||
the quickstart ruleset, as the new rule {% rule java/errorprone/ReturnEmptyCollectionRatherThanNull %}
|
||||
supersedes it.
|
||||
|
||||
* The following Java rules are deprecated and removed from the quickstart ruleset,
|
||||
as the new rule {% rule java/bestpractices/PrimitiveWrapperInstantiation %} merges
|
||||
their functionality:
|
||||
* {% rule java/performance/BooleanInstantiation %}
|
||||
* {% rule java/performance/ByteInstantiation %}
|
||||
* {% rule java/performance/IntegerInstantiation %}
|
||||
* {% rule java/performance/LongInstantiation %}
|
||||
* {% rule java/performance/ShortInstantiation %}
|
||||
|
||||
* The Java rule {% rule java/performance/UnnecessaryWrapperObjectCreation %} is deprecated
|
||||
with no planned replacement before PMD 7. In it's current state, the rule is not useful
|
||||
as it finds only contrived cases of creating a primitive wrapper and unboxing it explicitly
|
||||
in the same expression. In PMD 7 this and more cases will be covered by a
|
||||
new rule `UnnecessaryBoxing`.
|
||||
|
||||
### Fixed Issues
|
||||
|
||||
@@ -67,8 +109,12 @@ supersedes it.
|
||||
* [#3201](https://github.com/pmd/pmd/issues/3201): \[apex] ApexCRUDViolation doesn't report Database class DMLs, inline no-arg object instantiations and inline list initialization
|
||||
* [#3329](https://github.com/pmd/pmd/issues/3329): \[apex] ApexCRUDViolation doesn't report SOQL for loops
|
||||
* core
|
||||
* [#1603](https://github.com/pmd/pmd/issues/1603): \[core] Language version comparison
|
||||
* [#3377](https://github.com/pmd/pmd/issues/3377): \[core] NPE when specifying report file in current directory in PMD CLI
|
||||
* [#3387](https://github.com/pmd/pmd/issues/3387): \[core] CPD should avoid unnecessary copies when running with --skip-lexical-errors
|
||||
* java-bestpractices
|
||||
* [#2908](https://github.com/pmd/pmd/issues/2908): \[java] Merge Junit assertion simplification rules
|
||||
* [#3235](https://github.com/pmd/pmd/issues/3235): \[java] UseTryWithResources false positive when closeable is provided as a method argument or class field
|
||||
* java-errorprone
|
||||
* [#3361](https://github.com/pmd/pmd/issues/3361): \[java] Rename rule MissingBreakInSwitch to ImplicitSwitchFallThrough
|
||||
* [#3382](https://github.com/pmd/pmd/pull/3382): \[java] New rule ReturnEmptyCollectionRatherThanNull
|
||||
@@ -83,6 +129,14 @@ supersedes it.
|
||||
{% jdoc !!java::lang.java.ast.ASTClassOrInterfaceDeclaration#getPermittedSubclasses() %}
|
||||
* {% jdoc java::lang.java.ast.ASTPermitsList %}
|
||||
|
||||
#### Internal API
|
||||
|
||||
Those APIs are not intended to be used by clients, and will be hidden or removed with PMD 7.0.0.
|
||||
You can identify them with the `@InternalApi` annotation. You'll also get a deprecation warning.
|
||||
|
||||
* The inner class {% jdoc !!core::cpd.TokenEntry.State %} is considered to be internal API.
|
||||
It will probably be moved away with PMD 7.
|
||||
|
||||
### External Contributions
|
||||
|
||||
* [#3367](https://github.com/pmd/pmd/pull/3367): \[apex] Check SOQL CRUD on for loops - [Jonathan Wiesel](https://github.com/jonathanwiesel)
|
||||
|
||||
@@ -147,12 +147,12 @@ public class CPD {
|
||||
}
|
||||
|
||||
private void addAndSkipLexicalErrors(SourceCode sourceCode) throws IOException {
|
||||
final TokenEntry.State savedState = tokens.snapshot();
|
||||
final TokenEntry.State savedState = new TokenEntry.State();
|
||||
try {
|
||||
addAndThrowLexicalError(sourceCode);
|
||||
} catch (TokenMgrError e) {
|
||||
System.err.println("Skipping " + sourceCode.getFileName() + ". Reason: " + e.getMessage());
|
||||
tokens.restore(savedState);
|
||||
savedState.restore(tokens);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
|
||||
public class TokenEntry implements Comparable<TokenEntry> {
|
||||
|
||||
public static final TokenEntry EOF = new TokenEntry();
|
||||
@@ -92,7 +94,11 @@ public class TokenEntry implements Comparable<TokenEntry> {
|
||||
/**
|
||||
* Helper class to preserve and restore the current state of the token
|
||||
* entries.
|
||||
*
|
||||
* @deprecated This is internal API.
|
||||
*/
|
||||
@InternalApi
|
||||
@Deprecated
|
||||
public static class State {
|
||||
private final int tokenCount;
|
||||
private final int tokensMapSize;
|
||||
@@ -102,7 +108,8 @@ public class TokenEntry implements Comparable<TokenEntry> {
|
||||
this.tokensMapSize = TokenEntry.TOKENS.get().size();
|
||||
}
|
||||
|
||||
public void restore(final List<TokenEntry> entries) {
|
||||
public void restore(Tokens tokens) {
|
||||
final List<TokenEntry> entries = tokens.getTokens();
|
||||
TokenEntry.TOKEN_COUNT.get().set(tokenCount);
|
||||
final Iterator<Map.Entry<String, Integer>> it = TOKENS.get().entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
|
||||
@@ -8,8 +8,6 @@ import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.cpd.TokenEntry.State;
|
||||
|
||||
public class Tokens {
|
||||
|
||||
private List<TokenEntry> tokens = new ArrayList<>();
|
||||
@@ -45,13 +43,4 @@ public class Tokens {
|
||||
public List<TokenEntry> getTokens() {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
public State snapshot() {
|
||||
return new State();
|
||||
}
|
||||
|
||||
public void restore(final State savedState) {
|
||||
savedState.restore(tokens);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
package net.sourceforge.pmd.lang;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.Rule;
|
||||
import net.sourceforge.pmd.annotation.InternalApi;
|
||||
|
||||
@@ -120,27 +122,10 @@ public class LanguageVersion implements Comparable<LanguageVersion> {
|
||||
|
||||
@Override
|
||||
public int compareTo(LanguageVersion o) {
|
||||
if (o == null) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int comp = getName().compareTo(o.getName());
|
||||
if (comp != 0) {
|
||||
return comp;
|
||||
}
|
||||
|
||||
String[] vals1 = getName().split("\\.");
|
||||
String[] vals2 = o.getName().split("\\.");
|
||||
int i = 0;
|
||||
while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) {
|
||||
i++;
|
||||
}
|
||||
if (i < vals1.length && i < vals2.length) {
|
||||
int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i]));
|
||||
return Integer.signum(diff);
|
||||
} else {
|
||||
return Integer.signum(vals1.length - vals2.length);
|
||||
}
|
||||
List<LanguageVersion> versions = language.getVersions();
|
||||
int thisPosition = versions.indexOf(this);
|
||||
int otherPosition = versions.indexOf(o);
|
||||
return Integer.compare(thisPosition, otherPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<ruleset name="6370"
|
||||
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.37.0
|
||||
</description>
|
||||
|
||||
<rule ref="category/java/bestpractices.xml/PrimitiveWrapperInstantiation" />
|
||||
<rule ref="category/java/bestpractices.xml/SimplifiableTestAssertion" />
|
||||
<rule ref="category/java/errorprone.xml/ReturnEmptyCollectionRatherThanNull" />
|
||||
|
||||
</ruleset>
|
||||
@@ -10,5 +10,7 @@ This ruleset contains links to rules that are new in PMD v7.0.0
|
||||
|
||||
<rule ref="category/apex/design.xml/UnusedMethod"/>
|
||||
|
||||
<rule ref="category/java/codestyle.xml/UnnecessaryBoxing"/>
|
||||
|
||||
</ruleset>
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.rule.bestpractices;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTArguments;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTArrayDimsAndInits;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTBooleanLiteral;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTLiteral;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
|
||||
import net.sourceforge.pmd.lang.java.ast.JavaNode;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
|
||||
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
|
||||
|
||||
public class PrimitiveWrapperInstantiationRule extends AbstractJavaRule {
|
||||
|
||||
public PrimitiveWrapperInstantiationRule() {
|
||||
addRuleChainVisit(ASTAllocationExpression.class);
|
||||
addRuleChainVisit(ASTPrimaryExpression.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTAllocationExpression node, Object data) {
|
||||
if (node.getFirstChildOfType(ASTArrayDimsAndInits.class) != null) {
|
||||
return data;
|
||||
}
|
||||
ASTClassOrInterfaceType type = node.getFirstChildOfType(ASTClassOrInterfaceType.class);
|
||||
if (type == null) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (TypeTestUtil.isA(Double.class, type)
|
||||
|| TypeTestUtil.isA(Float.class, type)
|
||||
|| TypeTestUtil.isA(Long.class, type)
|
||||
|| TypeTestUtil.isA(Integer.class, type)
|
||||
|| TypeTestUtil.isA(Short.class, type)
|
||||
|| TypeTestUtil.isA(Byte.class, type)
|
||||
|| TypeTestUtil.isA(Character.class, type)) {
|
||||
addViolation(data, node, type.getImage());
|
||||
} else if (TypeTestUtil.isA(Boolean.class, type)) {
|
||||
checkArguments(node.getFirstChildOfType(ASTArguments.class), node, data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds calls of "Boolean.valueOf".
|
||||
*/
|
||||
@Override
|
||||
public Object visit(ASTPrimaryExpression node, Object data) {
|
||||
if (!TypeTestUtil.isA(Boolean.class, node)) {
|
||||
return data;
|
||||
}
|
||||
|
||||
if (node.getNumChildren() >= 2 && node.getChild(0).getNumChildren() > 0
|
||||
&& node.getChild(0).getChild(0) instanceof ASTName
|
||||
&& node.getChild(0).getChild(0).hasImageEqualTo("Boolean.valueOf")) {
|
||||
ASTPrimarySuffix suffix = (ASTPrimarySuffix) node.getChild(1);
|
||||
checkArguments(suffix.getFirstChildOfType(ASTArguments.class), node, data);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private void checkArguments(ASTArguments arguments, JavaNode node, Object data) {
|
||||
if (arguments == null || arguments.size() != 1) {
|
||||
return;
|
||||
}
|
||||
String messagePart = node instanceof ASTAllocationExpression
|
||||
? "Do not use `new Boolean"
|
||||
: "Do not use `Boolean.valueOf";
|
||||
ASTLiteral stringLiteral = getFirstArgStringLiteralOrNull(arguments);
|
||||
ASTBooleanLiteral boolLiteral = getFirstArgBooleanLiteralOrNull(arguments);
|
||||
if (stringLiteral != null) {
|
||||
if (stringLiteral.hasImageEqualTo("\"true\"")) {
|
||||
addViolationWithMessage(data, node, messagePart + "(\"true\")`, prefer `Boolean.TRUE`");
|
||||
} else if (stringLiteral.hasImageEqualTo("\"false\"")) {
|
||||
addViolationWithMessage(data, node, messagePart + "(\"false\")`, prefer `Boolean.FALSE`");
|
||||
}
|
||||
} else if (boolLiteral != null) {
|
||||
if (boolLiteral.isTrue()) {
|
||||
addViolationWithMessage(data, node, messagePart + "(true)`, prefer `Boolean.TRUE`");
|
||||
} else {
|
||||
addViolationWithMessage(data, node, messagePart + "(false)`, prefer `Boolean.FALSE`");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* └─ Arguments
|
||||
* └─ ArgumentList
|
||||
* └─ Expression
|
||||
* └─ PrimaryExpression
|
||||
* └─ PrimaryPrefix
|
||||
* └─ Literal
|
||||
* </pre>
|
||||
*/
|
||||
private static ASTLiteral getFirstArgStringLiteralOrNull(ASTArguments arguments) {
|
||||
if (arguments.size() == 1) {
|
||||
ASTExpression expr = arguments.getFirstDescendantOfType(ASTExpression.class);
|
||||
ASTPrimaryExpression primaryExpr = getSingleChildOf(expr, ASTPrimaryExpression.class);
|
||||
ASTPrimaryPrefix prefix = getSingleChildOf(primaryExpr, ASTPrimaryPrefix.class);
|
||||
ASTLiteral literal = getSingleChildOf(prefix, ASTLiteral.class);
|
||||
if (literal != null && literal.isStringLiteral()) {
|
||||
return literal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* └─ Arguments
|
||||
* └─ ArgumentList
|
||||
* └─ Expression
|
||||
* └─ PrimaryExpression
|
||||
* └─ PrimaryPrefix
|
||||
* └─ Literal
|
||||
* └─ BooleanLiteral
|
||||
* </pre>
|
||||
*/
|
||||
private static ASTBooleanLiteral getFirstArgBooleanLiteralOrNull(ASTArguments arguments) {
|
||||
if (arguments.size() == 1) {
|
||||
ASTExpression expr = arguments.getFirstDescendantOfType(ASTExpression.class);
|
||||
ASTPrimaryExpression primaryExpr = getSingleChildOf(expr, ASTPrimaryExpression.class);
|
||||
ASTPrimaryPrefix prefix = getSingleChildOf(primaryExpr, ASTPrimaryPrefix.class);
|
||||
ASTLiteral literal = getSingleChildOf(prefix, ASTLiteral.class);
|
||||
return getSingleChildOf(literal, ASTBooleanLiteral.class);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static <N extends JavaNode> N getSingleChildOf(JavaNode node, Class<N> type) {
|
||||
if (node == null || node.getNumChildren() != 1
|
||||
|| type != node.getChild(0).getClass()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
N result = (N) node.getChild(0);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
+327
File diff suppressed because it is too large.
Load diff
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.rule.bestpractices;
|
||||
|
||||
import static net.sourceforge.pmd.properties.PropertyFactory.stringListProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTFinallyClause;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTryStatement;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTTypeExpression;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
|
||||
import net.sourceforge.pmd.lang.java.rule.internal.JavaRuleUtil;
|
||||
import net.sourceforge.pmd.lang.java.types.TypeTestUtil;
|
||||
import net.sourceforge.pmd.properties.PropertyDescriptor;
|
||||
|
||||
public final class UseTryWithResourcesRule extends AbstractJavaRulechainRule {
|
||||
|
||||
private static final PropertyDescriptor<List<String>> CLOSE_METHODS =
|
||||
stringListProperty("closeMethods")
|
||||
.desc("Method names in finally block, which trigger this rule")
|
||||
.defaultValues("close", "closeQuietly")
|
||||
.delim(',')
|
||||
.build();
|
||||
|
||||
public UseTryWithResourcesRule() {
|
||||
super(ASTTryStatement.class);
|
||||
definePropertyDescriptor(CLOSE_METHODS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTTryStatement node, Object data) {
|
||||
boolean isJava9OrLater = node.getAstInfo().getLanguageVersion().compareToVersion("9") >= 0;
|
||||
|
||||
ASTFinallyClause finallyClause = node.getFinallyClause();
|
||||
if (finallyClause != null) {
|
||||
List<ASTMethodCall> methods = finallyClause.descendants(ASTMethodCall.class)
|
||||
.filter(m -> getProperty(CLOSE_METHODS).contains(m.getMethodName()))
|
||||
.toList();
|
||||
for (ASTMethodCall method : methods) {
|
||||
ASTExpression closeTarget = method.getQualifier();
|
||||
if (!(closeTarget instanceof ASTTypeExpression) // ignore static method calls
|
||||
&& TypeTestUtil.isA(AutoCloseable.class, closeTarget)
|
||||
&& (isJava9OrLater || JavaRuleUtil.isReferenceToLocal(closeTarget))
|
||||
|| hasAutoClosableArguments(method)) {
|
||||
addViolation(data, node);
|
||||
break; // only report the first closeable
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private boolean hasAutoClosableArguments(ASTMethodCall method) {
|
||||
return method.getArguments().children()
|
||||
.filter(e -> TypeTestUtil.isA(AutoCloseable.class, e))
|
||||
.nonEmpty();
|
||||
}
|
||||
}
|
||||
+168
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java.rule.codestyle;
|
||||
|
||||
import static net.sourceforge.pmd.util.CollectionUtil.setOf;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.RuleContext;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTConstructorCall;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTList;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTMethodCall;
|
||||
import net.sourceforge.pmd.lang.java.ast.InvocationNode;
|
||||
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRulechainRule;
|
||||
import net.sourceforge.pmd.lang.java.types.JMethodSig;
|
||||
import net.sourceforge.pmd.lang.java.types.JTypeMirror;
|
||||
import net.sourceforge.pmd.lang.java.types.OverloadSelectionResult;
|
||||
import net.sourceforge.pmd.lang.java.types.TypePrettyPrint;
|
||||
import net.sourceforge.pmd.lang.java.types.ast.ExprContext;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class UnnecessaryBoxingRule extends AbstractJavaRulechainRule {
|
||||
|
||||
private static final Set<String> INTERESTING_NAMES = setOf(
|
||||
"valueOf",
|
||||
"booleanValue",
|
||||
"charValue",
|
||||
"byteValue",
|
||||
"shortValue",
|
||||
"intValue",
|
||||
"longValue",
|
||||
"floatValue",
|
||||
"doubleValue"
|
||||
);
|
||||
|
||||
public UnnecessaryBoxingRule() {
|
||||
super(ASTMethodCall.class, ASTConstructorCall.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTConstructorCall node, Object data) {
|
||||
if (node.getTypeMirror().isBoxedPrimitive()) {
|
||||
ASTExpression arg = ASTList.singleOrNull(node.getArguments());
|
||||
if (arg == null) {
|
||||
return null;
|
||||
}
|
||||
JTypeMirror argT = arg.getTypeMirror();
|
||||
if (argT.isPrimitive()) {
|
||||
checkBox((RuleContext) data, "boxing", node, arg, node.getMethodType().getFormalParameters().get(0));
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object visit(ASTMethodCall node, Object data) {
|
||||
if (INTERESTING_NAMES.contains(node.getMethodName())) {
|
||||
OverloadSelectionResult overload = node.getOverloadSelectionInfo();
|
||||
if (overload.isFailed()) {
|
||||
return null;
|
||||
}
|
||||
JMethodSig m = overload.getMethodType();
|
||||
boolean isValueOf = "valueOf".equals(node.getMethodName());
|
||||
ASTExpression qualifier = node.getQualifier();
|
||||
|
||||
if (isValueOf && isWrapperValueOf(m)) {
|
||||
checkBox((RuleContext) data, "boxing", node, node.getArguments().get(0), m.getFormalParameters().get(0));
|
||||
} else if (!isValueOf && isUnboxingCall(m) && qualifier != null) {
|
||||
checkBox((RuleContext) data, "unboxing", node, qualifier, qualifier.getTypeMirror());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isUnboxingCall(JMethodSig m) {
|
||||
return !m.isStatic() && m.getDeclaringType().isBoxedPrimitive() && m.getArity() == 0;
|
||||
}
|
||||
|
||||
private boolean isWrapperValueOf(JMethodSig m) {
|
||||
return m.isStatic()
|
||||
&& m.getArity() == 1
|
||||
&& m.getDeclaringType().isBoxedPrimitive()
|
||||
&& m.getFormalParameters().get(0).isPrimitive();
|
||||
}
|
||||
|
||||
private void checkBox(
|
||||
RuleContext rctx,
|
||||
String opKind,
|
||||
ASTExpression conversionExpr,
|
||||
ASTExpression convertedExpr,
|
||||
JTypeMirror conversionInput
|
||||
) {
|
||||
// the conversion looks like
|
||||
// CTX _ = conversion(sourceExpr)
|
||||
|
||||
// we have the following data flow:
|
||||
// sourceExpr -> convInput -> convOutput -> ctx
|
||||
// 1 2 3
|
||||
// where 1 and 3 are implicit conversions which we assume are
|
||||
// valid because the code should compile.
|
||||
|
||||
// we want to report a violation if this is equivalent to
|
||||
// sourceExpr -> ctx
|
||||
|
||||
// which basically means testing that convInput -> convOutput
|
||||
// may be performed implicitly.
|
||||
|
||||
// We cannot just test compatibility of the source to the ctx,
|
||||
// because of situations like
|
||||
// int i = integer.byteValue()
|
||||
// where the conversion actually truncates the input value.
|
||||
|
||||
JTypeMirror sourceType = convertedExpr.getTypeMirror();
|
||||
JTypeMirror conversionOutput = conversionExpr.getTypeMirror();
|
||||
ExprContext ctx = conversionExpr.getConversionContext();
|
||||
JTypeMirror ctxType = ctx.getTargetType();
|
||||
if (ctxType == null && conversionExpr instanceof InvocationNode) {
|
||||
ctxType = conversionOutput;
|
||||
}
|
||||
|
||||
if (ctxType != null) {
|
||||
|
||||
if (isImplicitlyConvertible(conversionInput, conversionOutput)) {
|
||||
|
||||
boolean simpleConv = isReferenceSubtype(sourceType, conversionInput);
|
||||
|
||||
final String reason;
|
||||
if (simpleConv && conversionInput.unbox().equals(conversionOutput)) {
|
||||
reason = "explicit unboxing";
|
||||
} else if (simpleConv && conversionInput.box().equals(conversionOutput)) {
|
||||
reason = "explicit boxing";
|
||||
} else if (sourceType.equals(conversionOutput)) {
|
||||
reason = "boxing of boxed value";
|
||||
} else {
|
||||
if (sourceType.equals(ctxType)) {
|
||||
reason = opKind;
|
||||
} else {
|
||||
reason = "explicit conversion from " + TypePrettyPrint.prettyPrintWithSimpleNames(sourceType) + " to " + TypePrettyPrint.prettyPrintWithSimpleNames(ctxType);
|
||||
}
|
||||
}
|
||||
|
||||
addViolation(rctx, conversionExpr, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isImplicitlyConvertible(JTypeMirror i, JTypeMirror o) {
|
||||
return i.box().isSubtypeOf(o.box())
|
||||
|| i.unbox().isSubtypeOf(o.unbox());
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether {@code S <: T}, but ignoring primitive widening.
|
||||
* {@code isReferenceSubtype(int, double) == false} even though
|
||||
* {@code int.isSubtypeOf(double)}.
|
||||
*/
|
||||
private static boolean isReferenceSubtype(JTypeMirror s, JTypeMirror t) {
|
||||
return s.isPrimitive() ? t.equals(s)
|
||||
: s.isSubtypeOf(t);
|
||||
}
|
||||
|
||||
}
|
||||
+2
-2
@@ -75,6 +75,7 @@ import net.sourceforge.pmd.lang.java.ast.TypeNode;
|
||||
import net.sourceforge.pmd.lang.java.ast.UnaryOp;
|
||||
import net.sourceforge.pmd.lang.java.symbols.JFieldSymbol;
|
||||
import net.sourceforge.pmd.lang.java.symbols.JVariableSymbol;
|
||||
import net.sourceforge.pmd.lang.java.symbols.internal.ast.AstLocalVarSym;
|
||||
import net.sourceforge.pmd.lang.java.types.InvocationMatcher;
|
||||
import net.sourceforge.pmd.lang.java.types.InvocationMatcher.CompoundInvocationMatcher;
|
||||
import net.sourceforge.pmd.lang.java.types.JPrimitiveType.PrimitiveTypeKind;
|
||||
@@ -806,8 +807,7 @@ public final class JavaRuleUtil {
|
||||
*/
|
||||
public static boolean isReferenceToLocal(ASTExpression expr) {
|
||||
if (expr instanceof ASTVariableAccess) {
|
||||
JVariableSymbol sym = ((ASTVariableAccess) expr).getReferencedSym();
|
||||
return sym != null && !sym.isField();
|
||||
return ((ASTVariableAccess) expr).getReferencedSym() instanceof AstLocalVarSym;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
-1
@@ -31,7 +31,6 @@ public class BigIntegerInstantiationRule extends AbstractJavaRulechainRule {
|
||||
super(ASTConstructorCall.class);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object visit(ASTConstructorCall node, Object data) {
|
||||
LanguageVersion languageVersion = node.getAstInfo().getLanguageVersion();
|
||||
|
||||
+1
-4
@@ -8,9 +8,7 @@ import static net.sourceforge.pmd.util.CollectionUtil.setOf;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
import net.sourceforge.pmd.lang.java.JavaLanguageModule;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTName;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryExpression;
|
||||
import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
|
||||
@@ -36,8 +34,7 @@ public class UnnecessaryWrapperObjectCreationRule extends AbstractJavaRule {
|
||||
image = image.substring(10);
|
||||
}
|
||||
|
||||
boolean checkBoolean = node.getAstInfo().getLanguageVersion()
|
||||
.compareTo(LanguageRegistry.getLanguage(JavaLanguageModule.NAME).getVersion("1.5")) >= 0;
|
||||
boolean checkBoolean = node.getAstInfo().getLanguageVersion().compareToVersion("1.5") >= 0;
|
||||
|
||||
if (PREFIX_SET.contains(image) || checkBoolean && "Boolean.valueOf".equals(image)) {
|
||||
ASTPrimaryExpression parent = (ASTPrimaryExpression) node.getParent();
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import net.sourceforge.pmd.lang.java.types.Substitution;
|
||||
/**
|
||||
* @author Clément Fournier
|
||||
*/
|
||||
final class AstLocalVarSym extends AbstractAstVariableSym implements JLocalVariableSymbol {
|
||||
public final class AstLocalVarSym extends AbstractAstVariableSym implements JLocalVariableSymbol {
|
||||
|
||||
AstLocalVarSym(ASTVariableDeclaratorId node, AstSymFactory factory) {
|
||||
super(node, factory);
|
||||
|
||||
@@ -31,6 +31,10 @@ public final class TypePrettyPrint {
|
||||
return prettyPrint(t, new TypePrettyPrinter());
|
||||
}
|
||||
|
||||
public static @NonNull String prettyPrintWithSimpleNames(@NonNull JTypeVisitable t) {
|
||||
return prettyPrint(t, new TypePrettyPrinter().useSimpleNames(true));
|
||||
}
|
||||
|
||||
public static String prettyPrint(@NonNull JTypeVisitable t, TypePrettyPrinter prettyPrinter) {
|
||||
t.acceptVisitor(PrettyPrintVisitor.INSTANCE, prettyPrinter);
|
||||
return prettyPrinter.consumeResult();
|
||||
|
||||
@@ -802,7 +802,6 @@ public class MyTest {
|
||||
since="6.35.0"
|
||||
message="JUnit 5 tests should be package-private."
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
||||
typeResolution="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#junit5testshouldbepackageprivate">
|
||||
<description><![CDATA[
|
||||
Reports JUnit 5 test classes and methods that are not package-private.
|
||||
@@ -1197,6 +1196,36 @@ public class Foo {
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
<rule name="PrimitiveWrapperInstantiation"
|
||||
language="java"
|
||||
since="6.37.0"
|
||||
message="Do not use `new {0}(...)`, prefer `{0}.valueOf(...)`"
|
||||
class="net.sourceforge.pmd.lang.java.rule.bestpractices.PrimitiveWrapperInstantiationRule"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#primitivewrapperinstantiation">
|
||||
<description>
|
||||
Reports usages of primitive wrapper constructors. They are deprecated
|
||||
since Java 9 and should not be used. Even before Java 9, they can
|
||||
be replaced with usage of the corresponding static `valueOf` factory method
|
||||
(which may be automatically inserted by the compiler since Java 1.5).
|
||||
This has the advantage that it may reuse common instances instead of creating
|
||||
a new instance each time.
|
||||
|
||||
Note that for `Boolean`, the named constants `Boolean.TRUE` and `Boolean.FALSE`
|
||||
are preferred instead of `Boolean.valueOf`.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<example>
|
||||
<![CDATA[
|
||||
public class Foo {
|
||||
private Integer ZERO = new Integer(0); // violation
|
||||
private Integer ZERO1 = Integer.valueOf(0); // better
|
||||
private Integer ZERO1 = 0; // even better
|
||||
}
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
|
||||
<rule name="ReplaceEnumerationWithIterator"
|
||||
language="java"
|
||||
since="3.4"
|
||||
@@ -1287,6 +1316,49 @@ public class Foo {
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
<rule name="SimplifiableTestAssertion"
|
||||
language="java"
|
||||
since="6.37.0"
|
||||
message="Assertion may be simplified using {0}"
|
||||
class="net.sourceforge.pmd.lang.java.rule.bestpractices.SimplifiableTestAssertionRule"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#simplifiabletestassertion">
|
||||
<description>
|
||||
Reports test assertions that may be simplified using a more specific
|
||||
assertion method. This enables better error messages, and makes the
|
||||
assertions more readable.
|
||||
|
||||
The rule only applies within test classes for the moment. It replaces
|
||||
the deprecated rules {% rule UseAssertEqualsInsteadOfAssertTrue %},
|
||||
{% rule UseAssertNullInsteadOfAssertTrue %}, {% rule UseAssertSameInsteadOfAssertTrue %},
|
||||
{% rule UseAssertTrueInsteadOfAssertEquals %}, and {% rule java/design/SimplifyBooleanAssertion %}.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<example>
|
||||
<![CDATA[
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
class SomeTestClass {
|
||||
Object a,b;
|
||||
@Test
|
||||
void testMethod() {
|
||||
assertTrue(a.equals(b)); // could be assertEquals(a, b);
|
||||
assertTrue(!a.equals(b)); // could be assertNotEquals(a, b);
|
||||
|
||||
assertTrue(!something); // could be assertFalse(something);
|
||||
assertFalse(!something); // could be assertTrue(something);
|
||||
|
||||
assertTrue(a == b); // could be assertSame(a, b);
|
||||
assertTrue(a != b); // could be assertNotSame(a, b);
|
||||
|
||||
assertTrue(a == null); // could be assertNull(a);
|
||||
assertTrue(a != null); // could be assertNotNull(a);
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
<rule name="SwitchStmtsShouldHaveDefault"
|
||||
language="java"
|
||||
since="1.0"
|
||||
@@ -1580,9 +1652,12 @@ public class Something {
|
||||
since="3.1"
|
||||
message="Use assertEquals(x, y) instead of assertTrue(x.equals(y))"
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
||||
deprecated="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#useassertequalsinsteadofasserttrue">
|
||||
<description>
|
||||
This rule detects JUnit assertions in object equality. These assertions should be made by more specific methods, like assertEquals.
|
||||
|
||||
Deprecated since PMD 6.37.0, use {% rule SimplifiableTestAssertion %} instead.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
@@ -1615,10 +1690,13 @@ public class FooTest extends TestCase {
|
||||
since="3.5"
|
||||
message="Use assertNull(x) instead of assertTrue(x==null), or assertNotNull(x) vs assertFalse(x==null)"
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
||||
deprecated="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#useassertnullinsteadofasserttrue">
|
||||
<description>
|
||||
This rule detects JUnit assertions in object references equality. These assertions should be made by
|
||||
more specific methods, like assertNull, assertNotNull.
|
||||
|
||||
Deprecated since PMD 6.37.0, use {% rule SimplifiableTestAssertion %} instead.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
@@ -1655,10 +1733,13 @@ public class FooTest extends TestCase {
|
||||
since="3.1"
|
||||
message="Use assertSame(x, y) instead of assertTrue(x==y), or assertNotSame(x,y) vs assertFalse(x==y)"
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
||||
deprecated="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#useassertsameinsteadofasserttrue">
|
||||
<description>
|
||||
This rule detects JUnit assertions in object references equality. These assertions should be made
|
||||
by more specific methods, like assertSame, assertNotSame.
|
||||
|
||||
Deprecated since PMD 6.37.0, use {% rule SimplifiableTestAssertion %} instead.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
@@ -1693,9 +1774,12 @@ public class FooTest extends TestCase {
|
||||
since="5.0"
|
||||
message="Use assertTrue(x)/assertFalse(x) instead of assertEquals(true, x)/assertEquals(false, x) or assertEquals(Boolean.TRUE, x)/assertEquals(Boolean.FALSE, x)."
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
||||
deprecated="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#useasserttrueinsteadofassertequals">
|
||||
<description>
|
||||
When asserting a value is the same as a literal or Boxed boolean, use assertTrue/assertFalse, instead of assertEquals.
|
||||
|
||||
Deprecated since PMD 6.37.0, use {% rule SimplifiableTestAssertion %} instead.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
@@ -1816,7 +1900,7 @@ public class UseStandardCharsets {
|
||||
minimumLanguageVersion="1.7"
|
||||
since="6.12.0"
|
||||
message="Consider using a try-with-resources statement instead of explicitly closing the resource"
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
||||
class="net.sourceforge.pmd.lang.java.rule.bestpractices.UseTryWithResourcesRule"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#usetrywithresources">
|
||||
<description>
|
||||
Java 7 introduced the try-with-resources statement. This statement ensures that each resource is closed at the end
|
||||
@@ -1826,21 +1910,6 @@ the try block was suppressed. With the `try`-with-resources statement, the excep
|
||||
preserved.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
<property name="closeMethods" type="List[String]" delimiter="," description="Method names in finally block, which trigger this rule" value="close,closeQuietly"/>
|
||||
<property name="xpath">
|
||||
<value>
|
||||
<![CDATA[
|
||||
//TryStatement[FinallyClause//ExpressionStatement/MethodCall[@MethodName = $closeMethods][
|
||||
(: vvvvvvvvvvvvvvvvvvvvvvvvv This is to rule out static method call :)
|
||||
*[1][not(self::TypeExpression) and pmd-java:typeIs('java.lang.AutoCloseable')]
|
||||
or
|
||||
ArgumentList/*[pmd-java:typeIs('java.lang.AutoCloseable')]
|
||||
]]
|
||||
]]>
|
||||
</value>
|
||||
</property>
|
||||
</properties>
|
||||
<example>
|
||||
<![CDATA[
|
||||
public class TryWithResources {
|
||||
|
||||
@@ -1477,6 +1477,36 @@ public class Foo {
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
<rule name="UnnecessaryBoxing"
|
||||
language="java"
|
||||
since="7.0.0"
|
||||
minimumLanguageVersion="1.5"
|
||||
message="Unnecessary {0}"
|
||||
class="net.sourceforge.pmd.lang.java.rule.codestyle.UnnecessaryBoxingRule"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#unnecessaryboxing">
|
||||
<description>
|
||||
Reports explicit boxing and unboxing conversions that may safely be removed,
|
||||
either because they would be inserted by the compiler automatically,
|
||||
or because they're semantically a noop (eg unboxing a value to rebox it immediately).
|
||||
|
||||
Note that this only handles boxing and unboxing conversions occurring through
|
||||
calls to `valueOf` or one of the `intValue`, `byteValue`, etc. methods. Casts
|
||||
that command a conversion are reported by {% rule UnnecessaryCast %} instead.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<example><![CDATA[
|
||||
{
|
||||
// Instead of
|
||||
Integer integer = Integer.valueOf(2);
|
||||
// you may just write
|
||||
Integer integer = 2;
|
||||
|
||||
int i = integer.intValue(); // similarly for unboxing
|
||||
}
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
<!-- This is only restricted to java 5+ because the rule doesn't support
|
||||
the type system pre-java5, where there were no autoboxing conversions. -->
|
||||
<rule name="UnnecessaryCast"
|
||||
|
||||
@@ -1169,6 +1169,7 @@ public class Foo {
|
||||
since="3.6"
|
||||
message="assertTrue(!expr) can be replaced by assertFalse(expr)"
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
||||
deprecated="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_design.html#simplifybooleanassertion">
|
||||
<description>
|
||||
Avoid negation in an assertTrue or assertFalse test.
|
||||
@@ -1181,6 +1182,7 @@ as:
|
||||
|
||||
assertFalse(expr);
|
||||
|
||||
Deprecated since PMD 6.37.0, use {% rule java/bestpractices/SimplifiableTestAssertion %} instead.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
|
||||
@@ -341,10 +341,13 @@ BigDecimal bd3 = new BigDecimal(10); // reference BigDecimal.TEN instead
|
||||
since="1.2"
|
||||
message="Avoid instantiating Boolean objects; reference Boolean.TRUE or Boolean.FALSE or call Boolean.valueOf() instead."
|
||||
class="net.sourceforge.pmd.lang.java.rule.performance.BooleanInstantiationRule"
|
||||
deprecated="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#booleaninstantiation">
|
||||
<description>
|
||||
Avoid instantiating Boolean objects; you can reference Boolean.TRUE, Boolean.FALSE, or call Boolean.valueOf() instead.
|
||||
Note that new Boolean() is deprecated since JDK 9 for that reason.
|
||||
|
||||
Deprecated since PMD 6.37.0, use {% rule java/bestpractices/PrimitiveWrapperInstantiation %} instead.
|
||||
</description>
|
||||
<priority>2</priority>
|
||||
<example>
|
||||
@@ -360,11 +363,14 @@ Boolean buz = Boolean.valueOf(false); // ...., just reference Boolean.FALSE;
|
||||
since="4.0"
|
||||
message="Avoid instantiating Byte objects. Call Byte.valueOf() instead"
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
||||
deprecated="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#byteinstantiation">
|
||||
<description>
|
||||
Calling new Byte() causes memory allocation that can be avoided by the static Byte.valueOf().
|
||||
It makes use of an internal cache that recycles earlier instances making it more memory efficient.
|
||||
Note that new Byte() is deprecated since JDK 9 for that reason.
|
||||
|
||||
Deprecated since PMD 6.37.0, use {% rule java/bestpractices/PrimitiveWrapperInstantiation %} instead.
|
||||
</description>
|
||||
<priority>2</priority>
|
||||
<properties>
|
||||
@@ -534,11 +540,14 @@ good.append("This is a long string, which is pre-sized");
|
||||
since="3.5"
|
||||
message="Avoid instantiating Integer objects. Call Integer.valueOf() instead."
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
||||
deprecated="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#integerinstantiation">
|
||||
<description>
|
||||
Calling new Integer() causes memory allocation that can be avoided by the static Integer.valueOf().
|
||||
It makes use of an internal cache that recycles earlier instances making it more memory efficient.
|
||||
Note that new Integer() is deprecated since JDK 9 for that reason.
|
||||
|
||||
Deprecated since PMD 6.37.0, use {% rule java/bestpractices/PrimitiveWrapperInstantiation %} instead.
|
||||
</description>
|
||||
<priority>2</priority>
|
||||
<properties>
|
||||
@@ -564,11 +573,14 @@ public class Foo {
|
||||
since="4.0"
|
||||
message="Avoid instantiating Long objects.Call Long.valueOf() instead"
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
||||
deprecated="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#longinstantiation">
|
||||
<description>
|
||||
Calling new Long() causes memory allocation that can be avoided by the static Long.valueOf().
|
||||
It makes use of an internal cache that recycles earlier instances making it more memory efficient.
|
||||
Note that new Long() is deprecated since JDK 9 for that reason.
|
||||
|
||||
Deprecated since PMD 6.37.0, use {% rule java/bestpractices/PrimitiveWrapperInstantiation %} instead.
|
||||
</description>
|
||||
<priority>2</priority>
|
||||
<properties>
|
||||
@@ -717,11 +729,14 @@ public class Foo {
|
||||
since="4.0"
|
||||
message="Avoid instantiating Short objects. Call Short.valueOf() instead"
|
||||
class="net.sourceforge.pmd.lang.rule.XPathRule"
|
||||
deprecated="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#shortinstantiation">
|
||||
<description>
|
||||
Calling new Short() causes memory allocation that can be avoided by the static Short.valueOf().
|
||||
It makes use of an internal cache that recycles earlier instances making it more memory efficient.
|
||||
Note that new Short() is deprecated since JDK 9 for that reason.
|
||||
|
||||
Deprecated since PMD 6.37.0, use {% rule java/bestpractices/PrimitiveWrapperInstantiation %} instead.
|
||||
</description>
|
||||
<priority>2</priority>
|
||||
<properties>
|
||||
@@ -831,11 +846,14 @@ public class Foo {
|
||||
since="3.8"
|
||||
message="Unnecessary wrapper object creation"
|
||||
class="net.sourceforge.pmd.lang.java.rule.performance.UnnecessaryWrapperObjectCreationRule"
|
||||
deprecated="true"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_performance.html#unnecessarywrapperobjectcreation">
|
||||
<description>
|
||||
Most wrapper classes provide static conversion methods that avoid the need to create intermediate objects
|
||||
just to create the primitive forms. Using these avoids the cost of creating objects that also need to be
|
||||
garbage-collected later.
|
||||
|
||||
Deprecated since PMD 6.37.0. The planned replacement is not expected before PMD 7.0.0.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<example>
|
||||
|
||||
@@ -37,10 +37,12 @@
|
||||
<!-- <rule ref="category/java/bestpractices.xml/MethodReturnsInternalArray" /> -->
|
||||
<rule ref="category/java/bestpractices.xml/MissingOverride"/>
|
||||
<rule ref="category/java/bestpractices.xml/OneDeclarationPerLine"/>
|
||||
<rule ref="category/java/bestpractices.xml/PrimitiveWrapperInstantiation"/>
|
||||
<rule ref="category/java/bestpractices.xml/PreserveStackTrace"/>
|
||||
<!-- <rule ref="category/java/bestpractices.xml/ReplaceEnumerationWithIterator" /> -->
|
||||
<!-- <rule ref="category/java/bestpractices.xml/ReplaceHashtableWithMap" /> -->
|
||||
<!-- <rule ref="category/java/bestpractices.xml/ReplaceVectorWithList" /> -->
|
||||
<rule ref="category/java/bestpractices.xml/SimplifiableTestAssertion"/>
|
||||
<rule ref="category/java/bestpractices.xml/SwitchStmtsShouldHaveDefault"/>
|
||||
<!-- <rule ref="category/java/bestpractices.xml/SystemPrintln" /> -->
|
||||
<!-- <rule ref="category/java/bestpractices.xml/UnusedAssignment"/> -->
|
||||
@@ -48,10 +50,6 @@
|
||||
<rule ref="category/java/bestpractices.xml/UnusedLocalVariable"/>
|
||||
<rule ref="category/java/bestpractices.xml/UnusedPrivateField"/>
|
||||
<rule ref="category/java/bestpractices.xml/UnusedPrivateMethod"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseAssertEqualsInsteadOfAssertTrue"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseAssertNullInsteadOfAssertTrue"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseAssertSameInsteadOfAssertTrue"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseAssertTrueInsteadOfAssertEquals"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseCollectionIsEmpty"/>
|
||||
<rule ref="category/java/bestpractices.xml/UseStandardCharsets" />
|
||||
<!-- <rule ref="category/java/bestpractices.xml/UseTryWithResources" /> -->
|
||||
@@ -104,6 +102,7 @@
|
||||
<!-- <rule ref="category/java/codestyle.xml/PrematureDeclaration" /> -->
|
||||
<!-- <rule ref="category/java/codestyle.xml/TooManyStaticImports" /> -->
|
||||
<rule ref="category/java/codestyle.xml/UnnecessaryAnnotationValueElement"/>
|
||||
<!-- <rule ref="category/java/codestyle.xml/UnnecessaryBoxing" /> -->
|
||||
<!-- <rule ref="category/java/codestyle.xml/UnnecessaryCast" /> -->
|
||||
<rule ref="category/java/codestyle.xml/UnnecessaryConstructor"/>
|
||||
<rule ref="category/java/codestyle.xml/UnnecessaryFullyQualifiedName"/>
|
||||
@@ -153,7 +152,6 @@
|
||||
<!-- <rule ref="category/java/design.xml/NPathComplexity" /> -->
|
||||
<!-- <rule ref="category/java/design.xml/SignatureDeclareThrowsException" /> -->
|
||||
<rule ref="category/java/design.xml/SimplifiedTernary"/>
|
||||
<!-- <rule ref="category/java/design.xml/SimplifyBooleanAssertion" /> -->
|
||||
<!-- <rule ref="category/java/design.xml/SimplifyBooleanExpressions" /> -->
|
||||
<rule ref="category/java/design.xml/SimplifyBooleanReturns"/>
|
||||
<rule ref="category/java/design.xml/SimplifyConditional"/>
|
||||
@@ -299,23 +297,17 @@
|
||||
<!-- <rule ref="category/java/performance.xml/AvoidInstantiatingObjectsInLoops" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/AvoidUsingShortType"/> -->
|
||||
<rule ref="category/java/performance.xml/BigIntegerInstantiation"/>
|
||||
<rule ref="category/java/performance.xml/BooleanInstantiation"/>
|
||||
<!-- <rule ref="category/java/performance.xml/ByteInstantiation" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/ConsecutiveAppendsShouldReuse" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/ConsecutiveLiteralAppends" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/InefficientEmptyStringCheck" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/InefficientStringBuffering" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/InsufficientStringBufferDeclaration" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/IntegerInstantiation" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/LongInstantiation" /> -->
|
||||
<rule ref="category/java/performance.xml/OptimizableToArrayCall"/>
|
||||
<!--<rule ref="category/java/performance.xml/RedundantFieldInitializer"/>-->
|
||||
<!-- <rule ref="category/java/performance.xml/SimplifyStartsWith" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/ShortInstantiation" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/StringInstantiation" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/StringToString" /> -->
|
||||
<!--<rule ref="category/java/performance.xml/TooFewBranchesForASwitchStatement"/>-->
|
||||
<!-- <rule ref="category/java/performance.xml/UnnecessaryWrapperObjectCreation" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/UseArrayListInsteadOfVector" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/UseArraysAsList" /> -->
|
||||
<!-- <rule ref="category/java/performance.xml/UseIndexOfChar" /> -->
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.java;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.Language;
|
||||
import net.sourceforge.pmd.lang.LanguageRegistry;
|
||||
import net.sourceforge.pmd.lang.LanguageVersion;
|
||||
|
||||
public class JavaLanguageModuleTest {
|
||||
private Language javaLanguage = LanguageRegistry.getLanguage(JavaLanguageModule.NAME);
|
||||
|
||||
@Test
|
||||
public void java9IsSmallerThanJava10() {
|
||||
LanguageVersion java9 = javaLanguage.getVersion("9");
|
||||
LanguageVersion java10 = javaLanguage.getVersion("10");
|
||||
|
||||
Assert.assertTrue("java9 should be smaller than java10", java9.compareTo(java10) < 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void previewVersionShouldBeGreaterThanNonPreview() {
|
||||
LanguageVersion java16 = javaLanguage.getVersion("16");
|
||||
LanguageVersion java16p = javaLanguage.getVersion("16-preview");
|
||||
|
||||
Assert.assertTrue("java16-preview should be greater than java16", java16p.compareTo(java16) > 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareToVersion() {
|
||||
LanguageVersion java9 = javaLanguage.getVersion("9");
|
||||
Assert.assertTrue("java9 should be smaller than java10", java9.compareToVersion("10") < 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allVersions() {
|
||||
List<LanguageVersion> versions = javaLanguage.getVersions();
|
||||
for (int i = 1; i < versions.size(); i++) {
|
||||
LanguageVersion previous = versions.get(i - 1);
|
||||
LanguageVersion current = versions.get(i);
|
||||
Assert.assertTrue("Version " + previous + " should be smaller than " + current,
|
||||
previous.compareTo(current) < 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
+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.bestpractices;
|
||||
|
||||
import net.sourceforge.pmd.testframework.PmdRuleTst;
|
||||
|
||||
@org.junit.Ignore("Rule has not been updated yet")
|
||||
public class PrimitiveWrapperInstantiationTest extends PmdRuleTst {
|
||||
// no additional unit tests
|
||||
}
|
||||
+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.bestpractices;
|
||||
|
||||
import net.sourceforge.pmd.testframework.PmdRuleTst;
|
||||
|
||||
@org.junit.Ignore("Rule has not been updated yet")
|
||||
public class SimplifiableTestAssertionTest extends PmdRuleTst {
|
||||
// no additional unit tests
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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 UnnecessaryBoxingTest extends PmdRuleTst {
|
||||
// no additional unit tests
|
||||
}
|
||||
+385
File diff suppressed because it is too large.
Load diff
+662
File diff suppressed because it is too large.
Load diff
+115
@@ -219,6 +219,7 @@ public class TryWithResources {
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>[java] UseTryWithResources - false negative for explicit close #2882</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
@@ -276,4 +277,118 @@ public class TryWithResources {
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<code-fragment id="issue-3235"><![CDATA[
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
||||
class Scratch {
|
||||
public static int count(AutoCloseable iterator) {
|
||||
int count = 0;
|
||||
try {
|
||||
count++;
|
||||
} finally {
|
||||
iterator.close();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
class Holder implements AutoCloseable {
|
||||
private Reader reader;
|
||||
public void close() throws IOException {
|
||||
try {
|
||||
someOtherActivity();
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
private void someOtherActivity() throws IOException {
|
||||
// do stuff
|
||||
}
|
||||
}
|
||||
]]></code-fragment>
|
||||
|
||||
<test-code>
|
||||
<description>[java] UseTryWithResources false positive when closeable is provided as a method argument or class field #3235 before java 9</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code-ref id="issue-3235"/>
|
||||
<source-type>java 1.8</source-type>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>[java] UseTryWithResources false positive when closeable is provided as a method argument or class field #3235</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>7,19</expected-linenumbers>
|
||||
<code-ref id="issue-3235"/>
|
||||
</test-code>
|
||||
|
||||
<code-fragment id="issue-3235-with-local-var"><![CDATA[
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
||||
class Scratch {
|
||||
public static int count() {
|
||||
AutoCloseable iterator;
|
||||
int count = 0;
|
||||
try {
|
||||
count++;
|
||||
} finally {
|
||||
iterator.close();
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
class Holder implements AutoCloseable {
|
||||
public void close() throws IOException {
|
||||
Reader reader;
|
||||
try {
|
||||
someOtherActivity();
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
private void someOtherActivity() throws IOException {
|
||||
// do stuff
|
||||
}
|
||||
}
|
||||
]]></code-fragment>
|
||||
|
||||
<test-code>
|
||||
<description>[java] UseTryWithResources with local var and before java 9 #3235</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>8,20</expected-linenumbers>
|
||||
<code-ref id="issue-3235-with-local-var"/>
|
||||
<source-type>java 1.8</source-type>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>[java] UseTryWithResources with local var and latest java #3235</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<expected-linenumbers>8,20</expected-linenumbers>
|
||||
<code-ref id="issue-3235-with-local-var"/>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>NPE when determining closeTarget</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<expected-linenumbers>6</expected-linenumbers>
|
||||
<code><![CDATA[
|
||||
import java.io.InputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class UseTryWithResources {
|
||||
public void read(InputStream is, boolean close) throws IOException {
|
||||
try {
|
||||
is.read();
|
||||
} finally {
|
||||
if (close) {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
</test-data>
|
||||
Loaded 30 of 32 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user