Merge branch 'master' into deprecate-DuplicateImports-ImportsFromSamePackage

This commit is contained in:
Clément Fournier
2021-04-12 17:12:29 +02:00
12 changed files with 453 additions and 13 deletions

View File

@ -5,6 +5,7 @@
package net.sourceforge.pmd.lang.java.ast;
import java.util.Iterator;
import java.util.List;
import net.sourceforge.pmd.Rule;
import net.sourceforge.pmd.annotation.InternalApi;
@ -45,6 +46,11 @@ public class ASTLocalVariableDeclaration extends AbstractJavaAccessNode implemen
return visitor.visit(this, data);
}
@Override
public List<ASTAnnotation> getDeclaredAnnotations() {
return findChildrenOfType(ASTAnnotation.class);
}
@Override
public boolean hasSuppressWarningsAnnotationFor(Rule rule) {
for (int i = 0; i < getNumChildren(); i++) {

View File

@ -45,6 +45,7 @@ import net.sourceforge.pmd.lang.java.ast.ASTStatementExpression;
import net.sourceforge.pmd.lang.java.ast.ASTTryStatement;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclarator;
import net.sourceforge.pmd.lang.java.ast.ASTVariableDeclaratorId;
import net.sourceforge.pmd.lang.java.ast.Annotatable;
import net.sourceforge.pmd.lang.java.ast.JavaNode;
import net.sourceforge.pmd.lang.java.ast.TypeNode;
import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
@ -187,6 +188,10 @@ public class CloseResourceRule extends AbstractJavaRule {
List<ASTVariableDeclarator> vars = method.findDescendantsOfType(ASTVariableDeclarator.class);
Map<ASTVariableDeclarator, TypeNode> resVars = new HashMap<>();
for (ASTVariableDeclarator var : vars) {
if (var.getParent() instanceof Annotatable
&& ((Annotatable) var.getParent()).isAnnotationPresent("lombok.Cleanup")) {
continue; // auto cleaned up
}
TypeNode varType = getTypeOfVariable(var);
if (varType != null && isResourceTypeOrSubtype(varType)) {
resVars.put(var, wrappedResourceTypeOrReturn(var, varType));

View File

@ -1832,6 +1832,51 @@ public class Foo {
</example>
</rule>
<rule name="UseStandardCharsets"
language="java"
since="6.34.0"
minimumLanguageVersion="1.7"
message="Please use StandardCharsets constants"
class="net.sourceforge.pmd.lang.rule.XPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#usestandardcharsets">
<description>
Starting with Java 7, StandardCharsets provides constants for common Charset objects, such as UTF-8.
Using the constants is less error prone, and can provide a small performance advantage compared to `Charset.forName(...)`
since no scan across the internal `Charset` caches is needed.
</description>
<priority>3</priority>
<properties>
<property name="version" value="2.0"/>
<property name="xpath">
<value>
<![CDATA[
//PrimaryExpression[PrimaryPrefix/Name/@Image = 'Charset.forName']
/PrimarySuffix/Arguments/ArgumentList/Expression/PrimaryExpression/PrimaryPrefix
/Literal[@Image = ('"US-ASCII"', '"ISO-8859-1"', '"UTF-8"', '"UTF-16BE"', '"UTF-16LE"', '"UTF-16"')]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
public class UseStandardCharsets {
public void run() {
// looking up the charset dynamically
try (OutputStreamWriter osw = new OutputStreamWriter(out, Charset.forName("UTF-8"))) {
osw.write("test");
}
// best to use StandardCharsets
try (OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
osw.write("test");
}
}
}
]]>
</example>
</rule>
<rule name="UseTryWithResources"
language="java"
minimumLanguageVersion="1.7"

View File

@ -53,6 +53,7 @@
<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" /> -->
<!-- <rule ref="category/java/bestpractices.xml/UseVarargs" /> -->
<!-- <rule ref="category/java/bestpractices.xml/WhileLoopWithLiteralBoolean" /> -->

View File

@ -0,0 +1,11 @@
/**
* 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;
public class UseStandardCharsetsTest extends PmdRuleTst {
// no additional unit tests
}

View File

@ -0,0 +1,23 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.errorprone.closeresource;
import java.io.Closeable;
import java.io.IOException;
/**
* Helper class for #2757
*/
public class FakeContext implements Closeable, AutoCloseable {
public <T> T getBean(Class<T> klass) {
return null;
}
@Override
public void close() throws IOException {
}
}

View File

@ -0,0 +1,158 @@
<?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>fail, US-ASCII</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>7</expected-linenumbers>
<code><![CDATA[
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
public class Foo {
public static void charset() {
// looking up the charset dynamically
try (OutputStreamWriter osw = new OutputStreamWriter(out, Charset.forName("US-ASCII"))) {
osw.write("test");
}
}
}
]]></code>
</test-code>
<test-code>
<description>fail, ISO-8859-1</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>7</expected-linenumbers>
<code><![CDATA[
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
public class Foo {
public static void charset() {
// looking up the charset dynamically
try (OutputStreamWriter osw = new OutputStreamWriter(out, Charset.forName("ISO-8859-1"))) {
osw.write("test");
}
}
}
]]></code>
</test-code>
<test-code>
<description>fail, UTF-8</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>7</expected-linenumbers>
<code><![CDATA[
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
public class Foo {
public static void charset() {
// looking up the charset dynamically
try (OutputStreamWriter osw = new OutputStreamWriter(out, Charset.forName("UTF-8"))) {
osw.write("test");
}
}
}
]]></code>
</test-code>
<test-code>
<description>fail, UTF-16BE</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>7</expected-linenumbers>
<code><![CDATA[
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
public class Foo {
public static void charset() {
// looking up the charset dynamically
try (OutputStreamWriter osw = new OutputStreamWriter(out, Charset.forName("UTF-16BE"))) {
osw.write("test");
}
}
}
]]></code>
</test-code>
<test-code>
<description>fail, UTF-16LE</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>7</expected-linenumbers>
<code><![CDATA[
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
public class Foo {
public static void charset() {
// looking up the charset dynamically
try (OutputStreamWriter osw = new OutputStreamWriter(out, Charset.forName("UTF-16LE"))) {
osw.write("test");
}
}
}
]]></code>
</test-code>
<test-code>
<description>fail, UTF-16</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>7</expected-linenumbers>
<code><![CDATA[
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
public class Foo {
public static void charset() {
// looking up the charset dynamically
try (OutputStreamWriter osw = new OutputStreamWriter(out, Charset.forName("UTF-16"))) {
osw.write("test");
}
}
}
]]></code>
</test-code>
<test-code>
<description>pass, ISO-8859-2, no constant for it</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
public class Foo {
public static void charset() {
// looking up the charset dynamically
try (OutputStreamWriter osw = new OutputStreamWriter(out, Charset.forName("ISO-8859-2"))) {
osw.write("test");
}
}
}
]]></code>
</test-code>
<test-code>
<description>pass, UTF-8 from StandardCharsets</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
public class Foo {
public static void charset() {
// looking up the charset dynamically
try (OutputStreamWriter osw = new OutputStreamWriter(out, StandardCharsets.UTF_8)) {
osw.write("test");
}
}
}
]]></code>
</test-code>
</test-data>

View File

@ -1659,4 +1659,25 @@ public class FalsePositive {
}
]]></code>
</test-code>
<test-code>
<description>#2757 support @lombok.Cleanup annotation</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
package net.sourceforge.pmd.lang.java.rule.errorprone.closeresource;
import lombok.Cleanup;
import lombok.val;
public class Mwe2757 {
private static SomeClass getCreator() {
@Cleanup val context = new FakeContext(); // FakeContext is is the package
return context.getBean(SomeClass.class);
}
public Mwe2757() {
}
static class SomeClass {}
}
]]></code>
</test-code>
</test-data>