Skip to content

Commit 807b321

Browse files
authored
Merge pull request #119 from codellm-devkit/113-call-graph-is-missing-edges-to-implementations-of-interfaces-merge-to-v1.X.X
Fix Issue 113: call graph is missing edges to implementations of interfaces. Merge to v1.X.X.
2 parents 286fa0f + 7614c2a commit 807b321

File tree

13 files changed

+510
-25
lines changed

13 files changed

+510
-25
lines changed

src/main/java/com/ibm/cldk/utils/AnalysisUtils.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ public static Iterable<Entrypoint> getEntryPoints(IClassHierarchy cha) {
153153
System.exit(1);
154154
return Stream.empty();
155155
}
156-
}).filter(method -> method.isPublic() || method.isPrivate() || method.isProtected() || method.isStatic()).map(method -> new DefaultEntrypoint(method, cha)).collect(Collectors.toList());
156+
}).map(method -> new DefaultEntrypoint(method, cha)).collect(Collectors.toList());
157157

158158
Log.info("Registered " + entrypoints.size() + " entrypoints.");
159159
return entrypoints;

src/main/java/com/ibm/cldk/utils/ProjectDirectoryScanner.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.nio.file.Files;
55
import java.nio.file.Path;
66
import java.nio.file.Paths;
7+
import java.util.ArrayList;
78
import java.util.List;
89
import java.util.stream.Collectors;
910
import java.util.stream.Stream;
@@ -37,7 +38,7 @@ public static List<Path> jarFilesStream(String projectPath) throws IOException {
3738
.collect(Collectors.toList());
3839
}
3940
}
40-
return null;
41+
return new ArrayList<>();
4142
}
4243

4344
public static List<Path> sourceFilesStream(String projectPath) throws IOException {

src/test/java/com/ibm/cldk/CodeAnalyzerIntegrationTest.java

Lines changed: 66 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
11
package com.ibm.cldk;
22

3+
import com.google.gson.Gson;
4+
import com.google.gson.JsonArray;
5+
import com.google.gson.JsonElement;
6+
import com.google.gson.JsonObject;
7+
import org.json.JSONArray;
38
import org.junit.jupiter.api.BeforeAll;
49
import org.junit.jupiter.api.Test;
510
import org.junit.jupiter.api.Assertions;
611
import org.testcontainers.containers.BindMode;
712
import org.testcontainers.containers.GenericContainer;
13+
import org.testcontainers.containers.startupcheck.OneShotStartupCheckStrategy;
814
import org.testcontainers.junit.jupiter.Container;
915
import org.testcontainers.junit.jupiter.Testcontainers;
1016
import org.testcontainers.utility.MountableFile;
1117

1218
import java.io.File;
1319
import java.io.FileInputStream;
1420
import java.io.IOException;
15-
import java.nio.file.Path;
1621
import java.nio.file.Paths;
17-
import java.text.MessageFormat;
22+
import java.time.Duration;
1823
import java.util.Properties;
24+
import java.util.stream.StreamSupport;
1925

20-
import static org.junit.jupiter.api.Assertions.assertThrows;
2126

2227
@Testcontainers
2328
@SuppressWarnings("resource")
@@ -28,7 +33,7 @@ public class CodeAnalyzerIntegrationTest {
2833
*/
2934
static String codeanalyzerVersion;
3035
static final String javaVersion = "17";
31-
36+
static String javaHomePath;
3237
static {
3338
// Build project first
3439
try {
@@ -44,15 +49,14 @@ public class CodeAnalyzerIntegrationTest {
4449
}
4550

4651
@Container
47-
static final GenericContainer<?> container = new GenericContainer<>("openjdk:17-jdk")
52+
static final GenericContainer<?> container = new GenericContainer<>("ubuntu:latest")
4853
.withCreateContainerCmdModifier(cmd -> cmd.withEntrypoint("sh"))
4954
.withCommand("-c", "while true; do sleep 1; done")
50-
.withFileSystemBind(
51-
String.valueOf(Paths.get(System.getProperty("user.dir")).resolve("build/libs")),
52-
"/opt/jars",
53-
BindMode.READ_WRITE)
55+
.withCopyFileToContainer(MountableFile.forHostPath(Paths.get(System.getProperty("user.dir")).resolve("build/libs")), "/opt/jars")
5456
.withCopyFileToContainer(MountableFile.forHostPath(Paths.get(System.getProperty("user.dir")).resolve("build/libs")), "/opt/jars")
5557
.withCopyFileToContainer(MountableFile.forHostPath(Paths.get(System.getProperty("user.dir")).resolve("src/test/resources/test-applications/mvnw-corrupt-test")), "/test-applications/mvnw-corrupt-test")
58+
.withCopyFileToContainer(MountableFile.forHostPath(Paths.get(System.getProperty("user.dir")).resolve("src/test/resources/test-applications/plantsbywebsphere")), "/test-applications/plantsbywebsphere")
59+
.withCopyFileToContainer(MountableFile.forHostPath(Paths.get(System.getProperty("user.dir")).resolve("src/test/resources/test-applications/call-graph-test")), "/test-applications/call-graph-test")
5660
.withCopyFileToContainer(MountableFile.forHostPath(Paths.get(System.getProperty("user.dir")).resolve("src/test/resources/test-applications/mvnw-working-test")), "/test-applications/mvnw-working-test");
5761

5862
@Container
@@ -61,11 +65,32 @@ public class CodeAnalyzerIntegrationTest {
6165
.withCommand("-c", "while true; do sleep 1; done")
6266
.withCopyFileToContainer(MountableFile.forHostPath(Paths.get(System.getProperty("user.dir")).resolve("build/libs")), "/opt/jars")
6367
.withCopyFileToContainer(MountableFile.forHostPath(Paths.get(System.getProperty("user.dir")).resolve("src/test/resources/test-applications/mvnw-corrupt-test")), "/test-applications/mvnw-corrupt-test")
64-
.withCopyFileToContainer(MountableFile.forHostPath(Paths.get(System.getProperty("user.dir")).resolve("src/test/resources/test-applications/mvnw-working-test")), "/test-applications/mvnw-working-test");
68+
.withCopyFileToContainer(MountableFile.forHostPath(Paths.get(System.getProperty("user.dir")).resolve("src/test/resources/test-applications/mvnw-working-test")), "/test-applications/mvnw-working-test")
69+
.withCopyFileToContainer(MountableFile.forHostPath(Paths.get(System.getProperty("user.dir")).resolve("src/test/resources/test-applications/daytrader8")), "/test-applications/daytrader8");
6570

71+
public CodeAnalyzerIntegrationTest() throws IOException, InterruptedException {
72+
}
6673

6774
@BeforeAll
6875
static void setUp() {
76+
// Install Java 17 in the base container
77+
try {
78+
container.execInContainer("apt-get", "update");
79+
container.execInContainer("apt-get", "install", "-y", "openjdk-17-jdk");
80+
81+
// Get JAVA_HOME dynamically
82+
var javaHomeResult = container.execInContainer("bash", "-c",
83+
"dirname $(dirname $(readlink -f $(which java)))"
84+
);
85+
javaHomePath = javaHomeResult.getStdout().trim();
86+
Assertions.assertFalse(javaHomePath.isEmpty(), "Failed to determine JAVA_HOME");
87+
88+
} catch (IOException | InterruptedException e) {
89+
throw new RuntimeException(e);
90+
}
91+
92+
93+
// Get the version of the codeanalyzer jar
6994
Properties properties = new Properties();
7095
try (FileInputStream fis = new FileInputStream(
7196
Paths.get(System.getProperty("user.dir"), "gradle.properties").toFile())) {
@@ -94,18 +119,36 @@ void shouldHaveCodeAnalyzerJar() throws Exception {
94119
@Test
95120
void shouldBeAbleToRunCodeAnalyzer() throws Exception {
96121
var runCodeAnalyzerJar = container.execInContainer(
97-
"java",
98-
"-jar",
99-
String.format("/opt/jars/codeanalyzer-%s.jar", codeanalyzerVersion),
100-
"--help"
101-
);
122+
"bash", "-c",
123+
String.format("export JAVA_HOME=%s && java -jar /opt/jars/codeanalyzer-%s.jar --help",
124+
javaHomePath, codeanalyzerVersion
125+
));
102126

103127
Assertions.assertEquals(0, runCodeAnalyzerJar.getExitCode(),
104128
"Command should execute successfully");
105129
Assertions.assertTrue(runCodeAnalyzerJar.getStdout().length() > 0,
106130
"Should have some output");
107131
}
108132

133+
@Test
134+
void callGraphShouldHaveKnownEdges() throws Exception {
135+
var whatIsInTheTestAppFolder = container.execInContainer("ls", "/test-applications/call-graph-test");
136+
var runCodeAnalyzerOnCallGraphTest = container.execInContainer(
137+
"bash", "-c",
138+
String.format(
139+
"export JAVA_HOME=%s && java -jar /opt/jars/codeanalyzer-%s.jar --input=/test-applications/call-graph-test --analysis-level=2",
140+
javaHomePath, codeanalyzerVersion
141+
)
142+
);
143+
144+
// Read the output JSON
145+
Gson gson = new Gson();
146+
JsonObject jsonObject = gson.fromJson(runCodeAnalyzerOnCallGraphTest.getStdout(), JsonObject.class);
147+
JsonArray systemDepGraph = jsonObject.getAsJsonArray("system_dependency_graph");
148+
Assertions.assertEquals(4, StreamSupport.stream(systemDepGraph.spliterator(), false).count(),
149+
"Expected exactly 4 entries in the system dependency graph");
150+
}
151+
109152
@Test
110153
void corruptMavenShouldNotBuildWithWrapper() throws IOException, InterruptedException {
111154
// Make executable
@@ -129,19 +172,19 @@ void corruptMavenShouldProduceAnalysisArtifactsWhenMVNCommandIsInPath() throws I
129172
Assertions.assertTrue(runCodeAnalyzer.getStdout().contains("[ERROR]\tCannot run program \"/test-applications/mvnw-corrupt-test/mvnw\"") && runCodeAnalyzer.getStdout().contains("/mvn."));
130173
// We should correctly identify the build tool used in the mvn command from the system path.
131174
Assertions.assertTrue(runCodeAnalyzer.getStdout().contains("[INFO]\tBuilding the project using /usr/bin/mvn."));
132-
}
175+
}
133176

134177
@Test
135178
void corruptMavenShouldNotTerminateWithErrorWhenMavenIsNotPresentUnlessAnalysisLevel2() throws IOException, InterruptedException {
136179
// When analysis level 2, we should get a Runtime Exception
137180
var runCodeAnalyzer = container.execInContainer(
138-
"java",
139-
"-jar",
140-
String.format("/opt/jars/codeanalyzer-%s.jar", codeanalyzerVersion),
141-
"--input=/test-applications/mvnw-corrupt-test",
142-
"--output=/tmp/",
143-
"--analysis-level=2"
144-
);
181+
"bash", "-c",
182+
String.format(
183+
"export JAVA_HOME=%s && java -jar /opt/jars/codeanalyzer-%s.jar --input=/test-applications/mvnw-corrupt-test --output=/tmp/ --analysis-level=2",
184+
javaHomePath, codeanalyzerVersion
185+
)
186+
);
187+
145188
Assertions.assertEquals(1, runCodeAnalyzer.getExitCode());
146189
Assertions.assertTrue(runCodeAnalyzer.getStderr().contains("java.lang.RuntimeException"));
147190
}

src/test/resources/test-applications/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ target/
3838
*.iws
3939
*.ipr
4040

41+
!gradle-wrapper.jar
42+
4143
# Ignore Eclipse files
4244
.settings/
4345
*.classpath
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#
2+
# https://help.github.com/articles/dealing-with-line-endings/
3+
#
4+
# Linux start script should use lf
5+
/gradlew text eol=lf
6+
7+
# These are Windows script files and should use crlf
8+
*.bat text eol=crlf
9+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Ignore Gradle project-specific cache directory
2+
.gradle
3+
4+
# Ignore Gradle build output directory
5+
build
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
plugins {
2+
id 'application'
3+
}
4+
5+
repositories {
6+
mavenCentral()
7+
}
8+
9+
java {
10+
sourceCompatibility = JavaVersion.VERSION_11
11+
targetCompatibility = JavaVersion.VERSION_11
12+
}
13+
14+
if (project.hasProperty('mainClass')) {
15+
mainClassName = project.getProperty('mainClass')
16+
} else {
17+
// use a default
18+
mainClassName =("org.example.User")
19+
}
20+
21+
sourceSets {
22+
main {
23+
java {
24+
srcDirs = ["src/main/java"]
25+
}
26+
resources {
27+
srcDirs = ["src/main/resources"]
28+
}
29+
}
30+
}
42.6 KB
Binary file not shown.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
distributionBase=GRADLE_USER_HOME
2+
distributionPath=wrapper/dists
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12.1-bin.zip
4+
networkTimeout=10000
5+
validateDistributionUrl=true
6+
zipStoreBase=GRADLE_USER_HOME
7+
zipStorePath=wrapper/dists

0 commit comments

Comments
 (0)