Skip to content

Commit fcb5e99

Browse files
authored
Merge branch 'dev' into dependabot/npm_and_yarn/vm2-3.9.19
2 parents 23772e1 + d5f3573 commit fcb5e99

29 files changed

+751
-101
lines changed

sfge/lib/apex-jorje-lsp-sfge.jar

13.4 KB
Binary file not shown.

sfge/src/main/java/com/salesforce/graph/symbols/apex/ApexStringValue.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public final class ApexStringValue extends ApexSimpleValue<ApexStringValue, Stri
6868
static final String METHOD_STARTS_WITH_IGNORE_CASE = "startsWithIgnoreCase";
6969
static final String METHOD_SUB_STRING = "subString";
7070
static final String METHOD_SUB_STRING_AFTER = "subStringAfter";
71+
static final String METHOD_SUB_STRING_AFTER_LAST = "subStringAfterLast";
7172
static final String METHOD_SUB_STRING_BEFORE = "subStringBefore";
7273
static final String METHOD_SUB_STRING_BETWEEN = "subStringBetween";
7374
static final String METHOD_TO_LOWER_CASE = "toLowerCase";
@@ -198,6 +199,7 @@ public TypeableUtil.OrderedTreeSet getTypes() {
198199
METHOD_REMOVE_START_IGNORE_CASE,
199200
StringUtils::removeStartIgnoreCase),
200201
Pair.of(METHOD_SUB_STRING_AFTER, StringUtils::substringAfter),
202+
Pair.of(METHOD_SUB_STRING_AFTER_LAST, StringUtils::substringAfterLast),
201203
Pair.of(METHOD_SUB_STRING_BEFORE, StringUtils::substringBefore),
202204
Pair.of(METHOD_SUB_STRING_BETWEEN, StringUtils::substringBetween));
203205

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,86 @@
11
package com.salesforce.graph.vertex;
22

3+
import com.salesforce.apex.jorje.ASTConstants;
4+
import java.util.List;
35
import java.util.Map;
6+
import org.apache.logging.log4j.LogManager;
7+
import org.apache.logging.log4j.Logger;
48

9+
/** Represents a vertex that can perform DML through Apex. */
510
public abstract class DmlStatementVertex extends BaseSFVertex {
11+
protected static final Logger LOGGER = LogManager.getLogger(DmlStatementVertex.class);
12+
13+
private static final String ACCESS_LEVEL_REFERENCE = "AccessLevel";
14+
15+
private enum AccessLevel {
16+
USER_MODE,
17+
SYSTEM_MODE
18+
}
19+
20+
private final AccessLevel accessLevel;
21+
622
DmlStatementVertex(Map<Object, Object> properties) {
723
super(properties);
24+
accessLevel = calculateAccessLevel(this);
25+
}
26+
27+
private static AccessLevel calculateAccessLevel(DmlStatementVertex vertex) {
28+
// Default to System mode to begin with.
29+
AccessLevel accessLevel = AccessLevel.SYSTEM_MODE;
30+
31+
// If AccessLevel is included in the syntax, it's usually the last child. It shows up in the
32+
// form of a VariableExpression with a ReferenceExpression child.
33+
34+
// spotless:off
35+
// Example:
36+
//<DmlUpdateStatement BeginColumn="9" BeginLine="6" DefiningType="MyClass" DefiningType_CaseSafe="myclass" EndLine="6" EndScopes="[BlockStatement]" FirstChild="false" LastChild="true" childIdx="2">
37+
// <VariableExpression BeginColumn="24" BeginLine="6" DefiningType="MyClass" DefiningType_CaseSafe="myclass" EndLine="6" FirstChild="true" LastChild="false" Name="a" Name_CaseSafe="a" childIdx="0">
38+
// <EmptyReferenceExpression BeginColumn="24" BeginLine="6" DefiningType="MyClass" DefiningType_CaseSafe="myclass" EndLine="6" FirstChild="true" LastChild="true" childIdx="0"/>
39+
// </VariableExpression>
40+
// <VariableExpression BeginColumn="30" BeginLine="-1" DefiningType="MyClass" DefiningType_CaseSafe="myclass" EndLine="-1" FirstChild="false" LastChild="true" Name="USER_MODE" Name_CaseSafe="user_mode" childIdx="1">
41+
// <ReferenceExpression BeginColumn="19" BeginLine="6" DefiningType="MyClass" DefiningType_CaseSafe="myclass" EndLine="6" FirstChild="true" LastChild="true" Name="AccessLevel" Name_CaseSafe="accesslevel" Names="[AccessLevel]" ReferenceType="LOAD" childIdx="0"/>
42+
// </VariableExpression>
43+
//</DmlUpdateStatement>
44+
45+
// spotless:on
46+
47+
final List<VariableExpressionVertex> children =
48+
vertex.getChildren(ASTConstants.NodeType.VARIABLE_EXPRESSION);
49+
if (children.size() > 0) {
50+
final VariableExpressionVertex lastChild = children.get(children.size() - 1);
51+
ReferenceExpressionVertex referenceExpression =
52+
lastChild.getOnlyChildOrNull(ASTConstants.NodeType.REFERENCE_EXPRESSION);
53+
if (referenceExpression != null) {
54+
if (ACCESS_LEVEL_REFERENCE.equalsIgnoreCase(referenceExpression.getName())) {
55+
// lastChild's name holds AccessLevel value
56+
final String accessLevelValueString = lastChild.getName();
57+
final AccessLevel accessLevelValue =
58+
AccessLevel.valueOf(accessLevelValueString);
59+
if (accessLevelValue != null) {
60+
accessLevel = accessLevelValue;
61+
} else {
62+
if (LOGGER.isInfoEnabled()) {
63+
LOGGER.info(
64+
"AccessLevel is unknown. accessLevelValueString="
65+
+ accessLevelValueString);
66+
}
67+
}
68+
} else {
69+
if (LOGGER.isInfoEnabled()) {
70+
LOGGER.info(
71+
"Unknown ReferenceExpression name. referenceExpression="
72+
+ referenceExpression);
73+
}
74+
}
75+
}
76+
}
77+
return accessLevel;
78+
}
79+
80+
/**
81+
* @return true if the DML statement has System access level.
82+
*/
83+
public boolean isSystemMode() {
84+
return accessLevel == AccessLevel.SYSTEM_MODE;
885
}
986
}

sfge/src/main/java/com/salesforce/graph/visitor/DefaultNoOpPathVertexVisitor.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ public boolean visit(CatchBlockStatementVertex vertex, SymbolProvider symbols) {
3636
return DefaultNoOpScopeVisitor.shouldVisitChildren(vertex);
3737
}
3838

39+
@Override
40+
public boolean visit(DoLoopStatementVertex vertex, SymbolProvider symbols) {
41+
return DefaultNoOpScopeVisitor.shouldVisitChildren(vertex);
42+
}
43+
3944
@Override
4045
public boolean visit(DmlDeleteStatementVertex vertex, SymbolProvider symbols) {
4146
return DefaultNoOpScopeVisitor.shouldVisitChildren(vertex);
@@ -241,6 +246,11 @@ public boolean visit(VariableExpressionVertex.Single vertex, SymbolProvider symb
241246
return DefaultNoOpScopeVisitor.shouldVisitChildren(vertex);
242247
}
243248

249+
@Override
250+
public boolean visit(WhileLoopStatementVertex vertex, SymbolProvider symbols) {
251+
return DefaultNoOpScopeVisitor.shouldVisitChildren(vertex);
252+
}
253+
244254
@Override
245255
public void afterVisit(BaseSFVertex vertex, SymbolProvider symbols) {}
246256

sfge/src/main/java/com/salesforce/graph/visitor/PathVertexVisitor.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ void recursionDetected(
2323

2424
boolean visit(CatchBlockStatementVertex vertex, SymbolProvider symbols);
2525

26+
boolean visit(DoLoopStatementVertex vertex, SymbolProvider symbols);
27+
2628
boolean visit(DmlDeleteStatementVertex vertex, SymbolProvider symbols);
2729

2830
boolean visit(DmlInsertStatementVertex vertex, SymbolProvider symbols);
@@ -105,6 +107,8 @@ void recursionDetected(
105107

106108
boolean visit(VariableExpressionVertex.Single vertex, SymbolProvider symbols);
107109

110+
boolean visit(WhileLoopStatementVertex vertex, SymbolProvider symbols);
111+
108112
void afterVisit(BaseSFVertex vertex, SymbolProvider symbols);
109113

110114
void afterVisit(DoLoopStatementVertex vertex, SymbolProvider symbols);

sfge/src/main/java/com/salesforce/rules/MultipleMassSchemaLookupRule.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ protected String getCategory() {
5858

5959
@Override
6060
protected boolean isEnabled() {
61-
return false;
61+
return true;
6262
}
6363

6464
public static MultipleMassSchemaLookupRule getInstance() {

sfge/src/main/java/com/salesforce/rules/fls/apex/AbstractFlsVisitor.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ protected boolean shouldCollectInfo(BaseSFVertex vertex) {
9191
}
9292

9393
protected void afterVisitDmlStatementVertex(DmlStatementVertex vertex, SymbolProvider symbols) {
94-
if (shouldCollectInfo(vertex)) {
94+
// If the DML statement is in User mode, the operation is already considered safe.
95+
// Continue only if the statement is in System mode.
96+
if (vertex.isSystemMode() && shouldCollectInfo(vertex)) {
9597
validationCentral.createExpectedValidations(vertex, symbols);
9698
validationCentral.tallyValidations(vertex);
9799
}

sfge/src/main/java/com/salesforce/rules/fls/apex/operations/FlsValidationCentral.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,10 +142,6 @@ public void createExpectedValidations(DmlStatementVertex vertex, SymbolProvider
142142
}
143143

144144
final List<BaseSFVertex> dmlStatementVertexChildren = vertex.getChildren();
145-
if (dmlStatementVertexChildren.size() != validationType.parameterCount) {
146-
throw new UnexpectedException(
147-
"Unexpected count of parameters: " + dmlStatementVertexChildren.size());
148-
}
149145

150146
// Create expected validations based on the first parameter.
151147
// Even though MERGE operation takes two parameters, both of them need to be of the same
@@ -166,7 +162,6 @@ public void createExpectedValidations(DmlStatementVertex vertex, SymbolProvider
166162
if (LOGGER.isWarnEnabled()) {
167163
LOGGER.warn(
168164
"TODO: Apex value not detected for dml's child vertex: " + childVertex);
169-
// TODO: add telemetry
170165
}
171166
violations.add(
172167
FlsViolationCreatorUtil.createUnresolvedCrudFlsViolation(
@@ -175,7 +170,6 @@ public void createExpectedValidations(DmlStatementVertex vertex, SymbolProvider
175170
} else {
176171
if (LOGGER.isWarnEnabled()) {
177172
LOGGER.warn("TODO: Child vertex of DML is not a chained vertex: " + childVertex);
178-
// TODO: add telemetry
179173
}
180174
violations.add(
181175
FlsViolationCreatorUtil.createUnresolvedCrudFlsViolation(

sfge/src/main/java/com/salesforce/rules/multiplemassschemalookup/MultipleMassSchemaLookupVisitor.java

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package com.salesforce.rules.multiplemassschemalookup;
22

33
import com.salesforce.graph.symbols.SymbolProvider;
4-
import com.salesforce.graph.vertex.BaseSFVertex;
5-
import com.salesforce.graph.vertex.MethodCallExpressionVertex;
6-
import com.salesforce.graph.vertex.SFVertex;
7-
import com.salesforce.rules.ops.LoopDetectionVisitor;
4+
import com.salesforce.graph.vertex.*;
5+
import com.salesforce.rules.ops.visitor.LoopDetectionVisitor;
86
import java.util.HashSet;
7+
import java.util.Optional;
98
import java.util.Set;
109

1110
/**
12-
* Visitor detects when more than one invocation of Schema.getGlobalDescribe() is made in a path.
11+
* Visitor detects when more than one invocation of Schema.getGlobalDescribe() or
12+
* Schema.describeSObjects is made in a path.
1313
*/
1414
class MultipleMassSchemaLookupVisitor extends LoopDetectionVisitor {
1515
/** Represents the path entry point that this visitor is walking */
@@ -30,13 +30,8 @@ class MultipleMassSchemaLookupVisitor extends LoopDetectionVisitor {
3030
this.violations = new HashSet<>();
3131
}
3232

33-
@Override
34-
protected void execAfterLoopVertexVisit(BaseSFVertex vertex, SymbolProvider symbols) {
35-
if (shouldContinue()) {
36-
violations.add(
37-
new MultipleMassSchemaLookupInfo(
38-
sourceVertex, sinkVertex, RuleConstants.RepetitionType.LOOP, vertex));
39-
}
33+
public boolean visit(BlockStatementVertex vertex, SymbolProvider symbols) {
34+
return true;
4035
}
4136

4237
@Override
@@ -46,16 +41,49 @@ public void afterVisit(MethodCallExpressionVertex vertex, SymbolProvider symbols
4641
// look for anymore loops or additional calls.
4742
// TODO: A more performant approach would be to stop walking path from this point
4843
isSinkVisited = true;
44+
checkIfInsideLoop(vertex, symbols);
4945
} else if (RuleConstants.isSchemaExpensiveMethod(vertex) && shouldContinue()) {
50-
violations.add(
51-
new MultipleMassSchemaLookupInfo(
52-
sourceVertex,
53-
sinkVertex,
54-
RuleConstants.RepetitionType.MULTIPLE,
55-
vertex));
46+
createViolation(RuleConstants.RepetitionType.MULTIPLE, vertex);
47+
}
48+
49+
// Perform super method's logic as well to remove exclusion boundary if needed.
50+
super.afterVisit(vertex, symbols);
51+
}
52+
53+
private void checkIfInsideLoop(MethodCallExpressionVertex vertex, SymbolProvider symbols) {
54+
final Optional<? extends SFVertex> loopedVertexOpt = isInsideLoop();
55+
if (loopedVertexOpt.isPresent()) {
56+
// Method has been invoked inside a loop. Create a violation.
57+
createViolation(RuleConstants.RepetitionType.LOOP, loopedVertexOpt.get());
5658
}
5759
}
5860

61+
private void createViolation(RuleConstants.RepetitionType type, SFVertex repetitionVertex) {
62+
violations.add(
63+
new MultipleMassSchemaLookupInfo(sourceVertex, sinkVertex, type, repetitionVertex));
64+
}
65+
66+
/**
67+
* Identifies cases where even if the call is within a loop, this action wouldn't be called
68+
* multiple times.
69+
*
70+
* @param vertex Method call to examine
71+
* @param symbols
72+
* @return true if the method call would be called only once even if it's in a loop.
73+
*/
74+
private boolean isLoopOutlier(MethodCallExpressionVertex vertex, SymbolProvider symbols) {
75+
// If method call is in the ForEach value stream, consider the call an outlier.
76+
// For example, getValues() method would get invoked only once:
77+
// for (String s : getValues()) {...}
78+
// In this case, the method's immediate parent is the ForEachStatementVertex
79+
final BaseSFVertex parent = vertex.getParent();
80+
if (parent instanceof ForEachStatementVertex) {
81+
return true;
82+
}
83+
84+
return false;
85+
}
86+
5987
/**
6088
* Decides whether the rule should continue collecting violations
6189
*

sfge/src/main/java/com/salesforce/rules/multiplemassschemalookup/RuleConstants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public enum RepetitionType {
3535
}
3636

3737
public String getMessage(String... params) {
38-
return String.format(messageTemplate, params);
38+
return String.format(messageTemplate, (Object[]) params);
3939
}
4040
}
4141
}

0 commit comments

Comments
 (0)