[java] Move rule CloneMethodMustImplementCloneable from typeresolution to clone

Replace existing rule with the typeresolution-based implementation.
This commit is contained in:
Andreas Dangel
2017-10-13 12:27:59 +02:00
parent 2ef082ae19
commit a89d449169
8 changed files with 111 additions and 265 deletions

View File

@ -2,7 +2,7 @@
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.typeresolution.rules;
package net.sourceforge.pmd.lang.java.rule.clone;
import java.util.HashSet;
import java.util.List;
@ -30,7 +30,7 @@ import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
*
* @author acaplan
*/
public class CloneMethodMustImplementCloneable extends AbstractJavaRule {
public class CloneMethodMustImplementCloneableRule extends AbstractJavaRule {
@Override
public Object visit(final ASTClassOrInterfaceDeclaration node, final Object data) {

View File

@ -90,32 +90,16 @@ public class MyClass implements Cloneable{
language="java"
since="1.9"
message="clone() method should be implemented only if implementing Cloneable interface"
class="net.sourceforge.pmd.lang.rule.XPathRule"
class="net.sourceforge.pmd.lang.java.rule.clone.CloneMethodMustImplementCloneableRule"
typeResolution="true"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_clone.html#clonemethodmustimplementcloneable">
<description>
The method clone() should only be implemented if the class implements the Cloneable interface with the exception of a final method that only throws CloneNotSupportedException.
The method clone() should only be implemented if the class implements the Cloneable interface with the exception of
a final method that only throws CloneNotSupportedException.
The rule can also detect, if the class implements or extends a Cloneable class.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>
<![CDATA[
//ClassOrInterfaceDeclaration
[not(./ExtendsList/ClassOrInterfaceType[@Image='Cloneable'])]
[not(./ImplementsList/ClassOrInterfaceType[@Image='Cloneable'])]
/ClassOrInterfaceBody/ClassOrInterfaceBodyDeclaration
[MethodDeclaration
[MethodDeclarator[@Image
= 'clone' and count(FormalParameters/*) = 0]]
[not((../MethodDeclaration[@Final = 'true'] or ancestor::ClassOrInterfaceDeclaration[1][@Final = 'true'])
and Block[count(BlockStatement)=1]
/BlockStatement/Statement/ThrowStatement/Expression
/PrimaryExpression/PrimaryPrefix/AllocationExpression
/ClassOrInterfaceType[@Image = 'CloneNotSupportedException'])]]
]]>
</value>
</property>
</properties>
<example>
<![CDATA[
public class MyClass {

View File

@ -10,29 +10,7 @@ These are rules which resolve java Class files for comparison, as opposed to a S
</description>
<rule ref="java-coupling/LooseCoupling" deprecated="true" />
<rule name="CloneMethodMustImplementCloneable"
since="3.9"
message="clone() method should be implemented only if implementing Cloneable interface"
class="net.sourceforge.pmd.lang.java.typeresolution.rules.CloneMethodMustImplementCloneable"
typeResolution="true"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_typeresolution.html#clonemethodmustimplementcloneable">
<description>
The method clone() should only be implemented if the class implements the Cloneable interface with the exception
of a final method that only throws CloneNotSupportedException. This version uses PMD's type resolution facilities,
and can detect if the class implements or extends a Cloneable class.
</description>
<priority>3</priority>
<example>
<![CDATA[
public class MyClass {
public Object clone() throws CloneNotSupportedException {
return foo;
}
}
]]>
</example>
</rule>
<rule ref="java-clone/CloneMethodMustImplementCloneable" deprecated="true" />
<rule name="UnusedImports"
since="4.0"

View File

@ -1,16 +0,0 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.typeresolution;
import net.sourceforge.pmd.testframework.SimpleAggregatorTst;
public class CloneMethodMustImplementCloneableTest extends SimpleAggregatorTst {
private static final String RULESET = "java-typeresolution";
@Override
public void setUp() {
addRule(RULESET, "CloneMethodMustImplementCloneable");
}
}

View File

@ -62,6 +62,52 @@ public class Bar {
</test-code>
<test-code>
<description><![CDATA[
ok, implements interface in same package which extends Cloneable
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
package net.sourceforge.pmd.lang.java.rule.typeresolution.xml;
public class FooX extends MyInterface {
void clone() {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
ok, implements interface imported implicitly which extends Cloneable
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import net.sourceforge.pmd.lang.java.rule.typeresolution.xml.*;
public class FooX extends MyInterface {
void clone() {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
ok, implements interface which extends Cloneable
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class FooX extends net.sourceforge.pmd.lang.java.rule.typeresolution.xml.MyInterface {
void clone() {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
ok, extends superclass AND implements cloneable
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo extends Bar implements Cloneable{
void clone() {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Bug 1698550, nr 1
]]></description>
<expected-problems>0</expected-problems>
@ -83,6 +129,38 @@ public final class Foo {
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Bug 681, extending a class which implements Clonable.
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class MyAbstractClass implements Cloneable{
}
public class MyClonableClass extends MyAbstractClass{
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Bug 1765613, NullPointerException on enum
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public enum Foo {
BAR("bar");
private String bar;
public String getBar() {
return bar;
}
}
]]></code>
</test-code>
@ -104,4 +182,21 @@ public class UnmodifiableList<T> implements @Readonly List<@Readonly T> {}
}
]]></code>
</test-code>
<test-code>
<description>#1532 [java] CloneMethodMustImplementCloneable: Implemented Interface extends Cloneable</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
interface TestInterface extends Cloneable {
TestInterface clone();
}
class CloneableClass implements TestInterface {
@Override // creates a warning though CloneableClass is actually implementing Cloneable
public CloneableClass clone() {
// clone implementation
}
}
]]></code>
</test-code>
</test-data>

View File

@ -1,202 +0,0 @@
<?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><![CDATA[
ok, implements Cloneable
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo implements Cloneable {
void clone() {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
bad, doesn't implement Cloneable
]]></description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Foo {
void clone() {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
ok, not Object.clone since method has a param
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
void clone(int x) {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
ok, doesn't implement Cloneable but only throw CloneNotSupportedException
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
final Object clone() { throw new CloneNotSupportedException(); }
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
ok, inner class implements Cloneable
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Bar {
class Foo implements Cloneable {
void clone() {}
}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
ok, implements interface in same package which extends Cloneable
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
package net.sourceforge.pmd.lang.java.rule.typeresolution.xml;
public class FooX extends MyInterface {
void clone() {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
ok, implements interface imported implicitly which extends Cloneable
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
import net.sourceforge.pmd.lang.java.rule.typeresolution.xml.*;
public class FooX extends MyInterface {
void clone() {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
ok, implements interface which extends Cloneable
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class FooX extends net.sourceforge.pmd.lang.java.rule.typeresolution.xml.MyInterface {
void clone() {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
ok, extends superclass AND implements cloneable
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo extends Bar implements Cloneable{
void clone() {}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Bug 1698550, nr 1
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
public final Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Bug 1698550, nr 2
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public final class Foo {
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Bug 681, extending a class which implements Clonable.
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class MyAbstractClass implements Cloneable{
}
public class MyClonableClass extends MyAbstractClass{
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
]]></code>
</test-code>
<test-code>
<description><![CDATA[
Bug 1765613, NullPointerException on enum
]]></description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public enum Foo {
BAR("bar");
private String bar;
public String getBar() {
return bar;
}
}
]]></code>
</test-code>
<test-code>
<description>#1534 [java] CloneMethodMustImplementCloneable: ClassCastException with Annotation (java8)</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class UnmodifiableList<T> implements @Readonly List<@Readonly T> {}
]]></code>
</test-code>
<test-code>
<description>#1532 [java] CloneMethodMustImplementCloneable: Implemented Interface extends Cloneable - part 1: interface</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
interface TestInterface extends Cloneable {
TestInterface clone();
}
]]></code>
</test-code>
<test-code>
<description>#1532 [java] CloneMethodMustImplementCloneable: Implemented Interface extends Cloneable</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
interface TestInterface extends Cloneable {
TestInterface clone();
}
class CloneableClass implements TestInterface {
@Override // creates a warning though CloneableClass is actually implementing Cloneable
public CloneableClass clone() {
// clone implementation
}
}
]]></code>
</test-code>
</test-data>