Clover coverage report - PMD - 3.9 Coverage timestamp: Tue Dec 19 2006 09:38:44 EST FRAMES NO FRAMES |
file stats: | LOC: | 120 |  | Methods: | 3
| NCLOC: | 52 |  | Classes: | 1
Source file | Conditionals | Statements | Methods | TOTAL
AbstractPoorMethodCall.java | 75% | 88% | 100% | 83.3% |

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.SimpleNode;
9 |  | import net.sourceforge.pmd.symboltable.NameOccurrence;
10 |  |
11 |  | import java.util.Iterator;
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 judgement on any literal
21 |  | * arguments we find in the subclass as well.
22 |  | *
23 |  | * @author Brian Remedios
24 |  | * @version $Revision: 1.1 $
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 string argument at the stated position being sent to
45 |  | * the method is ok or not. Return true if you want to record the method call
46 |  | * as a violation, false otherwise.
47 |  | *
48 |  | * @param argIndex int
49 |  | * @param arg String
50 |  | * @return boolean
51 |  | */
52 |  | protected abstract boolean isViolationArgument(int argIndex, String arg);
53 |  |
54 |  | /**
55 |  | * Returns whether the name occurrence is one of the method calls
56 |  | * we are interested in.
57 |  | *
58 |  | * @param occurrence NameOccurrence
59 |  | * @return boolean
60 |  | */
61 | 6 | private boolean isNotedMethod(NameOccurrence occurrence) {
62 |  |
63 | 0 | if (occurrence == null) return false;
64 |  |
65 | 6 | String methodCall = occurrence.getImage();
66 | 6 | String[] methodNames = methodNames();
67 |  |
68 | 7 | for (int i=0; i<methodNames.length; i++) {
69 | 6 | if (methodCall.indexOf(methodNames[i]) != -1) return true;
70 |  | }
71 | 0 | return false;
72 |  | }
73 |  |
74 |  | /**
75 |  | * Returns whether the value argument is a single character string.
76 |  | *
77 |  | * @param value String
78 |  | * @return boolean
79 |  | */
80 | 7 | public static boolean isSingleCharAsString(String value) {
81 | 7 | return value.length() == 3 && value.charAt(0) == '\"';
82 |  | }
83 |  |
84 |  | /**
85 |  | * Method visit.
86 |  | * @param node ASTVariableDeclaratorId
87 |  | * @param data Object
88 |  | * @return Object
89 |  | * @see net.sourceforge.pmd.ast.JavaParserVisitor#visit(ASTVariableDeclaratorId, Object)
90 |  | */
91 | 6 | public Object visit(ASTVariableDeclaratorId node, Object data) {
92 |  |
93 | 6 | if (!node.getNameDeclaration().getTypeImage().equals(targetTypename())) {
94 | 0 | return data;
95 |  | }
96 |  |
97 | 6 | for (Iterator i = node.getUsages().iterator(); i.hasNext();) {
98 | 6 | NameOccurrence occ = (NameOccurrence) i.next();
99 | 6 | if (isNotedMethod(occ.getNameForWhichThisIsAQualifier())) {
100 | 6 | SimpleNode parent = (SimpleNode)occ.getLocation().jjtGetParent().jjtGetParent();
101 | 6 | if (parent instanceof ASTPrimaryExpression) {
102 |  | // bail out if it's something like indexOf("a" + "b")
103 | 6 | List additives = parent.findChildrenOfType(ASTAdditiveExpression.class);
104 | 6 | if (!additives.isEmpty()) {
105 | 1 | return data;
106 |  | }
107 | 5 | List literals = parent.findChildrenOfType(ASTLiteral.class);
108 | 5 | for (int l=0; l<literals.size(); l++) {
109 | 7 | ASTLiteral literal = (ASTLiteral)literals.get(l);
110 | 7 | if (isViolationArgument(l, literal.getImage())) {
111 | 3 | addViolation(data, occ.getLocation());
112 |  | }
113 |  | }
114 |  | }
115 |  | }
116 |  | }
117 | 5 | return data;
118 |  | }
119 |  | }
120 |  |