net.sourceforge.pmd.lang.apex.rule.performance.AbstractAvoidNodeInLoopsRule Maven / Gradle / Ivy
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.apex.rule.performance;
import net.sourceforge.pmd.lang.apex.ast.ASTBlockStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTDoLoopStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTForEachStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTForLoopStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTReturnStatement;
import net.sourceforge.pmd.lang.apex.ast.ASTWhileLoopStatement;
import net.sourceforge.pmd.lang.apex.ast.ApexNode;
import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule;
import net.sourceforge.pmd.lang.ast.Node;
/**
* Base class for any rules that detect operations contained within a loop that could be more efficiently executed by
* refactoring the code into a batched execution.
*/
abstract class AbstractAvoidNodeInLoopsRule extends AbstractApexRule {
/**
* Adds a violation if any parent of {@code node} is a looping construct that would cause {@code node} to execute
* multiple times and {@code node} is not part of a return statement that short circuits the loop.
*/
protected Object checkForViolation(ApexNode node, Object data) {
if (insideLoop(node) && parentNotReturn(node)) {
asCtx(data).addViolation(node);
}
return data;
}
/**
* @return false if {@code node} is a direct child of a return statement. Children of return statements should not
* result in a violation because the return short circuits the loop's execution.
*/
private boolean parentNotReturn(ApexNode node) {
return !(node.getParent() instanceof ASTReturnStatement);
}
/**
* @return true if any parent of {@code node} is a construct that would cause {@code node} to execute multiple
* times.
*/
private boolean insideLoop(Node node) {
Node n = node.getParent();
while (n != null) {
if (n instanceof ASTBlockStatement && n.getParent() instanceof ASTForEachStatement) {
// only consider the block of the for-each statement, not the iterator
return true;
}
if (n instanceof ASTDoLoopStatement || n instanceof ASTWhileLoopStatement
|| n instanceof ASTForLoopStatement) {
return true;
}
n = n.getParent();
}
return false;
}
}