<?xml version="1.0"?>

<ruleset name="Clone Implementation"
    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 http://pmd.sourceforge.net/ruleset_2_0_0.xsd">
  <description>
The Clone Implementation ruleset contains a collection of rules that find questionable usages of the clone() method.
  </description>

    <rule name="ProperCloneImplementation"
   		language="java"
    		since="1.4"
         message="Object clone() should be implemented with super.clone()"
         class="net.sourceforge.pmd.lang.rule.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/rules/java/clone.html#ProperCloneImplementation">
     <description>
Object clone() should be implemented with super.clone().
     </description>
     <priority>2</priority>
     <properties>
         <property name="xpath">
             <value>
                 <![CDATA[
//MethodDeclarator
[@Image = 'clone']
[count(FormalParameters/*) = 0]
[count(../Block//*[
    (self::AllocationExpression) and
    (./ClassOrInterfaceType/@Image = ancestor::
ClassOrInterfaceDeclaration[1]/@Image)
  ])> 0
]
                ]]>
             </value>
         </property>
     </properties>
     <example>
 <![CDATA[
class Foo{
    public Object clone(){
        return new Foo(); // This is bad
    }
}
]]>
     </example>
     </rule>

    <rule name="CloneThrowsCloneNotSupportedException"
   		language="java"
    		since="1.9"
         message="clone() method should throw CloneNotSupportedException"
         class="net.sourceforge.pmd.lang.rule.XPathRule"
         externalInfoUrl="${pmd.website.baseurl}/rules/java/clone.html#CloneThrowsCloneNotSupportedException">
         <description>
The method clone() should throw a CloneNotSupportedException.
         </description>
         <priority>3</priority>
         <properties>
             <property name="xpath">
                 <value>
                     <![CDATA[
//MethodDeclaration
[
MethodDeclarator/@Image = 'clone'
and count(MethodDeclarator/FormalParameters/*) = 0
and count(NameList/Name[contains
(@Image,'CloneNotSupportedException')]) = 0
]
[
../../../../ClassOrInterfaceDeclaration[@Final = 'false']
]
                     ]]>
                 </value>
             </property>
         </properties>
         <example>
             <![CDATA[
 public class MyClass implements Cloneable{
     public Object clone() { // will cause an error
          MyClass clone = (MyClass)super.clone();
          return clone;
     }
 }
    ]]>
         </example>
     </rule>

    <rule name="CloneMethodMustImplementCloneable"
   		language="java"
    	  since="1.9"
        message="clone() method should be implemented only if implementing Cloneable interface"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
          externalInfoUrl="${pmd.website.baseurl}/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.
        </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 {
 public Object clone() throws CloneNotSupportedException {
  return foo;
 }
}
   ]]>
        </example>
    </rule>

    <rule name="CloneMethodReturnTypeMustMatchClassName"
        language="java"
        minimumLanguageVersion="1.5"
        since="5.4.0"
        message="The return type of the clone() method must be the class name when implements Cloneable"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/clone.html#CloneMethodReturnTypeMustMatchClassName">
        <description>
If a class implements cloneable the return type of the method clone() must be the class name. That way, the caller
of the clone method doesn't need to cast the returned clone to the correct type.

Note: This is only possible with Java 1.5 or higher.
        </description>
        <priority>3</priority>
        <properties>
            <property name="xpath">
                <value>
                    <![CDATA[
//MethodDeclaration
[
MethodDeclarator/@Image = 'clone'
and MethodDeclarator/FormalParameters/@ParameterCount = 0
and not (ResultType//ClassOrInterfaceType/@Image = ancestor::ClassOrInterfaceDeclaration[1]/@Image)
]
                    ]]>
                </value>
            </property>
        </properties>
        <example>
            <![CDATA[
public class Foo implements Cloneable {
    @Override
    protected Object clone() { // Violation, Object must be Foo
    }
}

public class Foo implements Cloneable {
    @Override
    public Foo clone() { //Ok
    }
}
            ]]>
        </example>
    </rule>

    <rule name="CloneMethodMustBePublic"
        language="java"
        since="5.4.0"
        message="clone() method must be public if the class implements Cloneable"
        class="net.sourceforge.pmd.lang.rule.XPathRule"
        externalInfoUrl="${pmd.website.baseurl}/rules/java/clone.html#CloneMethodMustBePublic">
        <description>
The java Manual says "By convention, classes that implement this interface should override
Object.clone (which is protected) with a public method."
        </description>
        <priority>3</priority>
        <properties>
            <property name="xpath">
                <value>
                    <![CDATA[
//MethodDeclaration[@Public='false']
[
MethodDeclarator/@Image = 'clone'
and MethodDeclarator/FormalParameters/@ParameterCount = 0
]
                    ]]>
                </value>
            </property>
        </properties>
        <example>
            <![CDATA[
public class Foo implements Cloneable {
    @Override
    protected Object clone() throws CloneNotSupportedException { // Violation, must be public
    }
}

public class Foo implements Cloneable {
    @Override
    protected Foo clone() { // Violation, must be public
    }
}

public class Foo implements Cloneable {
    @Override
    public Object clone() // Ok
}
]]></example>
    </rule>
</ruleset>