Merge branch 'master' into close-resource-io

This commit is contained in:
Andreas Dangel
2019-06-29 12:30:18 +02:00
23 changed files with 526 additions and 97 deletions

View File

@ -398,6 +398,46 @@ public class Foo {
</example>
</rule>
<rule name="DoubleBraceInitialization"
language="java"
since="6.16.0"
message="Double-brace initialization should be avoided"
class="net.sourceforge.pmd.lang.rule.XPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_bestpractices.html#doublebraceinitialization">
<description>
Double brace initialisation is a pattern to initialise eg collections concisely. But it implicitly
generates a new .class file, and the object holds a strong reference to the enclosing object. For those
reasons, it is preferable to initialize the object normally, even though it's verbose.
This rule counts any anonymous class which only has a single initializer as an instance of double-brace
initialization. There is currently no way to find out whether a method called in the initializer is not
accessible from outside the anonymous class, and those legit cases should be suppressed for the time being.
</description>
<priority>3</priority>
<properties>
<property name="version" value="2.0"/>
<property name="xpath">
<value>
<![CDATA[
//AllocationExpression/ClassOrInterfaceBody[count(*)=1]/*/Initializer[@Static=false()]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
// this is double-brace initialization
return new ArrayList<String>(){{addAll("a","b","c");}};
// the better way is to not create an anonymous class:
List<String> a=new ArrayList<>();
a.addAll("a","b","c");
return a;
]]>
</example>
</rule>
<rule name="ForLoopCanBeForeach"
language="java"
since="6.0.0"

View File

@ -2526,10 +2526,11 @@ confusing.
</description>
<priority>3</priority>
<properties>
<property name="version" value="2.0" />
<property name="xpath">
<value>
<![CDATA[
//Initializer[@Static='false']
//Initializer[@Static=false()][not(ancestor::*[3][self::AllocationExpression or self::EnumConstant])]
]]>
</value>
</property>

View File

@ -17,6 +17,7 @@
<rule ref="category/java/bestpractices.xml/CheckResultSet"/>
<rule ref="category/java/bestpractices.xml/ConstantsInInterface"/>
<rule ref="category/java/bestpractices.xml/DefaultLabelNotLastInSwitchStmt"/>
<rule ref="category/java/bestpractices.xml/DoubleBraceInitialization"/>
<rule ref="category/java/bestpractices.xml/ForLoopCanBeForeach"/>
<!-- <rule ref="category/java/bestpractices.xml/ForLoopVariableCount" /> -->
<rule ref="category/java/bestpractices.xml/GuardLogStatement"/>

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 DoubleBraceInitializationTest extends PmdRuleTst {
// no additional unit tests
}

View File

@ -0,0 +1,97 @@
<?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>Pos in return</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>4</expected-linenumbers>
<code><![CDATA[
class Foo {
List<String> bar() {
return new ArrayList<String>(){{addAll("a","b","c");}};
}
}
]]></code>
</test-code>
<test-code>
<description>Neg, override</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
class Foo {
List<String> bar() {
return new ArrayList<String>(){
{addAll("a","b","c");}
void add(String x) {
throw new UnsupportedOperationException();
}
};
}
}
]]></code>
</test-code>
<test-code>
<description>Neg, new field</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
class Foo {
List<String> bar() {
return new ArrayList<String>(){
{addAll("a","b","c");}
int field;
};
}
}
]]></code>
</test-code>
<test-code>
<description>Neg, enum constant</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
enum Foo {
A {
// neg in enum cons
{addAll("a","b","c");}
};
}
]]></code>
</test-code>
<test-code>
<description>Neg, regular class</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
class Foo {
// neg in regular class
{addAll("a","b","c");}
}
]]></code>
</test-code>
</test-data>

View File

@ -1,28 +1,101 @@
<?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-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><![CDATA[
bad
]]></description>
<description>bad</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Foo {
{}
}
]]></code>
]]></code>
</test-code>
<test-code>
<description><![CDATA[
static initializers are OK
]]></description>
<description>static initializers are OK</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
static {}
}
]]></code>
]]></code>
</test-code>
<test-code>
<description>Allowed in anonymous classes</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
public Animation getStatusTransition() {
return new Transition() {
{
setCycleDuration(Duration.millis(1200));
}
@Override
protected void interpolate(double frac) {
// magic
}
};
}
}
]]></code>
</test-code>
<test-code>
<description>Flag in local class</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>3</expected-linenumbers>
<code><![CDATA[
public class Foo {
static {
class Local {{}}
}
}
]]></code>
</test-code>
<test-code>
<description>Allowed in enum constant</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>7</expected-linenumbers>
<code><![CDATA[
public enum Foo {
A {
{ setCycleDuration(Duration.millis(1200)); }
};
{ setCycleDuration(Duration.millis(1200)); }
}
]]></code>
</test-code>
<test-code>
<description>Flag in nested local class</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>7</expected-linenumbers>
<code><![CDATA[
public class Foo {
public Animation getStatusTransition() {
return new Transition() {
{
setCycleDuration(Duration.millis(1200));
class ImInAnon {{}} // should be flagged
}
@Override
protected void interpolate(double frac) {
// magic
}
};
}
}
]]></code>
</test-code>
</test-data>