/** * 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.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.ASTSoqlExpression; import net.sourceforge.pmd.lang.apex.ast.ASTWhileLoopStatement; import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule; import net.sourceforge.pmd.lang.ast.Node; public class AvoidSoqlInLoopsRule extends AbstractApexRule { public AvoidSoqlInLoopsRule() { setProperty(CODECLIMATE_CATEGORIES, new String[] { "Performance" }); // Note: Often more complicated as just moving the SOQL a few lines. // Involves Maps... setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 150); setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false); } @Override public Object visit(ASTSoqlExpression node, Object data) { if (insideLoop(node) && parentNotReturn(node) && parentNotForEach(node)) { addViolation(data, node); } return data; } private boolean parentNotReturn(ASTSoqlExpression node) { return !(node.jjtGetParent() instanceof ASTReturnStatement); } private boolean parentNotForEach(ASTSoqlExpression node) { return !(node.jjtGetParent() instanceof ASTForEachStatement); } private boolean insideLoop(ASTSoqlExpression node) { Node n = node.jjtGetParent(); while (n != null) { if (n instanceof ASTDoLoopStatement || n instanceof ASTWhileLoopStatement || n instanceof ASTForLoopStatement || n instanceof ASTForEachStatement) { return true; } n = n.jjtGetParent(); } return false; } }