1
2
3
4 package net.sourceforge.pmd.lang.java.rule.design;
5
6 import java.util.Arrays;
7 import java.util.HashMap;
8 import java.util.List;
9 import java.util.Map;
10
11 import net.sourceforge.pmd.lang.ast.Node;
12 import net.sourceforge.pmd.lang.java.ast.ASTClassOrInterfaceType;
13 import net.sourceforge.pmd.lang.java.ast.ASTMethodDeclaration;
14 import net.sourceforge.pmd.lang.java.ast.ASTName;
15 import net.sourceforge.pmd.lang.java.ast.ASTPrimaryPrefix;
16 import net.sourceforge.pmd.lang.java.ast.ASTPrimarySuffix;
17 import net.sourceforge.pmd.lang.java.ast.ASTResultType;
18 import net.sourceforge.pmd.lang.java.rule.AbstractInefficientZeroCheck;
19 import net.sourceforge.pmd.lang.java.symboltable.ClassScope;
20 import net.sourceforge.pmd.lang.java.symboltable.JavaNameOccurrence;
21 import net.sourceforge.pmd.lang.java.symboltable.MethodNameDeclaration;
22 import net.sourceforge.pmd.lang.symboltable.NameOccurrence;
23 import net.sourceforge.pmd.util.CollectionUtil;
24
25
26
27
28
29
30
31 public class UseCollectionIsEmptyRule extends AbstractInefficientZeroCheck {
32
33 public boolean appliesToClassName(String name){
34 return CollectionUtil.isCollectionType(name, true);
35 }
36
37
38
39
40
41
42
43
44 public boolean isTargetMethod(JavaNameOccurrence occ) {
45 if (occ.getNameForWhichThisIsAQualifier() != null) {
46 if (occ.getLocation().getImage().endsWith(".size")) {
47 return true;
48 }
49 }
50 return false;
51 }
52
53 @Override
54 public Map<String, List<String>> getComparisonTargets() {
55 Map<String, List<String>> rules = new HashMap<String, List<String>>();
56 rules.put("<", Arrays.asList("0", "1"));
57 rules.put(">", Arrays.asList("0"));
58 rules.put("==", Arrays.asList("0"));
59 rules.put("!=", Arrays.asList("0"));
60 rules.put(">=", Arrays.asList("0", "1"));
61 rules.put("<=", Arrays.asList("0", "1"));
62 return rules;
63 }
64
65 @Override
66 public Object visit(ASTPrimarySuffix node, Object data) {
67 if (node.getImage() != null && node.getImage().endsWith("size")) {
68
69 ASTClassOrInterfaceType type = getTypeOfPrimaryPrefix(node);
70 if (type == null) {
71 type = getTypeOfMethodCall(node);
72 }
73
74 if (type != null && CollectionUtil.isCollectionType(type.getType(), true)) {
75 Node expr = node.jjtGetParent().jjtGetParent();
76 checkNodeAndReport(data, node, expr);
77 }
78 }
79 return data;
80 }
81
82 private ASTClassOrInterfaceType getTypeOfMethodCall(ASTPrimarySuffix node) {
83 ASTClassOrInterfaceType type = null;
84 ASTName methodName = node.jjtGetParent()
85 .getFirstChildOfType(ASTPrimaryPrefix.class)
86 .getFirstChildOfType(ASTName.class);
87 if (methodName != null) {
88 ClassScope classScope = node.getScope().getEnclosingScope(ClassScope.class);
89 Map<MethodNameDeclaration, List<NameOccurrence>> methods = classScope.getMethodDeclarations();
90 for (Map.Entry<MethodNameDeclaration, List<NameOccurrence>> e : methods.entrySet()) {
91 if (e.getKey().getName().equals(methodName.getImage())) {
92 type = e.getKey().getNode()
93 .getFirstParentOfType(ASTMethodDeclaration.class)
94 .getFirstChildOfType(ASTResultType.class)
95 .getFirstDescendantOfType(ASTClassOrInterfaceType.class);
96 break;
97 }
98 }
99 }
100 return type;
101 }
102
103 private ASTClassOrInterfaceType getTypeOfPrimaryPrefix(ASTPrimarySuffix node) {
104 return node.jjtGetParent()
105 .getFirstChildOfType(ASTPrimaryPrefix.class)
106 .getFirstDescendantOfType(ASTClassOrInterfaceType.class);
107 }
108 }