1 package net.sourceforge.pmd.rules;
2
3 import net.sourceforge.pmd.AbstractRule;
4 import net.sourceforge.pmd.ast.ASTAdditiveExpression;
5 import net.sourceforge.pmd.ast.ASTLiteral;
6 import net.sourceforge.pmd.ast.ASTPrimaryExpression;
7 import net.sourceforge.pmd.ast.ASTVariableDeclaratorId;
8 import net.sourceforge.pmd.ast.Node;
9 import net.sourceforge.pmd.ast.SimpleNode;
10 import net.sourceforge.pmd.symboltable.NameOccurrence;
11
12 import java.util.List;
13
14 /**
15 * Detects and flags the occurrences of specific method calls against an instance of
16 * a designated class. I.e. String.indexOf. The goal is to be able to suggest more
17 * efficient/modern ways of implementing the same function.
18 *
19 * Concrete subclasses are expected to provide the name of the target class and an
20 * array of method names that we are looking for. We then pass judgment on any literal
21 * arguments we find in the subclass as well.
22 *
23 * @author Brian Remedios
24 * @version $Revision: 6422 $
25 */
26 public abstract class AbstractPoorMethodCall extends AbstractRule {
27
28
29 /**
30 * The name of the type the method will be invoked against.
31 * @return String
32 */
33 protected abstract String targetTypename();
34
35 /**
36 * Return the names of all the methods we are scanning for, no brackets or
37 * argument types.
38 *
39 * @return String[]
40 */
41 protected abstract String[] methodNames();
42
43 /**
44 * Returns whether the node being sent to the method is OK or not. Return
45 * true if you want to record the method call as a violation.
46 *
47 * @param arg the node to inspect
48 * @return boolean
49 */
50 protected abstract boolean isViolationArgument(Node arg);
51
52 /**
53 * Returns whether the name occurrence is one of the method calls
54 * we are interested in.
55 *
56 * @param occurrence NameOccurrence
57 * @return boolean
58 */
59 private boolean isNotedMethod(NameOccurrence occurrence) {
60
61 if (occurrence == null) return false;
62
63 String methodCall = occurrence.getImage();
64 String[] methodNames = methodNames();
65
66 for (int i=0; i<methodNames.length; i++) {
67 if (methodCall.indexOf(methodNames[i]) != -1) return true;
68 }
69 return false;
70 }
71
72 /**
73 * Method visit.
74 * @param node ASTVariableDeclaratorId
75 * @param data Object
76 * @return Object
77 * @see net.sourceforge.pmd.ast.JavaParserVisitor#visit(ASTVariableDeclaratorId, Object)
78 */
79 public Object visit(ASTVariableDeclaratorId node, Object data) {
80
81 if (!node.getNameDeclaration().getTypeImage().equals(targetTypename())) {
82 return data;
83 }
84
85 for (NameOccurrence occ: node.getUsages()) {
86 if (isNotedMethod(occ.getNameForWhichThisIsAQualifier())) {
87 SimpleNode parent = (SimpleNode)occ.getLocation().jjtGetParent().jjtGetParent();
88 if (parent instanceof ASTPrimaryExpression) {
89
90 List additives = parent.findChildrenOfType(ASTAdditiveExpression.class);
91 if (!additives.isEmpty()) {
92 return data;
93 }
94 List literals = parent.findChildrenOfType(ASTLiteral.class);
95 for (int l=0; l<literals.size(); l++) {
96 ASTLiteral literal = (ASTLiteral)literals.get(l);
97 if (isViolationArgument(literal)) {
98 addViolation(data, occ.getLocation());
99 }
100 }
101 }
102 }
103 }
104 return data;
105 }
106 }
107