[apex] avoid sosl in loops
This commit is contained in:
@ -5,7 +5,7 @@ permalink: pmd_rules_apex_performance.html
|
||||
folder: pmd/rules/apex
|
||||
sidebaractiveurl: /pmd_rules_apex.html
|
||||
editmepath: ../pmd-apex/src/main/resources/rulesets/apex/performance.xml
|
||||
keywords: Performance, AvoidSoqlInLoops, AvoidDmlStatementsInLoops
|
||||
keywords: Performance, AvoidSoqlInLoops, AvoidSoslInLoops, AvoidDmlStatementsInLoops
|
||||
---
|
||||
## AvoidDmlStatementsInLoops
|
||||
|
||||
@ -79,3 +79,37 @@ public class Something {
|
||||
<rule ref="rulesets/apex/performance.xml/AvoidSoqlInLoops" />
|
||||
```
|
||||
|
||||
## AvoidSoslInLoops
|
||||
|
||||
**Since:** PMD 6.0.0
|
||||
|
||||
**Priority:** Medium (3)
|
||||
|
||||
Sosl calls within loops can cause governor limit exceptions.
|
||||
|
||||
**This rule is defined by the following Java class:** [net.sourceforge.pmd.lang.apex.rule.performance.AvoidSoslInLoopsRule](https://github.com/pmd/pmd/blob/master/pmd-apex/src/main/java/net/sourceforge/pmd/lang/apex/rule/performance/AvoidSoslInLoopsRule.java)
|
||||
|
||||
**Example(s):**
|
||||
|
||||
``` java
|
||||
public class Something {
|
||||
public static void main( String as[] ) {
|
||||
for (Integer i = 0; i < 10; i++) {
|
||||
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**This rule has the following properties:**
|
||||
|
||||
|Name|Default Value|Description|
|
||||
|----|-------------|-----------|
|
||||
|cc_categories|[Style]|Code Climate Categories|
|
||||
|cc_remediation_points_multiplier|1|Code Climate Remediation Points multiplier|
|
||||
|cc_block_highlighting|false|Code Climate Block Highlighting|
|
||||
|
||||
**Use this rule by referencing it:**
|
||||
``` xml
|
||||
<rule ref="rulesets/apex/performance.xml/AvoidSoslInLoops" />
|
||||
```
|
||||
|
@ -0,0 +1,55 @@
|
||||
/**
|
||||
* 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.ASTSoslExpression;
|
||||
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 AvoidSoslInLoopsRule extends AbstractApexRule {
|
||||
|
||||
public AvoidSoslInLoopsRule() {
|
||||
setProperty(CODECLIMATE_CATEGORIES, "Performance");
|
||||
// Note: Often more complicated as just moving the SOSL a few lines.
|
||||
// Involves Maps...
|
||||
setProperty(CODECLIMATE_REMEDIATION_MULTIPLIER, 150);
|
||||
setProperty(CODECLIMATE_BLOCK_HIGHLIGHTING, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTSoslExpression node, Object data) {
|
||||
if (insideLoop(node) && parentNotReturn(node) && parentNotForEach(node)) {
|
||||
addViolation(data, node);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private boolean parentNotReturn(ASTSoslExpression node) {
|
||||
return !(node.jjtGetParent() instanceof ASTReturnStatement);
|
||||
}
|
||||
|
||||
private boolean parentNotForEach(ASTSoslExpression node) {
|
||||
return !(node.jjtGetParent() instanceof ASTForEachStatement);
|
||||
}
|
||||
|
||||
private boolean insideLoop(ASTSoslExpression 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;
|
||||
}
|
||||
}
|
@ -30,6 +30,28 @@ public class Something {
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
<rule name="AvoidSoslInLoops"
|
||||
since="6.0.0"
|
||||
message="Avoid Sosl queries inside loops"
|
||||
class="net.sourceforge.pmd.lang.apex.rule.performance.AvoidSoslInLoopsRule"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_performance.html#avoidsoslinloops">
|
||||
<description>
|
||||
Sosl calls within loops can cause governor limit exceptions.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<example>
|
||||
<![CDATA[
|
||||
public class Something {
|
||||
public static void main( String as[] ) {
|
||||
for (Integer i = 0; i < 10; i++) {
|
||||
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];
|
||||
}
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
<rule name="AvoidDmlStatementsInLoops"
|
||||
since="5.5.0"
|
||||
message="Avoid DML statements inside loops"
|
||||
|
@ -104,6 +104,15 @@
|
||||
<property name="cc_block_highlighting" value="false" />
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="rulesets/apex/performance.xml/AvoidSoslInLoops" message="Avoid Sosl queries inside loops">
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
<!-- relevant for Code Climate output only -->
|
||||
<property name="cc_categories" value="Performance" />
|
||||
<property name="cc_remediation_points_multiplier" value="150" />
|
||||
<property name="cc_block_highlighting" value="false" />
|
||||
</properties>
|
||||
</rule>
|
||||
<rule ref="rulesets/apex/performance.xml/AvoidDmlStatementsInLoops" message="Avoid DML Statements inside loops">
|
||||
<priority>3</priority>
|
||||
<properties>
|
||||
|
@ -13,6 +13,7 @@ public class PerformanceRulesTest extends SimpleAggregatorTst {
|
||||
@Override
|
||||
public void setUp() {
|
||||
addRule(RULESET, "AvoidSoqlInLoops");
|
||||
addRule(RULESET, "AvoidSoslInLoops");
|
||||
addRule(RULESET, "AvoidDmlStatementsInLoops");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<test-data
|
||||
xmlns="http://pmd.sourceforge.net/rule-tests"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
|
||||
|
||||
<test-code>
|
||||
<description>Problematic Sosl in for each</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void test1() {
|
||||
for(Integer i : new List<Integer>{1,2}) {
|
||||
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Problematic Sosl in for loop</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void test1() {
|
||||
for(;;) {
|
||||
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Problematic Sosl in While loop</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void test1() {
|
||||
while(true) {
|
||||
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Problematic Sosl in do loop</description>
|
||||
<expected-problems>1</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void test1() {
|
||||
do{
|
||||
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];
|
||||
}while(true) ;
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Multiple problematic Sosl expressions</description>
|
||||
<expected-problems>2</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void test1() {
|
||||
do{
|
||||
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];
|
||||
List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name)];
|
||||
}while(true) ;
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>Return Sosl is even ok in loop</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public List<Account> test1() {
|
||||
for(;;) {
|
||||
return [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
<test-code>
|
||||
<description>#29 SOSL For Loops should not throw an Avoid Sosl queries inside loops issue</description>
|
||||
<expected-problems>0</expected-problems>
|
||||
<code><![CDATA[
|
||||
public class Foo {
|
||||
public void test1() {
|
||||
for(List<sObject> a : [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity]) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
]]></code>
|
||||
</test-code>
|
||||
|
||||
</test-data>
|
Reference in New Issue
Block a user