Clover coverage report - PMD - 3.7
Coverage timestamp: Wed May 31 2006 09:25:59 EDT
file stats: LOC: 131   Methods: 7
NCLOC: 88   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
ConfusingTernary.java 20.8% 34.3% 85.7% 34.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  0 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 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 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 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 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 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 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    }