/** * BSD-style license; for more info see http://pmd.sourceforge.net/license.html */ package net.sourceforge.pmd.lang.java.rule.optimizations; import net.sourceforge.pmd.lang.ast.Node; import net.sourceforge.pmd.lang.java.ast.ASTAllocationExpression; import net.sourceforge.pmd.lang.java.ast.ASTDoStatement; import net.sourceforge.pmd.lang.java.ast.ASTForInit; import net.sourceforge.pmd.lang.java.ast.ASTForStatement; import net.sourceforge.pmd.lang.java.ast.ASTReturnStatement; import net.sourceforge.pmd.lang.java.ast.ASTThrowStatement; import net.sourceforge.pmd.lang.java.ast.ASTWhileStatement; public class AvoidInstantiatingObjectsInLoopsRule extends AbstractOptimizationRule { @Override public Object visit(ASTAllocationExpression node, Object data) { if (insideLoop(node) && fourthParentNotThrow(node) && fourthParentNotReturn(node)) { addViolation(data, node); } return data; } private boolean fourthParentNotThrow(ASTAllocationExpression node) { return !(node.jjtGetParent().jjtGetParent().jjtGetParent().jjtGetParent() instanceof ASTThrowStatement); } private boolean fourthParentNotReturn(ASTAllocationExpression node) { return !(node.jjtGetParent().jjtGetParent().jjtGetParent().jjtGetParent() instanceof ASTReturnStatement); } private boolean insideLoop(ASTAllocationExpression node) { Node n = node.jjtGetParent(); while (n != null) { if (n instanceof ASTDoStatement || n instanceof ASTWhileStatement || n instanceof ASTForStatement) { return true; } else if (n instanceof ASTForInit) { /* * init part is not technically inside the loop. Skip parent * ASTForStatement but continue higher up to detect nested loops */ n = n.jjtGetParent(); } else if (n.jjtGetParent() instanceof ASTForStatement && n.jjtGetParent().jjtGetNumChildren() > 1 && n == n.jjtGetParent().jjtGetChild(1)) { // it is the second child of a ForStatement - which means // we are dealing with a for-each construct // In that case, we can ignore this allocation expression, as // the second child // is the expression, over which to iterate. // Skip this parent but continue higher up // to detect nested loops n = n.jjtGetParent(); } n = n.jjtGetParent(); } return false; } }