stage next
This commit is contained in:
@@ -512,5 +512,166 @@ class JdtDataFlowModelTest {
|
||||
String val = model.resolveValue(initEv, context);
|
||||
assertThat(val).isEqualTo("PAY");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFlowSensitiveLocalFieldMutations(@TempDir Path tempDir) throws IOException {
|
||||
Path comFoo = tempDir.resolve("com/foo");
|
||||
Files.createDirectories(comFoo);
|
||||
Files.writeString(comFoo.resolve("Test.java"),
|
||||
"package com.foo;\n" +
|
||||
"public class Test {\n" +
|
||||
" public static class Command {\n" +
|
||||
" private String event = \"DEFAULT\";\n" +
|
||||
" public void setEvent(String event) {\n" +
|
||||
" this.event = event;\n" +
|
||||
" }\n" +
|
||||
" public String getEvent() {\n" +
|
||||
" return this.event;\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" public void run() {\n" +
|
||||
" Command cmd = new Command();\n" +
|
||||
" cmd.setEvent(\"PAY\");\n" +
|
||||
" String res = cmd.getEvent();\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.setSourcepath(List.of(tempDir.toAbsolutePath().toString()));
|
||||
context.scan(tempDir);
|
||||
|
||||
TypeDeclaration td = context.getTypeDeclaration("com.foo.Test");
|
||||
assertThat(td).isNotNull();
|
||||
|
||||
MethodDeclaration md = null;
|
||||
for (MethodDeclaration m : td.getMethods()) {
|
||||
if (m.getName().getIdentifier().equals("run")) {
|
||||
md = m;
|
||||
}
|
||||
}
|
||||
assertThat(md).isNotNull();
|
||||
|
||||
VariableDeclarationStatement resStmt = (VariableDeclarationStatement) md.getBody().statements().get(2);
|
||||
VariableDeclarationFragment resFrag = (VariableDeclarationFragment) resStmt.fragments().get(0);
|
||||
Expression initializer = resFrag.getInitializer();
|
||||
|
||||
DataFlowModel model = new JdtDataFlowModel(context);
|
||||
String val = model.resolveValue(initializer, context);
|
||||
assertThat(val).isEqualTo("PAY");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFluentBuilderPatternPropagation(@TempDir Path tempDir) throws IOException {
|
||||
Path comFoo = tempDir.resolve("com/foo");
|
||||
Files.createDirectories(comFoo);
|
||||
Files.writeString(comFoo.resolve("Test.java"),
|
||||
"package com.foo;\n" +
|
||||
"public class Test {\n" +
|
||||
" public static class EventWrapper {\n" +
|
||||
" private final String event;\n" +
|
||||
" private EventWrapper(String event) {\n" +
|
||||
" this.event = event;\n" +
|
||||
" }\n" +
|
||||
" public String getEvent() { return this.event; }\n" +
|
||||
" public static Builder builder() {\n" +
|
||||
" return new Builder();\n" +
|
||||
" }\n" +
|
||||
" public static class Builder {\n" +
|
||||
" private String event;\n" +
|
||||
" public Builder event(String event) {\n" +
|
||||
" this.event = event;\n" +
|
||||
" return this;\n" +
|
||||
" }\n" +
|
||||
" public EventWrapper build() {\n" +
|
||||
" return new EventWrapper(this.event);\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" public void run() {\n" +
|
||||
" EventWrapper w = EventWrapper.builder().event(\"PAY_SUCCESS\").build();\n" +
|
||||
" String res = w.getEvent();\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.setSourcepath(List.of(tempDir.toAbsolutePath().toString()));
|
||||
context.scan(tempDir);
|
||||
|
||||
TypeDeclaration td = context.getTypeDeclaration("com.foo.Test");
|
||||
assertThat(td).isNotNull();
|
||||
|
||||
MethodDeclaration md = null;
|
||||
for (MethodDeclaration m : td.getMethods()) {
|
||||
if (m.getName().getIdentifier().equals("run")) {
|
||||
md = m;
|
||||
}
|
||||
}
|
||||
assertThat(md).isNotNull();
|
||||
|
||||
VariableDeclarationStatement resStmt = (VariableDeclarationStatement) md.getBody().statements().get(1);
|
||||
VariableDeclarationFragment resFrag = (VariableDeclarationFragment) resStmt.fragments().get(0);
|
||||
Expression initializer = resFrag.getInitializer();
|
||||
|
||||
DataFlowModel model = new JdtDataFlowModel(context);
|
||||
String val = model.resolveValue(initializer, context);
|
||||
assertThat(val).isEqualTo("PAY_SUCCESS");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPolymorphicUnionFallback(@TempDir Path tempDir) throws IOException {
|
||||
Path comFoo = tempDir.resolve("com/foo");
|
||||
Files.createDirectories(comFoo);
|
||||
Files.writeString(comFoo.resolve("Test.java"),
|
||||
"package com.foo;\n" +
|
||||
"public class Test {\n" +
|
||||
" public interface Service {\n" +
|
||||
" String getEvent();\n" +
|
||||
" }\n" +
|
||||
" public static class PayService implements Service {\n" +
|
||||
" public String getEvent() { return \"PAY\"; }\n" +
|
||||
" }\n" +
|
||||
" public static class CancelService implements Service {\n" +
|
||||
" public String getEvent() { return \"CANCEL\"; }\n" +
|
||||
" }\n" +
|
||||
" public void run(Service s) {\n" +
|
||||
" String ev = s.getEvent();\n" +
|
||||
" }\n" +
|
||||
"}"
|
||||
);
|
||||
|
||||
CodebaseContext context = new CodebaseContext();
|
||||
context.setResolveBindings(true);
|
||||
context.setSourcepath(List.of(tempDir.toAbsolutePath().toString()));
|
||||
context.scan(tempDir);
|
||||
|
||||
TypeDeclaration td = context.getTypeDeclaration("com.foo.Test");
|
||||
assertThat(td).isNotNull();
|
||||
|
||||
MethodDeclaration md = null;
|
||||
for (MethodDeclaration m : td.getMethods()) {
|
||||
if (m.getName().getIdentifier().equals("run")) {
|
||||
md = m;
|
||||
}
|
||||
}
|
||||
assertThat(md).isNotNull();
|
||||
|
||||
VariableDeclarationStatement evStmt = (VariableDeclarationStatement) md.getBody().statements().get(0);
|
||||
VariableDeclarationFragment evFrag = (VariableDeclarationFragment) evStmt.fragments().get(0);
|
||||
Expression initEv = evFrag.getInitializer();
|
||||
|
||||
DataFlowModel model = new JdtDataFlowModel(context);
|
||||
List<Expression> defs = model.getReachingDefinitions(initEv);
|
||||
assertThat(defs).hasSize(2);
|
||||
|
||||
List<String> values = defs.stream()
|
||||
.filter(e -> e instanceof StringLiteral)
|
||||
.map(e -> ((StringLiteral) e).getLiteralValue())
|
||||
.toList();
|
||||
assertThat(values).containsExactlyInAnyOrder("PAY", "CANCEL");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user