1
2
3
4 package net.sourceforge.pmd.lang.java.typeresolution.rules;
5
6 import java.util.Arrays;
7 import java.util.List;
8
9 import net.sourceforge.pmd.lang.java.ast.ASTBlock;
10 import net.sourceforge.pmd.lang.java.ast.ASTBlockStatement;
11 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceDeclaration;
12 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
13 import net.sourceforge.pmd.lang.java.ast.ASTExtendsList;
14 import net.sourceforge.pmd.lang.java.ast.ASTFormalParameters;
15 import net.sourceforge.pmd.lang.java.ast.ASTImplementsList;
16 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
17 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclarator;
18 import net.sourceforge.pmd.lang.java.rule.AbstractJavaRule;
19
20
21
22
23
24
25
26
27
28
29 public class CloneMethodMustImplementCloneable extends AbstractJavaRule {
30
31 @Override
32 public Object visit(ASTClassOrInterfaceDeclaration node, Object data) {
33 ASTImplementsList impl = node.getFirstChildOfType(ASTImplementsList.class);
34 if (impl != null && impl.jjtGetParent().equals(node)) {
35 for (int ix = 0; ix < impl.jjtGetNumChildren(); ix++) {
36 ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) impl.jjtGetChild(ix);
37 if (type.getType() == null) {
38 if ("Cloneable".equals(type.getImage())) {
39 return data;
40 }
41 } else if (type.getType().equals(Cloneable.class)) {
42 return data;
43 } else {
44 List implementors = Arrays.asList(type.getType().getInterfaces());
45 if (implementors.contains(Cloneable.class)) {
46 return data;
47 }
48 }
49 }
50 }
51 if (node.jjtGetNumChildren() != 0 && node.jjtGetChild(0) instanceof ASTExtendsList) {
52 ASTClassOrInterfaceType type = (ASTClassOrInterfaceType) node.jjtGetChild(0).jjtGetChild(0);
53 Class clazz = type.getType();
54 if (clazz != null && clazz.equals(Cloneable.class)) {
55 return data;
56 }
57 while (clazz != null && !Object.class.equals(clazz)) {
58 if (Arrays.asList(clazz.getInterfaces()).contains(Cloneable.class)) {
59 return data;
60 }
61 clazz = clazz.getSuperclass();
62 }
63 }
64
65 return super.visit(node, data);
66 }
67
68 @Override
69 public Object visit(ASTMethodDeclaration node, Object data) {
70 ASTClassOrInterfaceDeclaration classOrInterface = node
71 .getFirstParentOfType(ASTClassOrInterfaceDeclaration.class);
72 if (classOrInterface != null &&
73 (node.isFinal() || classOrInterface.isFinal())) {
74 if (node.findDescendantsOfType(ASTBlock.class).size() == 1) {
75 List<ASTBlockStatement> blocks = node.findDescendantsOfType(ASTBlockStatement.class);
76 if (blocks.size() == 1) {
77 ASTBlockStatement block = blocks.get(0);
78 ASTClassOrInterfaceType type = block.getFirstDescendantOfType(ASTClassOrInterfaceType.class);
79 if (type != null && type.getType() != null && type.getNthParent(9).equals(node)
80 && type.getType().equals(CloneNotSupportedException.class)) {
81 return data;
82 } else if (type != null && type.getType() == null
83 && "CloneNotSupportedException".equals(type.getImage())) {
84 return data;
85 }
86 }
87 }
88 }
89 return super.visit(node, data);
90 }
91
92 @Override
93 public Object visit(ASTMethodDeclarator node, Object data) {
94 if (!"clone".equals(node.getImage())) {
95 return data;
96 }
97 int countParams = ((ASTFormalParameters) node.jjtGetChild(0)).jjtGetNumChildren();
98 if (countParams != 0) {
99 return data;
100 }
101 addViolation(data, node);
102 return data;
103 }
104 }