Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions sfge/src/main/java/com/salesforce/graph/ops/MethodUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ public static List<MethodVertex> getNamespaceAccessibleMethods(
}

/**
* Returns non-test methods in the target files with a @RemoteAction annotation. An empty
* list implicitly includes all files.
* Returns non-test methods in the target files with a @RemoteAction annotation. An empty list
* implicitly includes all files.
*/
public static List<MethodVertex> getRemoteActionMethods(
GraphTraversalSource g, List<String> targetFiles) {
Expand Down Expand Up @@ -229,6 +229,34 @@ private static GraphTraversal<Vertex, Vertex> rootMethodTraversal(
.not(has(Schema.IS_TEST, true));
}

/**
* Returns non-test methods in the target files whose modifier scope is `global`. An empty list
* implicitly includes all files.
*/
public static List<MethodVertex> getGlobalMethods(
GraphTraversalSource g, List<String> targetFiles) {
// Get all methods in the target files.
return SFVertexFactory.loadVertices(
g,
rootMethodTraversal(g, targetFiles)
.filter(
__.and(
// If a method has at least one block statement, then it is
// definitely actually declared, as
// opposed to being an implicit method.
out(Schema.CHILD)
.hasLabel(NodeType.BLOCK_STATEMENT)
.count()
.is(P.gte(1)),
// We only want global methods.
out(Schema.CHILD)
.hasLabel(NodeType.MODIFIER_NODE)
.has(Schema.GLOBAL, true),
// Ignore any standard methods, otherwise will get a ton of
// extra results.
__.not(__.has(Schema.IS_STANDARD, true)))));
}

/**
* Returns all non-test public- and global-scoped methods in controllers referenced by
* VisualForce pages, filtered by target file list. An empty list implicitly includes all files.
Expand Down
2 changes: 2 additions & 0 deletions sfge/src/main/java/com/salesforce/rules/RuleUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public static List<MethodVertex> getPathEntryPoints(
methods.addAll(MethodUtil.getRemoteActionMethods(g, fileLevelTargets));
// ...and PageReference methods...
methods.addAll(MethodUtil.getPageReferenceMethods(g, fileLevelTargets));
// ...and global-exposed methods...
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a RuleUtilTest for this category as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't hurt. Stand by for that.

methods.addAll(MethodUtil.getGlobalMethods(g, fileLevelTargets));
// ...and exposed methods on VF controllers.
methods.addAll(MethodUtil.getExposedControllerMethods(g, fileLevelTargets));
}
Expand Down
39 changes: 39 additions & 0 deletions sfge/src/test/java/com/salesforce/graph/ops/MethodUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -389,4 +389,43 @@ public void testGetMethodsWithAnnotation(String annotation) {
MatcherAssert.assertThat(excludedName, excludedMethod.isTest(), equalTo(true));
}
}

@Test
public void testGetGlobalMethods() {
String[] sourceCode = {
"public class MyClass {\n"
+ " global static void foo() {\n"
+ " }\n"
+ " global static testMethod void shouldBeExcludedByModifier() {\n"
+ " }\n"
+ " @isTest\n"
+ " global static void shouldBeExcludedByAnnotation() {\n"
+ " }\n"
+ " public static void bar() {\n"
+ " }\n"
+ "}\n",
"@isTest\n"
+ "public class MyTestClass {\n"
+ " public static void foo() {\n"
+ " }\n"
+ "}\n",
};

TestUtil.buildGraph(g, sourceCode);

List<MethodVertex> methods = MethodUtil.getGlobalMethods(g, new ArrayList<>());
// The `foo` method should be included because it's declared as global.
MatcherAssert.assertThat(methods, hasSize(equalTo(1)));
MatcherAssert.assertThat(methods.get(0).getName(), equalTo("foo"));

for (String excludedName :
new String[] {"shouldBeExcludedByModifier", "shouldBeExcludedByAnnotation"}) {
MethodVertex excludedMethod =
SFVertexFactory.load(
g,
g.V().hasLabel(ASTConstants.NodeType.METHOD)
.has(Schema.NAME, excludedName));
MatcherAssert.assertThat(excludedName, excludedMethod.isTest(), equalTo(true));
}
}
}
37 changes: 35 additions & 2 deletions sfge/src/test/java/com/salesforce/rules/RuleUtilTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.core.IsNot.not;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assertions.*;

import com.salesforce.TestUtil;
import com.salesforce.graph.Schema;
Expand Down Expand Up @@ -63,6 +62,40 @@ public void getPathEntryPoints_includesAnnotatedMethods(String annotation) {
assertEquals("annotatedMethod", firstVertex.getName());
}

@Test
public void getPathEntryPoints_includesGlobalMethods() {
String sourceCode =
"public class Foo {\n"
+ " global static void globalStaticMethod() {\n"
+ " }\n"
+ " global void globalInstanceMethod() {\n"
+ " }\n"
+ " public static void publicStaticMethod() {\n"
+ " }\n"
+ "}\n";
TestUtil.buildGraph(g, sourceCode, true);

List<MethodVertex> entryPoints = RuleUtil.getPathEntryPoints(g);

MatcherAssert.assertThat(entryPoints, hasSize(equalTo(2)));
boolean staticMethodFound = false;
boolean instanceMethodFound = false;
for (MethodVertex entrypoint : entryPoints) {
switch (entrypoint.getName()) {
case "globalStaticMethod":
staticMethodFound = true;
break;
case "globalInstanceMethod":
instanceMethodFound = true;
break;
default:
fail("Unexpected method " + entrypoint.getName());
}
}
assertTrue(staticMethodFound);
assertTrue(instanceMethodFound);
}

@Test
public void getPathEntryPoints_includesPageReferenceMethods() {
String sourceCode =
Expand Down