[java] Move rule CloneMethodMustImplementCloneable from typeresolution to clone
Replace existing rule with the typeresolution-based implementation.
This commit is contained in:
@ -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) {
|
@ -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 {
|
||||
|
@ -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"
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
@ -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>
|
||||
|
@ -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>
|
Reference in New Issue
Block a user