Clover Coverage Report - PMD-3.8
Coverage timestamp: Fri May 9 2008 10:49:56 EST
../../../../../img/srcFileCovDistChart4.png 68% of files have more coverage
35   131   24   5
24   88   0.69   7
7     3.43  
1    
 
  ConfusingTernary       Line # 39 35 24 34.8% 0.34848484
 
  (1)
 
1    /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4    package net.sourceforge.pmd.rules.design;
5   
6    import net.sourceforge.pmd.AbstractRule;
7    import net.sourceforge.pmd.ast.ASTConditionalAndExpression;
8    import net.sourceforge.pmd.ast.ASTConditionalExpression;
9    import net.sourceforge.pmd.ast.ASTConditionalOrExpression;
10    import net.sourceforge.pmd.ast.ASTEqualityExpression;
11    import net.sourceforge.pmd.ast.ASTExpression;
12    import net.sourceforge.pmd.ast.ASTIfStatement;
13    import net.sourceforge.pmd.ast.ASTPrimaryExpression;
14    import net.sourceforge.pmd.ast.ASTPrimaryPrefix;
15    import net.sourceforge.pmd.ast.ASTUnaryExpressionNotPlusMinus;
16    import net.sourceforge.pmd.ast.SimpleNode;
17   
18    /**
19    * if (x != y) { diff(); } else { same(); } and<br>
20    * (!x ? diff() : same());.
21    * <p/>
22    * XPath can handle the easy cases, e.g.:<pre>
23    * //IfStatement[
24    * Statement[2]
25    * and Expression[
26    * EqualityExpression[@Image="!="] or
27    * UnaryExpressionNotPlusMinus[@Image="!"]]]
28    * </pre>
29    * but "&amp;&amp;" and "||" are difficult, since we need a match
30    * for <i>all</i> children instead of just one. This can be done by
31    * using a double-negative, e.g.:<pre>
32    * not(*[not(<i>matchme</i>)])
33    * </pre>
34    * Still, XPath is unable to handle arbitrarily nested cases, since it
35    * lacks recursion, e.g.:<pre>
36    * if (((x != !y)) || !(x)) { diff(); } else { same(); }
37    * </pre>
38    */
 
39    public class ConfusingTernary extends AbstractRule {
40   
 
41  0 toggle public Object visit(ASTIfStatement node, Object data) {
42    // look for "if (match) ..; else .."
43  0 if (node.jjtGetNumChildren() == 3) {
44  0 SimpleNode inode = (SimpleNode) node.jjtGetChild(0);
45  0 if (inode instanceof ASTExpression &&
46    inode.jjtGetNumChildren() == 1) {
47  0 SimpleNode jnode = (SimpleNode) inode.jjtGetChild(0);
48  0 if (isMatch(jnode)) {
49  0 addViolation(data, node);
50    }
51    }
52    }
53  0 return super.visit(node, data);
54    }
55   
 
56  2 toggle public Object visit(ASTConditionalExpression node, Object data) {
57    // look for "match ? .. : .."
58  2 if (node.jjtGetNumChildren() > 0) {
59  2 SimpleNode inode = (SimpleNode) node.jjtGetChild(0);
60  2 if (isMatch(inode)) {
61  1 addViolation(data, node);
62    }
63    }
64  2 return super.visit(node, data);
65    }
66   
67    // recursive!
 
68  2 toggle private static boolean isMatch(SimpleNode node) {
69  2 return
70    isUnaryNot(node) ||
71    isNotEquals(node) ||
72    isConditionalWithAllMatches(node) ||
73    isParenthesisAroundMatch(node);
74    }
75   
 
76  2 toggle private static boolean isUnaryNot(SimpleNode node) {
77    // look for "!x"
78  2 return
79    node instanceof ASTUnaryExpressionNotPlusMinus &&
80    "!".equals(node.getImage());
81    }
82   
 
83  2 toggle private static boolean isNotEquals(SimpleNode node) {
84    // look for "x != y"
85  2 return
86    node instanceof ASTEqualityExpression &&
87    "!=".equals(node.getImage());
88    }
89   
 
90  1 toggle private static boolean isConditionalWithAllMatches(SimpleNode node) {
91    // look for "match && match" or "match || match"
92  1 if (!(node instanceof ASTConditionalAndExpression) &&
93    !(node instanceof ASTConditionalOrExpression)) {
94  1 return false;
95    }
96  0 int i_max = node.jjtGetNumChildren();
97  0 if (i_max <= 0) {
98  0 return false;
99    }
100  0 for (int i = 0; i < i_max; i++) {
101  0 SimpleNode inode = (SimpleNode) node.jjtGetChild(i);
102    // recurse!
103  0 if (!isMatch(inode)) {
104  0 return false;
105    }
106    }
107    // all match
108  0 return true;
109    }
110   
 
111  1 toggle private static boolean isParenthesisAroundMatch(SimpleNode node) {
112    // look for "(match)"
113  1 if (!(node instanceof ASTPrimaryExpression) ||
114    (node.jjtGetNumChildren() != 1)) {
115  1 return false;
116    }
117  0 SimpleNode inode = (SimpleNode) node.jjtGetChild(0);
118  0 if (!(inode instanceof ASTPrimaryPrefix) ||
119    (inode.jjtGetNumChildren() != 1)) {
120  0 return false;
121    }
122  0 SimpleNode jnode = (SimpleNode) inode.jjtGetChild(0);
123  0 if (!(jnode instanceof ASTExpression) ||
124    (jnode.jjtGetNumChildren() != 1)) {
125  0 return false;
126    }
127  0 SimpleNode knode = (SimpleNode) jnode.jjtGetChild(0);
128    // recurse!
129  0 return isMatch(knode);
130    }
131    }