[apex] OperationWithHighCostInLoop - support System.Schema... as well

And improve test cases
This commit is contained in:
Andreas Dangel committed 2023-10-28 12:07:23 +02:00
1 parent 95609960ac
commit c7cc050983
2 files changed
+115 -44

No files matched your search

@@ -4,11 +4,15 @@
package net.sourceforge.pmd.lang.apex.rule.performance;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;
import org.checkerframework.checker.nullness.qual.NonNull;
import net.sourceforge.pmd.lang.apex.ast.ASTMethodCallExpression;
import net.sourceforge.pmd.lang.apex.rule.internal.Helper;
import net.sourceforge.pmd.lang.rule.RuleTargetSelector;
import net.sourceforge.pmd.util.CollectionUtil;
/**
* Warn users when code that could impact performance is executing within a
@@ -16,9 +20,12 @@ import net.sourceforge.pmd.lang.rule.RuleTargetSelector;
*/
public class OperationWithHighCostInLoopRule extends AbstractAvoidNodeInLoopsRule {
private static final String SCHEMA_CLASS_NAME = "Schema";
private static final String[] SCHEMA_PERFORMANCE_METHODS = new String[] { "getGlobalDescribe", "describeSObjects" };
private static final Set<String> SCHEMA_PERFORMANCE_METHODS = CollectionUtil.setOf(
"System.Schema.getGlobalDescribe",
"Schema.getGlobalDescribe",
"System.Schema.describeSObjects",
"Schema.describeSObjects")
.stream().map(s -> s.toLowerCase(Locale.ROOT)).collect(Collectors.toSet());
@Override
protected @NonNull RuleTargetSelector buildTargetSelector() {
@@ -30,22 +37,15 @@ public class OperationWithHighCostInLoopRule extends AbstractAvoidNodeInLoopsRul
// Begin general method invocations
@Override
public Object visit(ASTMethodCallExpression node, Object data) {
if (checkHighCostClassMethods(node, SCHEMA_CLASS_NAME, SCHEMA_PERFORMANCE_METHODS)) {
if (checkHighCostClassMethods(node)) {
return checkForViolation(node, data);
} else {
return data;
}
}
private boolean checkHighCostClassMethods(ASTMethodCallExpression node, String className, String[] methodNames) {
for (String method : methodNames) {
if (Helper.isMethodName(node, className, method)) {
return true;
}
}
return false;
private boolean checkHighCostClassMethods(ASTMethodCallExpression node) {
return SCHEMA_PERFORMANCE_METHODS.contains(node.getFullMethodName().toLowerCase(Locale.ROOT));
}
// End general method invocations
}
@@ -6,43 +6,114 @@
<!-- Begin Schema method invocations -->
<test-code>
<description>High cost performance getGlobalDescribe in loop</description>
<expected-problems>1</expected-problems>
<code>
<![CDATA[
public class Foo {
public void testGetGlobalDescribe() {
Set<String> fieldNameSet = new Set<String> {'Id'};
for (String fieldNameOrDefaultValue : fieldNameOrDefaultValueList) {
if (Schema.getGlobalDescribe().get(objectName).getDescribe().fields.getMap().containsKey(fieldNameOrDefaultValue.trim() )) {
fieldNameSet.add(fieldNameOrDefaultValue);
}
}
}
<description>High cost performance getGlobalDescribe in loop (correct code) #4675</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
public void testGetGlobalDescribe() {
Map<String, Schema.SObjectField> fieldMap = Schema.getGlobalDescribe().get(objectName).getDescribe().fields.getMap();
Set<String> fieldNameSet = new Set<String> {'Id'};
for (String fieldNameOrDefaultValue : fieldNameOrDefaultValueList) {
if (fieldMap.containsKey(fieldNameOrDefaultValue.trim())) {
fieldNameSet.add(fieldNameOrDefaultValue);
}
]]>
</code>
}
}
}
]]></code>
</test-code>
<test-code>
<description>High cost performance describeSObjects in loop</description>
<description>High cost performance getGlobalDescribe in loop #4675</description>
<expected-problems>1</expected-problems>
<code>
<![CDATA[
public class Foo {
public void test1() {
Set<String> fieldNameSet = new Set<String> {'Id'};
for (String fieldNameOrDefaultValue : fieldNameOrDefaultValueList) {
Schema.DescribeSObjectResult dsr = Account.sObjectType.getDescribe();
if (Schema.describeSObjects(new List<String> { sObjectType })[0].fields.getMap().containsKey(fieldNameOrDefaultValue.trim() )) {
fieldNameSet.add(fieldNameOrDefaultValue);
}
}
}
<expected-linenumbers>5</expected-linenumbers>
<code><![CDATA[
public class Foo {
public void testGetGlobalDescribe() {
Set<String> fieldNameSet = new Set<String> {'Id'};
for (String fieldNameOrDefaultValue : fieldNameOrDefaultValueList) {
if (Schema.getGlobalDescribe().get(objectName).getDescribe().fields.getMap().containsKey(fieldNameOrDefaultValue.trim() )) {
fieldNameSet.add(fieldNameOrDefaultValue);
}
]]>
</code>
}
}
}
]]></code>
</test-code>
<test-code>
<description>High cost performance getGlobalDescribe in loop - fully qualified #4675</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>5</expected-linenumbers>
<code><![CDATA[
public class Foo {
public void testGetGlobalDescribe() {
Set<String> fieldNameSet = new Set<String> {'Id'};
for (String fieldNameOrDefaultValue : fieldNameOrDefaultValueList) {
if (System.Schema.getGlobalDescribe().get(objectName).getDescribe().fields.getMap().containsKey(fieldNameOrDefaultValue.trim() )) {
fieldNameSet.add(fieldNameOrDefaultValue);
}
}
}
}
]]></code>
</test-code>
<test-code>
<description>High cost performance describeSObjects in loop (correct code) #4675</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Foo {
public void testDescribeSObjects() {
Map<String, Schema.SObjectField> fieldMap = Schema.describeSObjects(new List<String> { 'Account' })[0].fields.getMap();
Set<String> fieldNameSet = new Set<String> {'Id'};
for (String fieldNameOrDefaultValue : fieldNameOrDefaultValueList) {
if (fieldMap.containsKey(fieldNameOrDefaultValue.trim())) {
fieldNameSet.add(fieldNameOrDefaultValue);
}
}
}
}
]]></code>
</test-code>
<test-code>
<description>High cost performance describeSObjects in loop #4675</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>6</expected-linenumbers>
<code><![CDATA[
public class Foo {
public void testDescribeSObjects() {
String sObjectType = 'Account';
Set<String> fieldNameSet = new Set<String> {'Id'};
for (String fieldNameOrDefaultValue : fieldNameOrDefaultValueList) {
if (Schema.describeSObjects(new List<String> { sObjectType })[0].fields.getMap().containsKey(fieldNameOrDefaultValue.trim())) {
fieldNameSet.add(fieldNameOrDefaultValue);
}
}
}
}
]]></code>
</test-code>
<test-code>
<description>High cost performance describeSObjects in loop - fully qualified #4675</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>6</expected-linenumbers>
<code><![CDATA[
public class Foo {
public void testDescribeSObjects() {
String sObjectType = 'Account';
Set<String> fieldNameSet = new Set<String> {'Id'};
for (String fieldNameOrDefaultValue : fieldNameOrDefaultValueList) {
if (System.Schema.describeSObjects(new List<String> { sObjectType })[0].fields.getMap().containsKey(fieldNameOrDefaultValue.trim())) {
fieldNameSet.add(fieldNameOrDefaultValue);
}
}
}
}
]]></code>
</test-code>
<!-- End Schema method invocations -->
</test-data>