Clover coverage report - PMD - 3.9
Coverage timestamp: Tue Dec 19 2006 09:38:44 EST
file stats: LOC: 131   Methods: 7
NCLOC: 88   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ConfusingTernary.java 66.7% 88.6% 100% 81.8%
coverage coverage
 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  1 public Object visit(ASTIfStatement node, Object data) {
 42    // look for "if (match) ..; else .."
 43  1 if (node.jjtGetNumChildren() == 3) {
 44  1 SimpleNode inode = (SimpleNode) node.jjtGetChild(0);
 45  1 if (inode instanceof ASTExpression &&
 46    inode.jjtGetNumChildren() == 1) {
 47  1 SimpleNode jnode = (SimpleNode) inode.jjtGetChild(0);
 48  1 if (isMatch(jnode)) {
 49  0 addViolation(data, node);
 50    }
 51    }
 52    }
 53  1 return super.visit(node, data);
 54    }
 55   
 56  5 public Object visit(ASTConditionalExpression node, Object data) {
 57    // look for "match ? .. : .."
 58  5 if (node.jjtGetNumChildren() > 0) {
 59  5 SimpleNode inode = (SimpleNode) node.jjtGetChild(0);
 60  5 if (isMatch(inode)) {
 61  3 addViolation(data, node);
 62    }
 63    }
 64  5 return super.visit(node, data);
 65    }
 66   
 67    // recursive!
 68  8 private static boolean isMatch(SimpleNode node) {
 69  8 return
 70    isUnaryNot(node) ||
 71    isNotEquals(node) ||
 72    isConditionalWithAllMatches(node) ||
 73    isParenthesisAroundMatch(node);
 74    }
 75   
 76  8 private static boolean isUnaryNot(SimpleNode node) {
 77    // look for "!x"
 78  8 return
 79    node instanceof ASTUnaryExpressionNotPlusMinus &&
 80    "!".equals(node.getImage());
 81    }
 82   
 83  8 private static boolean isNotEquals(SimpleNode node) {
 84    // look for "x != y"
 85  8 return
 86    node instanceof ASTEqualityExpression &&
 87    "!=".equals(node.getImage());
 88    }
 89   
 90  5 private static boolean isConditionalWithAllMatches(SimpleNode node) {
 91    // look for "match && match" or "match || match"
 92  5 if (!(node instanceof ASTConditionalAndExpression) &&
 93    !(node instanceof ASTConditionalOrExpression)) {
 94  4 return false;
 95    }
 96  1 int i_max = node.jjtGetNumChildren();
 97  1 if (i_max <= 0) {
 98  0 return false;
 99    }
 100  1 for (int i = 0; i < i_max; i++) {
 101  1 SimpleNode inode = (SimpleNode) node.jjtGetChild(i);
 102    // recurse!
 103  1 if (!isMatch(inode)) {
 104  1 return false;
 105    }
 106    }
 107    // all match
 108  0 return true;
 109    }
 110   
 111  5 private static boolean isParenthesisAroundMatch(SimpleNode node) {
 112    // look for "(match)"
 113  5 if (!(node instanceof ASTPrimaryExpression) ||
 114    (node.jjtGetNumChildren() != 1)) {
 115  2 return false;
 116    }
 117  3 SimpleNode inode = (SimpleNode) node.jjtGetChild(0);
 118  3 if (!(inode instanceof ASTPrimaryPrefix) ||
 119    (inode.jjtGetNumChildren() != 1)) {
 120  0 return false;
 121    }
 122  3 SimpleNode jnode = (SimpleNode) inode.jjtGetChild(0);
 123  3 if (!(jnode instanceof ASTExpression) ||
 124    (jnode.jjtGetNumChildren() != 1)) {
 125  2 return false;
 126    }
 127  1 SimpleNode knode = (SimpleNode) jnode.jjtGetChild(0);
 128    // recurse!
 129  1 return isMatch(knode);
 130    }
 131    }