Merge branch 'master' into pmd/7.0.x
This commit is contained in:
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@ -6,6 +6,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
continue-on-error: ${{ matrix.experimental }}
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]')"
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ ubuntu-latest , windows-latest , macos-latest ]
|
||||
|
@ -2,7 +2,7 @@ repository: pmd/pmd
|
||||
|
||||
pmd:
|
||||
version: 7.0.0-SNAPSHOT
|
||||
previous_version: 6.28.0
|
||||
previous_version: 6.29.0
|
||||
date: ??-?????-2020
|
||||
release_type: major
|
||||
|
||||
|
@ -246,6 +246,10 @@ the breaking API changes will be performed in 7.0.0.
|
||||
an API is tagged as `@Deprecated` or not in the latest minor release. During the development of 7.0.0,
|
||||
we may decide to remove some APIs that were not tagged as deprecated, though we'll try to avoid it." %}
|
||||
|
||||
#### 6.29.0
|
||||
|
||||
No changes.
|
||||
|
||||
#### 6.28.0
|
||||
|
||||
##### Deprecated API
|
||||
|
@ -19,27 +19,11 @@ This is a {{ site.pmd.release_type }} release.
|
||||
|
||||
### New and noteworthy
|
||||
|
||||
#### Renamed Rules
|
||||
|
||||
* The Java rule [`DoNotCallSystemExit`](https://pmd.github.io/latest/pmd_rules_java_errorprone.html#donotcallsystemexit) has been renamed to
|
||||
{% rule "java/errorprone/DoNotTerminateVM" %}, since it checks for all the following calls:
|
||||
`System.exit(int)`, `Runtime.exit(int)`, `Runtime.halt(int)`. All these calls terminate
|
||||
the Java VM, which is bad, if the VM runs an application server which many independent applications.
|
||||
|
||||
### Fixed Issues
|
||||
|
||||
* java-errorprone
|
||||
* [#2157](https://github.com/pmd/pmd/issues/2157): \[java] Improve DoNotCallSystemExit: permit call in main(), flag System.halt
|
||||
|
||||
### API Changes
|
||||
|
||||
### External Contributions
|
||||
|
||||
* [#2803](https://github.com/pmd/pmd/pull/2803): \[java] Improve DoNotCallSystemExit (Fixes #2157) - [Vitaly Polonetsky](https://github.com/mvitaly)
|
||||
* [#2809](https://github.com/pmd/pmd/pull/2809): \[java] Move test config from file to test class - [Stefan Birkner](https://github.com/stefanbirkner)
|
||||
* [#2810](https://github.com/pmd/pmd/pull/2810): \[core] Move method "renderTempFile" to XMLRendererTest - [Stefan Birkner](https://github.com/stefanbirkner)
|
||||
* [#2813](https://github.com/pmd/pmd/pull/2813): \[core] Use JUnit's TemporaryFolder rule - [Stefan Birkner](https://github.com/stefanbirkner)
|
||||
* [#2829](https://github.com/pmd/pmd/pull/2829): \[doc] Small correction in pmd\_report\_formats.md - [Gustavo Krieger](https://github.com/gustavopcassol)
|
||||
|
||||
{% endtocmaker %}
|
||||
|
||||
|
@ -5,6 +5,88 @@ permalink: pmd_release_notes_old.html
|
||||
|
||||
Previous versions of PMD can be downloaded here: https://github.com/pmd/pmd/releases
|
||||
|
||||
## 24-October-2020 - 6.29.0
|
||||
|
||||
The PMD team is pleased to announce PMD 6.29.0.
|
||||
|
||||
This is a minor release.
|
||||
|
||||
### Table Of Contents
|
||||
|
||||
* [New and noteworthy](#new-and-noteworthy)
|
||||
* [Updated Apex Support](#updated-apex-support)
|
||||
* [New Rules](#new-rules)
|
||||
* [Renamed Rules](#renamed-rules)
|
||||
* [Deprecated Rules](#deprecated-rules)
|
||||
* [Fixed Issues](#fixed-issues)
|
||||
* [External Contributions](#external-contributions)
|
||||
* [Stats](#stats)
|
||||
|
||||
### New and noteworthy
|
||||
|
||||
#### Updated Apex Support
|
||||
|
||||
* The Apex language support has been bumped to version 50 (Winter '21). All new language features are now properly
|
||||
parsed and processed. Especially the [Safe Navigation Operator](https://releasenotes.docs.salesforce.com/en-us/winter21/release-notes/rn_apex_SafeNavigationOperator.htm) is now supported.
|
||||
See also [Salesforce Winter '21 Release Notes](https://releasenotes.docs.salesforce.com/en-us/winter21/release-notes/rn_apex.htm)
|
||||
|
||||
#### New Rules
|
||||
|
||||
* The new Apex rule [`OperationWithLimitsInLoop`](https://pmd.github.io/pmd-6.29.0/pmd_rules_apex_performance.html#operationwithlimitsinloop) (`apex-performance`)
|
||||
finds operations in loops that may hit governor limits such as DML operations, SOQL
|
||||
queries and more. The rule replaces the three rules "AvoidDmlStatementsInLoops", "AvoidSoqlInLoops",
|
||||
and "AvoidSoslInLoops".
|
||||
|
||||
#### Renamed Rules
|
||||
|
||||
* The Java rule [`DoNotCallSystemExit`](https://pmd.github.io/pmd-6.29.0/pmd_rules_java_errorprone.html#donotcallsystemexit) has been renamed to
|
||||
[`DoNotTerminateVM`](https://pmd.github.io/pmd-6.29.0/pmd_rules_java_errorprone.html#donotterminatevm), since it checks for all the following calls:
|
||||
`System.exit(int)`, `Runtime.exit(int)`, `Runtime.halt(int)`. All these calls terminate
|
||||
the Java VM, which is bad, if the VM runs an application server which many independent applications.
|
||||
|
||||
#### Deprecated Rules
|
||||
|
||||
* The Apex rules [`AvoidDmlStatementsInLoops`](https://pmd.github.io/pmd-6.29.0/pmd_rules_apex_performance.html#avoiddmlstatementsinloops),
|
||||
[`AvoidSoqlInLoops`](https://pmd.github.io/pmd-6.29.0/pmd_rules_apex_performance.html#avoidsoqlinloops) and [`AvoidSoslInLoops`](https://pmd.github.io/pmd-6.29.0/pmd_rules_apex_performance.html#avoidsoslinloops)
|
||||
(`apex-performance`) are deprecated in favour of the new rule
|
||||
[`OperationWithLimitsInLoop`](https://pmd.github.io/pmd-6.29.0/pmd_rules_apex_performance.html#operationwithlimitsinloop). The deprecated rules will be removed
|
||||
with PMD 7.0.0.
|
||||
|
||||
### Fixed Issues
|
||||
|
||||
* apex
|
||||
* [#2839](https://github.com/pmd/pmd/issues/2839): \[apex] Apex classes with safe navigation operator from Winter 21 (50.0) are skipped
|
||||
* apex-performance
|
||||
* [#1713](https://github.com/pmd/pmd/issues/1713): \[apex] Mark Database DML statements in For Loop
|
||||
* core
|
||||
* [#2831](https://github.com/pmd/pmd/pull/2831): \[core] Fix XMLRenderer newlines when running under IBM Java
|
||||
* java-errorprone
|
||||
* [#2157](https://github.com/pmd/pmd/issues/2157): \[java] Improve DoNotCallSystemExit: permit call in main(), flag System.halt
|
||||
* [#2764](https://github.com/pmd/pmd/issues/2764): \[java] CloseResourceRule does not recognize multiple assignment done to resource
|
||||
* miscellaneous
|
||||
* [#2823](https://github.com/pmd/pmd/issues/2823): \[doc] Renamed/Moved rules are missing in documentation
|
||||
* vf (Salesforce VisualForce)
|
||||
* [#2765](https://github.com/pmd/pmd/issues/2765): \[vf] Attributes with dot cause a VfParseException
|
||||
|
||||
### External Contributions
|
||||
|
||||
* [#2803](https://github.com/pmd/pmd/pull/2803): \[java] Improve DoNotCallSystemExit (Fixes #2157) - [Vitaly Polonetsky](https://github.com/mvitaly)
|
||||
* [#2809](https://github.com/pmd/pmd/pull/2809): \[java] Move test config from file to test class - [Stefan Birkner](https://github.com/stefanbirkner)
|
||||
* [#2810](https://github.com/pmd/pmd/pull/2810): \[core] Move method "renderTempFile" to XMLRendererTest - [Stefan Birkner](https://github.com/stefanbirkner)
|
||||
* [#2811](https://github.com/pmd/pmd/pull/2811): \[java] CloseResource - Fix #2764: False-negative when re-assigning variable - [Andi Pabst](https://github.com/andipabst)
|
||||
* [#2813](https://github.com/pmd/pmd/pull/2813): \[core] Use JUnit's TemporaryFolder rule - [Stefan Birkner](https://github.com/stefanbirkner)
|
||||
* [#2816](https://github.com/pmd/pmd/pull/2816): \[apex] Detect 'Database' method invocations inside loops - [Jeff Bartolotta](https://github.com/jbartolotta-sfdc)
|
||||
* [#2829](https://github.com/pmd/pmd/pull/2829): \[doc] Small correction in pmd\_report\_formats.md - [Gustavo Krieger](https://github.com/gustavopcassol)
|
||||
* [#2834](https://github.com/pmd/pmd/pull/2834): \[vf] Allow attributes with dot in Visualforce - [rmohan20](https://github.com/rmohan20)
|
||||
* [#2842](https://github.com/pmd/pmd/pull/2842): \[core] Bump antlr4 from 4.7 to 4.7.2 - [Adrien Lecharpentier](https://github.com/alecharp)
|
||||
* [#2865](https://github.com/pmd/pmd/pull/2865): \[java] (doc) Update ExcessiveImports example code for clarity - [Gustavo Krieger](https://github.com/gustavopcassol)
|
||||
* [#2866](https://github.com/pmd/pmd/pull/2866): \[java] (doc) Fix example for CouplingBetweenObjects - [Gustavo Krieger](https://github.com/gustavopcassol)
|
||||
|
||||
### Stats
|
||||
* 50 commits
|
||||
* 23 closed tickets & PRs
|
||||
* Days since last release: 27
|
||||
|
||||
## 26-September-2020 - 6.28.0
|
||||
|
||||
The PMD team is pleased to announce PMD 6.28.0.
|
||||
|
@ -13,7 +13,7 @@
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<apex.jorje.version>2020-06-04-ba31c0</apex.jorje.version>
|
||||
<apex.jorje.version>2020-09-10-5a5192</apex.jorje.version>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
|
Binary file not shown.
@ -4,6 +4,6 @@
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>apex</groupId>
|
||||
<artifactId>apex-jorje-lsp-minimized</artifactId>
|
||||
<version>2020-06-04-ba31c0</version>
|
||||
<version>2020-09-10-5a5192</version>
|
||||
<description>POM was created from install:install-file</description>
|
||||
</project>
|
@ -3,10 +3,10 @@
|
||||
<groupId>apex</groupId>
|
||||
<artifactId>apex-jorje-lsp-minimized</artifactId>
|
||||
<versioning>
|
||||
<release>2020-06-04-ba31c0</release>
|
||||
<release>2020-09-10-5a5192</release>
|
||||
<versions>
|
||||
<version>2020-06-04-ba31c0</version>
|
||||
<version>2020-09-10-5a5192</version>
|
||||
</versions>
|
||||
<lastUpdated>20200724082242</lastUpdated>
|
||||
<lastUpdated>20201022163714</lastUpdated>
|
||||
</versioning>
|
||||
</metadata>
|
||||
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.ast;
|
||||
|
||||
import apex.jorje.semantic.ast.compilation.InvalidDependentCompilation;
|
||||
|
||||
public final class ASTInvalidDependentCompilation extends AbstractApexNode<InvalidDependentCompilation> {
|
||||
|
||||
ASTInvalidDependentCompilation(InvalidDependentCompilation userClass) {
|
||||
super(userClass);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected <P, R> R acceptApexVisitor(ApexVisitor<? super P, ? extends R> visitor, P data) {
|
||||
return visitor.visit(this, data);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getImage() {
|
||||
String apexName = getDefiningType();
|
||||
return apexName.substring(apexName.lastIndexOf('.') + 1);
|
||||
}
|
||||
}
|
@ -52,4 +52,8 @@ public final class ASTReferenceExpression extends AbstractApexNode<ReferenceExpr
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public boolean isSafeNav() {
|
||||
return node.isSafeNav();
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import apex.jorje.data.Location;
|
||||
import apex.jorje.data.Locations;
|
||||
import apex.jorje.semantic.ast.AstNode;
|
||||
import apex.jorje.semantic.exception.UnexpectedCodePathException;
|
||||
import apex.jorje.semantic.symbol.type.TypeInfo;
|
||||
|
||||
abstract class AbstractApexNode<T extends AstNode> extends AbstractNodeWithTextCoordinates<AbstractApexNode<?>, ApexNode<?>> implements ApexNode<T> {
|
||||
|
||||
@ -166,18 +167,28 @@ abstract class AbstractApexNode<T extends AstNode> extends AbstractNodeWithTextC
|
||||
}
|
||||
}
|
||||
|
||||
private TypeInfo getDefiningTypeOrNull() {
|
||||
try {
|
||||
return node.getDefiningType();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDefiningType() {
|
||||
if (node.getDefiningType() != null) {
|
||||
return node.getDefiningType().getApexName();
|
||||
TypeInfo definingType = getDefiningTypeOrNull();
|
||||
if (definingType != null) {
|
||||
return definingType.getApexName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNamespace() {
|
||||
if (node.getDefiningType() != null) {
|
||||
return node.getDefiningType().getNamespace().toString();
|
||||
TypeInfo definingType = getDefiningTypeOrNull();
|
||||
if (definingType != null) {
|
||||
return definingType.getNamespace().toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import apex.jorje.parser.impl.ApexLexer;
|
||||
import apex.jorje.semantic.ast.AstNode;
|
||||
import apex.jorje.semantic.ast.compilation.AnonymousClass;
|
||||
import apex.jorje.semantic.ast.compilation.ConstructorPreamble;
|
||||
import apex.jorje.semantic.ast.compilation.InvalidDependentCompilation;
|
||||
import apex.jorje.semantic.ast.compilation.UserClass;
|
||||
import apex.jorje.semantic.ast.compilation.UserClassMethods;
|
||||
import apex.jorje.semantic.ast.compilation.UserEnum;
|
||||
@ -152,6 +153,8 @@ final class ApexTreeBuilder extends AstVisitor<AdditionalPassScope> {
|
||||
register(DmlUpdateStatement.class, ASTDmlUpdateStatement.class);
|
||||
register(DmlUpsertStatement.class, ASTDmlUpsertStatement.class);
|
||||
register(DoLoopStatement.class, ASTDoLoopStatement.class);
|
||||
register(ElseWhenBlock.class, ASTElseWhenBlock.class);
|
||||
register(EmptyReferenceExpression.class, ASTEmptyReferenceExpression.class);
|
||||
register(Expression.class, ASTExpression.class);
|
||||
register(ExpressionStatement.class, ASTExpressionStatement.class);
|
||||
register(Field.class, ASTField.class);
|
||||
@ -159,12 +162,15 @@ final class ApexTreeBuilder extends AstVisitor<AdditionalPassScope> {
|
||||
register(FieldDeclarationStatements.class, ASTFieldDeclarationStatements.class);
|
||||
register(ForEachStatement.class, ASTForEachStatement.class);
|
||||
register(ForLoopStatement.class, ASTForLoopStatement.class);
|
||||
register(IdentifierCase.class, ASTIdentifierCase.class);
|
||||
register(IfBlockStatement.class, ASTIfBlockStatement.class);
|
||||
register(IfElseBlockStatement.class, ASTIfElseBlockStatement.class);
|
||||
register(IllegalStoreExpression.class, ASTIllegalStoreExpression.class);
|
||||
register(InstanceOfExpression.class, ASTInstanceOfExpression.class);
|
||||
register(InvalidDependentCompilation.class, ASTInvalidDependentCompilation.class);
|
||||
register(JavaMethodCallExpression.class, ASTJavaMethodCallExpression.class);
|
||||
register(JavaVariableExpression.class, ASTJavaVariableExpression.class);
|
||||
register(LiteralCase.class, ASTLiteralCase.class);
|
||||
register(LiteralExpression.class, ASTLiteralExpression.class);
|
||||
register(MapEntryNode.class, ASTMapEntryNode.class);
|
||||
register(Method.class, ASTMethod.class);
|
||||
@ -199,29 +205,25 @@ final class ApexTreeBuilder extends AstVisitor<AdditionalPassScope> {
|
||||
register(StatementExecuted.class, ASTStatementExecuted.class);
|
||||
register(SuperMethodCallExpression.class, ASTSuperMethodCallExpression.class);
|
||||
register(SuperVariableExpression.class, ASTSuperVariableExpression.class);
|
||||
register(SwitchStatement.class, ASTSwitchStatement.class);
|
||||
register(TernaryExpression.class, ASTTernaryExpression.class);
|
||||
register(ThisMethodCallExpression.class, ASTThisMethodCallExpression.class);
|
||||
register(ThisVariableExpression.class, ASTThisVariableExpression.class);
|
||||
register(ThrowStatement.class, ASTThrowStatement.class);
|
||||
register(TriggerVariableExpression.class, ASTTriggerVariableExpression.class);
|
||||
register(TryCatchFinallyBlockStatement.class, ASTTryCatchFinallyBlockStatement.class);
|
||||
register(TypeWhenBlock.class, ASTTypeWhenBlock.class);
|
||||
register(UserClass.class, ASTUserClass.class);
|
||||
register(UserClassMethods.class, ASTUserClassMethods.class);
|
||||
register(UserExceptionMethods.class, ASTUserExceptionMethods.class);
|
||||
register(UserEnum.class, ASTUserEnum.class);
|
||||
register(UserInterface.class, ASTUserInterface.class);
|
||||
register(UserTrigger.class, ASTUserTrigger.class);
|
||||
register(ValueWhenBlock.class, ASTValueWhenBlock.class);
|
||||
register(VariableDeclaration.class, ASTVariableDeclaration.class);
|
||||
register(VariableDeclarationStatements.class, ASTVariableDeclarationStatements.class);
|
||||
register(VariableExpression.class, ASTVariableExpression.class);
|
||||
register(WhileLoopStatement.class, ASTWhileLoopStatement.class);
|
||||
register(SwitchStatement.class, ASTSwitchStatement.class);
|
||||
register(ElseWhenBlock.class, ASTElseWhenBlock.class);
|
||||
register(TypeWhenBlock.class, ASTTypeWhenBlock.class);
|
||||
register(ValueWhenBlock.class, ASTValueWhenBlock.class);
|
||||
register(LiteralCase.class, ASTLiteralCase.class);
|
||||
register(IdentifierCase.class, ASTIdentifierCase.class);
|
||||
register(EmptyReferenceExpression.class, ASTEmptyReferenceExpression.class);
|
||||
}
|
||||
|
||||
private static <T extends AstNode> void register(Class<T> nodeType, Class<? extends AbstractApexNode<T>> nodeAdapterType) {
|
||||
|
@ -168,6 +168,10 @@ public interface ApexVisitor<P, R> extends AstVisitor<P, R> {
|
||||
return visitApexNode(node, data);
|
||||
}
|
||||
|
||||
default R visit(ASTInvalidDependentCompilation node, P data) {
|
||||
return visitApexNode(node, data);
|
||||
}
|
||||
|
||||
default R visit(ASTJavaMethodCallExpression node, P data) {
|
||||
return visitApexNode(node, data);
|
||||
}
|
||||
|
@ -353,4 +353,9 @@ class TestAccessEvaluator implements AccessEvaluator {
|
||||
public boolean hasNamespaceGuardedAccess(Namespace namespace, String arg1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNamespaceGuardNamespace(Namespace arg0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ import net.sourceforge.pmd.lang.apex.ast.ApexNode;
|
||||
@InternalApi
|
||||
public final class Helper {
|
||||
public static final String ANY_METHOD = "*";
|
||||
private static final String DATABASE_CLASS_NAME = "Database";
|
||||
|
||||
private Helper() {
|
||||
throw new AssertionError("Can't instantiate helper classes");
|
||||
@ -165,10 +166,10 @@ public final class Helper {
|
||||
|
||||
public static boolean isSystemLevelClass(ASTUserClass node) {
|
||||
List<String> interfaces = node.getInterfaceNames();
|
||||
return interfaces.stream().anyMatch(Helper::isWhitelisted);
|
||||
return interfaces.stream().anyMatch(Helper::isAllowed);
|
||||
}
|
||||
|
||||
private static boolean isWhitelisted(String identifier) {
|
||||
private static boolean isAllowed(String identifier) {
|
||||
switch (identifier.toLowerCase(Locale.ROOT)) {
|
||||
case "queueable":
|
||||
case "database.batchable":
|
||||
@ -186,4 +187,10 @@ public final class Helper {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if {@code node} is an invocation of a {@code Database} method.
|
||||
*/
|
||||
public static boolean isAnyDatabaseMethodCall(ASTMethodCallExpression node) {
|
||||
return isMethodName(node, DATABASE_CLASS_NAME, ANY_METHOD);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* 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)) {
|
||||
addViolation(data, 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;
|
||||
}
|
||||
}
|
@ -10,74 +10,40 @@ import net.sourceforge.pmd.lang.apex.ast.ASTDmlMergeStatement;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTDmlUndeleteStatement;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpdateStatement;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpsertStatement;
|
||||
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.ASTWhileLoopStatement;
|
||||
import net.sourceforge.pmd.lang.apex.rule.AbstractApexRule;
|
||||
import net.sourceforge.pmd.lang.ast.Node;
|
||||
|
||||
public class AvoidDmlStatementsInLoopsRule extends AbstractApexRule {
|
||||
/**
|
||||
* @deprecated use {@link OperationWithLimitsInLoopRule}
|
||||
*/
|
||||
@Deprecated
|
||||
public class AvoidDmlStatementsInLoopsRule extends AbstractAvoidNodeInLoopsRule {
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDmlDeleteStatement node, Object data) {
|
||||
if (insideLoop(node)) {
|
||||
addViolation(data, node);
|
||||
}
|
||||
return data;
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDmlInsertStatement node, Object data) {
|
||||
if (insideLoop(node)) {
|
||||
addViolation(data, node);
|
||||
}
|
||||
return data;
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDmlMergeStatement node, Object data) {
|
||||
if (insideLoop(node)) {
|
||||
addViolation(data, node);
|
||||
}
|
||||
return data;
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDmlUndeleteStatement node, Object data) {
|
||||
if (insideLoop(node)) {
|
||||
addViolation(data, node);
|
||||
}
|
||||
return data;
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDmlUpdateStatement node, Object data) {
|
||||
if (insideLoop(node)) {
|
||||
addViolation(data, node);
|
||||
}
|
||||
return data;
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDmlUpsertStatement node, Object data) {
|
||||
if (insideLoop(node)) {
|
||||
addViolation(data, node);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private boolean insideLoop(Node node) {
|
||||
Node n = node.getParent();
|
||||
|
||||
while (n != null) {
|
||||
if (n instanceof ASTDoLoopStatement || n instanceof ASTWhileLoopStatement
|
||||
|| n instanceof ASTForLoopStatement || n instanceof ASTForEachStatement) {
|
||||
return true;
|
||||
}
|
||||
n = n.getParent();
|
||||
}
|
||||
|
||||
return false;
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
}
|
||||
|
@ -4,45 +4,16 @@
|
||||
|
||||
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.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 {
|
||||
/**
|
||||
* @deprecated use {@link OperationWithLimitsInLoopRule}
|
||||
*/
|
||||
@Deprecated
|
||||
public class AvoidSoqlInLoopsRule extends AbstractAvoidNodeInLoopsRule {
|
||||
|
||||
@Override
|
||||
public Object visit(ASTSoqlExpression node, Object data) {
|
||||
if (insideLoop(node) && parentNotReturn(node)) {
|
||||
addViolation(data, node);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private boolean parentNotReturn(ASTSoqlExpression node) {
|
||||
return !(node.getParent() instanceof ASTReturnStatement);
|
||||
}
|
||||
|
||||
private boolean insideLoop(ASTSoqlExpression 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;
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
}
|
||||
|
@ -4,44 +4,16 @@
|
||||
|
||||
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 {
|
||||
/**
|
||||
* @deprecated use {@link OperationWithLimitsInLoopRule}
|
||||
*/
|
||||
@Deprecated
|
||||
public class AvoidSoslInLoopsRule extends AbstractAvoidNodeInLoopsRule {
|
||||
|
||||
@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.getParent() instanceof ASTReturnStatement);
|
||||
}
|
||||
|
||||
private boolean parentNotForEach(ASTSoslExpression node) {
|
||||
return !(node.getParent() instanceof ASTForEachStatement);
|
||||
}
|
||||
|
||||
private boolean insideLoop(ASTSoslExpression node) {
|
||||
Node n = node.getParent();
|
||||
|
||||
while (n != null) {
|
||||
if (n instanceof ASTDoLoopStatement || n instanceof ASTWhileLoopStatement
|
||||
|| n instanceof ASTForLoopStatement || n instanceof ASTForEachStatement) {
|
||||
return true;
|
||||
}
|
||||
n = n.getParent();
|
||||
}
|
||||
|
||||
return false;
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,101 @@
|
||||
/**
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.rule.performance;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTDmlDeleteStatement;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTDmlInsertStatement;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTDmlMergeStatement;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTDmlUndeleteStatement;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpdateStatement;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTDmlUpsertStatement;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTMethodCallExpression;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTSoqlExpression;
|
||||
import net.sourceforge.pmd.lang.apex.ast.ASTSoslExpression;
|
||||
import net.sourceforge.pmd.lang.apex.rule.internal.Helper;
|
||||
import net.sourceforge.pmd.lang.rule.RuleTargetSelector;
|
||||
|
||||
/**
|
||||
* Warn users when code that could trigger governor limits is executing within a looping construct.
|
||||
*/
|
||||
public class OperationWithLimitsInLoopRule extends AbstractAvoidNodeInLoopsRule {
|
||||
|
||||
@Override
|
||||
protected @NonNull RuleTargetSelector buildTargetSelector() {
|
||||
return RuleTargetSelector.forTypes(
|
||||
// DML
|
||||
ASTDmlDeleteStatement.class,
|
||||
ASTDmlInsertStatement.class,
|
||||
ASTDmlMergeStatement.class,
|
||||
ASTDmlUndeleteStatement.class,
|
||||
ASTDmlUpdateStatement.class,
|
||||
ASTDmlUpsertStatement.class,
|
||||
// Database methods
|
||||
ASTMethodCallExpression.class,
|
||||
// SOQL
|
||||
ASTSoqlExpression.class,
|
||||
// SOSL
|
||||
ASTSoslExpression.class
|
||||
);
|
||||
}
|
||||
|
||||
// Begin DML Statements
|
||||
@Override
|
||||
public Object visit(ASTDmlDeleteStatement node, Object data) {
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDmlInsertStatement node, Object data) {
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDmlMergeStatement node, Object data) {
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDmlUndeleteStatement node, Object data) {
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDmlUpdateStatement node, Object data) {
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visit(ASTDmlUpsertStatement node, Object data) {
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
// End DML Statements
|
||||
|
||||
// Begin Database method invocations
|
||||
@Override
|
||||
public Object visit(ASTMethodCallExpression node, Object data) {
|
||||
if (Helper.isAnyDatabaseMethodCall(node)) {
|
||||
return checkForViolation(node, data);
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
// End Database method invocations
|
||||
|
||||
// Begin SOQL method invocations
|
||||
@Override
|
||||
public Object visit(ASTSoqlExpression node, Object data) {
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
// End SOQL method invocations
|
||||
|
||||
// Begin SOSL method invocations
|
||||
@Override
|
||||
public Object visit(ASTSoslExpression node, Object data) {
|
||||
return checkForViolation(node, data);
|
||||
}
|
||||
// End SOSL method invocations
|
||||
}
|
@ -103,7 +103,7 @@ public class ApexSharingViolationsRule extends AbstractApexRule {
|
||||
|
||||
@Override
|
||||
public Object visit(ASTMethodCallExpression node, Object data) {
|
||||
if (Helper.isMethodName(node, "Database", Helper.ANY_METHOD)) {
|
||||
if (Helper.isAnyDatabaseMethodCall(node)) {
|
||||
checkForViolation(node, data);
|
||||
}
|
||||
|
||||
|
@ -12,11 +12,15 @@ Rules that flag suboptimal code.
|
||||
<rule name="AvoidDmlStatementsInLoops"
|
||||
language="apex"
|
||||
since="5.5.0"
|
||||
deprecated="true"
|
||||
message="Avoid DML statements inside loops"
|
||||
class="net.sourceforge.pmd.lang.apex.rule.performance.AvoidDmlStatementsInLoopsRule"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_performance.html#avoiddmlstatementsinloops">
|
||||
<description>
|
||||
Avoid DML statements inside loops to avoid hitting the DML governor limit. Instead, try to batch up the data into a list and invoke your DML once on that list of data outside the loop.
|
||||
|
||||
This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced
|
||||
by the more general rule {% rule "apex/performance/OperationWithLimitsInLoop" %}.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<example>
|
||||
@ -37,11 +41,15 @@ public class Something {
|
||||
<rule name="AvoidSoqlInLoops"
|
||||
language="apex"
|
||||
since="5.5.0"
|
||||
deprecated="true"
|
||||
message="Avoid Soql queries inside loops"
|
||||
class="net.sourceforge.pmd.lang.apex.rule.performance.AvoidSoqlInLoopsRule"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_performance.html#avoidsoqlinloops">
|
||||
<description>
|
||||
New objects created within loops should be checked to see if they can created outside them and reused.
|
||||
|
||||
This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced
|
||||
by the more general rule {% rule "apex/performance/OperationWithLimitsInLoop" %}.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<example>
|
||||
@ -60,11 +68,15 @@ public class Something {
|
||||
<rule name="AvoidSoslInLoops"
|
||||
language="apex"
|
||||
since="6.0.0"
|
||||
deprecated="true"
|
||||
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.
|
||||
|
||||
This rule is deprecated and will be removed with PMD 7.0.0. The rule is replaced
|
||||
by the more general rule {% rule "apex/performance/OperationWithLimitsInLoop" %}.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<example>
|
||||
@ -80,4 +92,46 @@ public class Something {
|
||||
</example>
|
||||
</rule>
|
||||
|
||||
<rule name="OperationWithLimitsInLoop"
|
||||
language="apex"
|
||||
since="6.29.0"
|
||||
message="Avoid operations in loops that may hit governor limits"
|
||||
class="net.sourceforge.pmd.lang.apex.rule.performance.OperationWithLimitsInLoopRule"
|
||||
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_apex_performance.html#operationwithlimitsinloop">
|
||||
<description>
|
||||
Database class methods, DML operations, SOQL queries, or SOSL queries within loops can cause governor limit exceptions. Instead, try to batch up the data into a list and invoke the operation once on that list of data outside the loop.
|
||||
</description>
|
||||
<priority>3</priority>
|
||||
<example>
|
||||
<![CDATA[
|
||||
public class Something {
|
||||
public void databaseMethodInsideOfLoop(List<Account> accounts) {
|
||||
for (Account a : accounts) {
|
||||
Database.insert(a);
|
||||
}
|
||||
}
|
||||
|
||||
public void dmlInsideOfLoop() {
|
||||
for (Integer i = 0; i < 151; i++) {
|
||||
Account account;
|
||||
// ...
|
||||
insert account;
|
||||
}
|
||||
}
|
||||
|
||||
public void soqlInsideOfLoop() {
|
||||
for (Integer i = 0; i < 10; i++) {
|
||||
List<Account> accounts = [SELECT Id FROM Account];
|
||||
}
|
||||
}
|
||||
|
||||
public void soslInsideOfLoop() {
|
||||
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>
|
||||
</ruleset>
|
||||
|
@ -66,13 +66,7 @@
|
||||
<!-- <rule ref="category/apex/design.xml/CognitiveComplexity"/> -->
|
||||
|
||||
<!-- PERFORMANCE -->
|
||||
<rule ref="category/apex/performance.xml/AvoidSoqlInLoops" message="Avoid Soql queries inside loops">
|
||||
<priority>3</priority>
|
||||
</rule>
|
||||
<rule ref="category/apex/performance.xml/AvoidSoslInLoops" message="Avoid Sosl queries inside loops">
|
||||
<priority>3</priority>
|
||||
</rule>
|
||||
<rule ref="category/apex/performance.xml/AvoidDmlStatementsInLoops" message="Avoid DML Statements inside loops">
|
||||
<rule ref="category/apex/performance.xml/OperationWithLimitsInLoop" message="Avoid operations in loops that may hit governor limits">
|
||||
<priority>3</priority>
|
||||
</rule>
|
||||
<rule ref="category/apex/errorprone.xml/AvoidDirectAccessTriggerMap" message="Avoid directly accessing Trigger.old and Trigger.new">
|
||||
|
@ -1,6 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ruleset xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Default ruleset for Salesforce.com Apex" xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
<description>Default ruleset for Salesforce.com Apex</description>
|
||||
<ruleset xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Default ruleset used by the CodeClimate Engine for Salesforce.com Apex" xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
|
||||
<description>
|
||||
Default ruleset used by the Code Climate Engine for Salesforce.com Apex
|
||||
|
||||
Note: This ruleset is deprecated. Use "rulesets/apex/quickstart.xml" instead.
|
||||
</description>
|
||||
|
||||
<rule ref="rulesets/apex/quickstart.xml/ExcessiveClassLength" deprecated="true" />
|
||||
<rule ref="rulesets/apex/quickstart.xml/ExcessiveParameterList" deprecated="true" />
|
||||
@ -12,9 +16,9 @@
|
||||
<rule ref="rulesets/apex/quickstart.xml/TooManyFields" deprecated="true" />
|
||||
<rule ref="rulesets/apex/quickstart.xml/AvoidDeeplyNestedIfStmts" deprecated="true" />
|
||||
<rule ref="rulesets/apex/quickstart.xml/CyclomaticComplexity" deprecated="true" />
|
||||
<rule ref="rulesets/apex/quickstart.xml/AvoidSoqlInLoops" deprecated="true" />
|
||||
<rule ref="rulesets/apex/quickstart.xml/AvoidSoslInLoops" deprecated="true" />
|
||||
<rule ref="rulesets/apex/quickstart.xml/AvoidDmlStatementsInLoops" deprecated="true" />
|
||||
<rule ref="category/apex/performance.xml/AvoidSoqlInLoops" deprecated="true" />
|
||||
<rule ref="category/apex/performance.xml/AvoidSoslInLoops" deprecated="true" />
|
||||
<rule ref="category/apex/performance.xml/AvoidDmlStatementsInLoops" deprecated="true" />
|
||||
<rule ref="rulesets/apex/quickstart.xml/AvoidDirectAccessTriggerMap" deprecated="true" />
|
||||
<rule ref="rulesets/apex/quickstart.xml/AvoidLogicInTrigger" deprecated="true" />
|
||||
<rule ref="rulesets/apex/quickstart.xml/AvoidGlobalModifier" deprecated="true" />
|
||||
|
@ -17,13 +17,13 @@ import org.junit.contrib.java.lang.system.SystemErrRule;
|
||||
import net.sourceforge.pmd.RulePriority;
|
||||
import net.sourceforge.pmd.RuleSet;
|
||||
import net.sourceforge.pmd.RuleSetFactory;
|
||||
import net.sourceforge.pmd.util.ResourceLoader;
|
||||
import net.sourceforge.pmd.RulesetsFactoryUtils;
|
||||
|
||||
public class DefaultRulesetTest {
|
||||
@Rule
|
||||
public final SystemErrRule systemErrRule = new SystemErrRule().enableLog().muteForSuccessfulTests();
|
||||
|
||||
private RuleSetFactory factory = new RuleSetFactory(new ResourceLoader(), RulePriority.LOW, true, false);
|
||||
private RuleSetFactory factory = RulesetsFactoryUtils.createFactory(RulePriority.LOW, true, false);
|
||||
|
||||
@Test
|
||||
public void loadDefaultRuleset() throws Exception {
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
|
||||
*/
|
||||
|
||||
|
||||
package net.sourceforge.pmd.lang.apex.ast;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import net.sourceforge.pmd.lang.ast.test.BaseParsingHelper;
|
||||
import net.sourceforge.pmd.lang.ast.test.BaseTreeDumpTest;
|
||||
import net.sourceforge.pmd.lang.ast.test.RelevantAttributePrinter;
|
||||
|
||||
public class ApexTreeDumpTest extends BaseTreeDumpTest {
|
||||
|
||||
public ApexTreeDumpTest() {
|
||||
super(new RelevantAttributePrinter(), ".cls");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseParsingHelper<?, ?> getParser() {
|
||||
return ApexParsingHelper.DEFAULT;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void safeNavigationOperator() throws Exception {
|
||||
doTest("SafeNavigationOperator");
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 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.testframework.PmdRuleTst;
|
||||
|
||||
public class OperationWithLimitsInLoopTest extends PmdRuleTst {
|
||||
// no additional unit tests
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// See https://github.com/pmd/pmd/issues/2839
|
||||
// and https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_SafeNavigationOperator.htm
|
||||
|
||||
public class Foo {
|
||||
Integer x = anObject?.anIntegerField; // The expression is of type Integer because the field is of type Integer
|
||||
|
||||
// New code using the safe navigation operator
|
||||
String profileUrl = user.getProfileUrl()?.toExternalForm();
|
||||
|
||||
public void bar1(Object a) {
|
||||
a?.b; // Evaluates to: a == null ? null : a.b
|
||||
((T)a1?.b1)?.c1();
|
||||
}
|
||||
|
||||
public void bar2(Object[] a, int x) {
|
||||
a[x]?.aMethod().aField; // Evaluates to null if a[x] == null
|
||||
a[x].aMethod()?.aField;
|
||||
}
|
||||
|
||||
public String getName(int accId) {
|
||||
String s = contact.Account?.BillingCity;
|
||||
// New code using the safe navigation operator
|
||||
return [SELECT Name FROM Account WHERE Id = :accId]?.Name;
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
+- ApexFile[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(4, 14, 180, 183)", @Namespace = "", @RealLoc = "true"]
|
||||
+- UserClass[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "Foo", @Location = "(4, 14, 180, 183)", @Namespace = "", @RealLoc = "true", @SuperClassName = "", @TypeKind = "CLASS"]
|
||||
+- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "(4, 14, 180, 183)", @Modifiers = "1", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "true", @RealLoc = "true", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
+- Field[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "x", @Location = "(5, 13, 198, 199)", @Name = "x", @Namespace = "", @RealLoc = "true", @Type = "Integer", @Value = null]
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "(5, 13, 198, 199)", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "true", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
+- Field[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "profileUrl", @Location = "(8, 12, 365, 375)", @Name = "profileUrl", @Namespace = "", @RealLoc = "true", @Type = "String", @Value = null]
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "(8, 12, 365, 375)", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "true", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
+- FieldDeclarationStatements[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(5, 5, 190, 199)", @Namespace = "", @RealLoc = "true", @TypeName = "Integer"]
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "no location", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "false", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| +- FieldDeclaration[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "anIntegerField", @Location = "(5, 13, 198, 199)", @Name = "anIntegerField", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "anIntegerField", @Location = "(5, 27, 212, 226)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| | +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "anObject", @Location = "(5, 17, 202, 210)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- EmptyReferenceExpression[@ApexVersion = "51.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
| +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "x", @Location = "(5, 13, 198, 199)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- EmptyReferenceExpression[@ApexVersion = "51.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
+- FieldDeclarationStatements[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(8, 5, 358, 375)", @Namespace = "", @RealLoc = "true", @TypeName = "String"]
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "no location", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "false", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| +- FieldDeclaration[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "profileUrl", @Location = "(8, 12, 365, 375)", @Name = "profileUrl", @Namespace = "", @RealLoc = "true"]
|
||||
| +- MethodCallExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @FullMethodName = "toExternalForm", @InputParametersSize = "0", @Location = "(8, 47, 400, 414)", @MethodName = "toExternalForm", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SafeNav = "true"]
|
||||
| | +- MethodCallExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @FullMethodName = "user.getProfileUrl", @InputParametersSize = "0", @Location = "(8, 30, 383, 396)", @MethodName = "getProfileUrl", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Image = "user", @Location = "(8, 25, 378, 382)", @Namespace = "", @RealLoc = "true", @ReferenceType = "METHOD", @SafeNav = "false"]
|
||||
| +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "profileUrl", @Location = "(8, 12, 365, 375)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- EmptyReferenceExpression[@ApexVersion = "51.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
+- Method[@ApexVersion = "51.0", @Arity = "1", @CanonicalName = "bar1", @Constructor = "false", @DefiningType = "Foo", @Image = "bar1", @Location = "(10, 17, 435, 439)", @Namespace = "", @RealLoc = "true", @ReturnType = "void", @Synthetic = "false"]
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "(10, 17, 435, 439)", @Modifiers = "1", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "true", @RealLoc = "true", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| +- Parameter[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "a", @Location = "(10, 29, 447, 448)", @Namespace = "", @RealLoc = "true", @Type = "Object"]
|
||||
| | +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "(10, 29, 447, 448)", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "true", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| +- BlockStatement[@ApexVersion = "51.0", @CurlyBrace = "true", @DefiningType = "Foo", @Location = "(10, 32, 450, 538)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ExpressionStatement[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(11, 12, 463, 465)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "b", @Location = "(11, 12, 463, 464)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| | +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "a", @Location = "(11, 9, 460, 461)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- EmptyReferenceExpression[@ApexVersion = "51.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
| +- ExpressionStatement[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(12, 22, 527, 532)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- MethodCallExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @FullMethodName = "c1", @InputParametersSize = "0", @Location = "(12, 22, 527, 529)", @MethodName = "c1", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SafeNav = "true"]
|
||||
| +- CastExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(12, 10, 515, 518)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "b1", @Location = "(12, 17, 522, 524)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "a1", @Location = "(12, 13, 518, 520)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- EmptyReferenceExpression[@ApexVersion = "51.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
+- Method[@ApexVersion = "51.0", @Arity = "2", @CanonicalName = "bar2", @Constructor = "false", @DefiningType = "Foo", @Image = "bar2", @Location = "(15, 17, 556, 560)", @Namespace = "", @RealLoc = "true", @ReturnType = "void", @Synthetic = "false"]
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "(15, 17, 556, 560)", @Modifiers = "1", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "true", @RealLoc = "true", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| +- Parameter[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "a", @Location = "(15, 31, 570, 571)", @Namespace = "", @RealLoc = "true", @Type = "List<Object>"]
|
||||
| | +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "(15, 31, 570, 571)", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "true", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| +- Parameter[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "x", @Location = "(15, 38, 577, 578)", @Namespace = "", @RealLoc = "true", @Type = "int"]
|
||||
| | +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "(15, 38, 577, 578)", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "true", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| +- BlockStatement[@ApexVersion = "51.0", @CurlyBrace = "true", @DefiningType = "Foo", @Location = "(15, 41, 580, 688)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ExpressionStatement[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(16, 25, 606, 613)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "aField", @Location = "(16, 25, 606, 612)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "false"]
|
||||
| | +- MethodCallExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @FullMethodName = "aMethod", @InputParametersSize = "0", @Location = "(16, 15, 596, 603)", @MethodName = "aMethod", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SafeNav = "true"]
|
||||
| | +- ArrayLoadExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(16, 9, 590, 591)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "a", @Location = "(16, 9, 590, 591)", @Namespace = "", @RealLoc = "true"]
|
||||
| | | +- EmptyReferenceExpression[@ApexVersion = "51.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
| | +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "x", @Location = "(16, 11, 592, 593)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- EmptyReferenceExpression[@ApexVersion = "51.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
| +- ExpressionStatement[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(17, 25, 675, 682)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "aField", @Location = "(17, 25, 675, 681)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| +- MethodCallExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @FullMethodName = "aMethod", @InputParametersSize = "0", @Location = "(17, 14, 664, 671)", @MethodName = "aMethod", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "METHOD", @SafeNav = "false"]
|
||||
| +- ArrayLoadExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(17, 9, 659, 660)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "a", @Location = "(17, 9, 659, 660)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- EmptyReferenceExpression[@ApexVersion = "51.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
| +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "x", @Location = "(17, 11, 661, 662)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- EmptyReferenceExpression[@ApexVersion = "51.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
+- Method[@ApexVersion = "51.0", @Arity = "1", @CanonicalName = "getName", @Constructor = "false", @DefiningType = "Foo", @Image = "getName", @Location = "(20, 19, 708, 715)", @Namespace = "", @RealLoc = "true", @ReturnType = "String", @Synthetic = "false"]
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "(20, 19, 708, 715)", @Modifiers = "1", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "true", @RealLoc = "true", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| +- Parameter[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "accId", @Location = "(20, 31, 720, 725)", @Namespace = "", @RealLoc = "true", @Type = "int"]
|
||||
| | +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "(20, 31, 720, 725)", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "true", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| +- BlockStatement[@ApexVersion = "51.0", @CurlyBrace = "true", @DefiningType = "Foo", @Location = "(20, 38, 727, 905)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableDeclarationStatements[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(21, 9, 737, 745)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "no location", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "false", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
| | +- VariableDeclaration[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "s", @Location = "(21, 16, 744, 745)", @Namespace = "", @RealLoc = "true", @Type = "String"]
|
||||
| | +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "BillingCity", @Location = "(21, 37, 765, 776)", @Namespace = "", @RealLoc = "true"]
|
||||
| | | +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| | | +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "Account", @Location = "(21, 28, 756, 763)", @Namespace = "", @RealLoc = "true"]
|
||||
| | | +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Image = "contact", @Location = "(21, 20, 748, 755)", @Namespace = "", @RealLoc = "true", @ReferenceType = "LOAD", @SafeNav = "false"]
|
||||
| | +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "s", @Location = "(21, 16, 744, 745)", @Namespace = "", @RealLoc = "true"]
|
||||
| | +- EmptyReferenceExpression[@ApexVersion = "51.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
| +- ReturnStatement[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(23, 9, 841, 899)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "Name", @Location = "(23, 62, 894, 898)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- ReferenceExpression[@ApexVersion = "51.0", @Context = null, @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReferenceType = "LOAD", @SafeNav = "true"]
|
||||
| +- SoqlExpression[@ApexVersion = "51.0", @CanonicalQuery = "SELECT Name FROM Account WHERE Id = :tmpVar1", @DefiningType = "Foo", @Location = "(23, 16, 848, 892)", @Namespace = "", @Query = "SELECT Name FROM Account WHERE Id = :accId", @RealLoc = "true"]
|
||||
| +- BindExpressions[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "(23, 16, 848, 892)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- VariableExpression[@ApexVersion = "51.0", @DefiningType = "Foo", @Image = "accId", @Location = "(23, 54, 886, 891)", @Namespace = "", @RealLoc = "true"]
|
||||
| +- EmptyReferenceExpression[@ApexVersion = "51.0", @DefiningType = null, @Location = "no location", @Namespace = null, @RealLoc = "false"]
|
||||
+- Method[@ApexVersion = "51.0", @Arity = "0", @CanonicalName = "<clinit>", @Constructor = "false", @DefiningType = "Foo", @Image = "<clinit>", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReturnType = "void", @Synthetic = "true"]
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "false", @InheritedSharing = "false", @Location = "(4, 14, 180, 183)", @Modifiers = "8", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "true", @Static = "true", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
+- Method[@ApexVersion = "51.0", @Arity = "0", @CanonicalName = "clone", @Constructor = "false", @DefiningType = "Foo", @Image = "clone", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReturnType = "Object", @Synthetic = "true"]
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "true", @InheritedSharing = "false", @Location = "no location", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "false", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
+- UserClassMethods[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false"]
|
||||
| +- Method[@ApexVersion = "51.0", @Arity = "0", @CanonicalName = "<init>", @Constructor = "true", @DefiningType = "Foo", @Image = "<init>", @Location = "no location", @Namespace = "", @RealLoc = "false", @ReturnType = "void", @Synthetic = "true"]
|
||||
| +- ModifierNode[@Abstract = "false", @ApexVersion = "51.0", @DefiningType = "Foo", @Final = "false", @Global = "true", @InheritedSharing = "false", @Location = "(4, 14, 180, 183)", @Modifiers = "0", @Namespace = "", @Override = "false", @Private = "false", @Protected = "false", @Public = "false", @RealLoc = "true", @Static = "false", @Test = "false", @TestOrTestSetup = "false", @Transient = "false", @WebService = "false", @WithSharing = "false", @WithoutSharing = "false"]
|
||||
+- BridgeMethodCreator[@ApexVersion = "51.0", @DefiningType = "Foo", @Location = "no location", @Namespace = "", @RealLoc = "false"]
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user