Skip to content

Commit 15b5613

Browse files
committed
Improve speed
1 parent f393625 commit 15b5613

3 files changed

Lines changed: 60 additions & 15 deletions

File tree

src/main/java/com/neuvem/java2graph/passes/DelombokPass.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ public void execute(Java2GraphConfig config, GraphContext context) throws Except
2727
System.out.println("Processing Lombok annotations via isolated process (with classpath resolution)...");
2828

2929
Path delombokDir = Files.createTempDirectory("delombok");
30-
String javaHome = System.getProperty("java.home");
31-
String javaBin = javaHome + "/bin/java";
30+
String providedJavaHome = "/opt/homebrew/Cellar/openjdk@17/17.0.18/libexec/openjdk.jdk/Contents/Home";
31+
String javaBin = providedJavaHome + "/bin/java";
3232
String mainClasspath = System.getProperty("java.class.path");
3333

3434
// Resolve the project's dependencies for delombok attribution

src/main/java/com/neuvem/java2graph/passes/ParsePass.java

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,18 @@ public void execute(Java2GraphConfig config, GraphContext context) throws Except
3333
// 1. ReflectionTypeSolver for classes on the full classpath (not just JRE)
3434
typeSolver.add(new ReflectionTypeSolver(false));
3535

36-
// 2. JavaParserTypeSolver for source code being analyzed
37-
typeSolver.add(new JavaParserTypeSolver(config.getSrcDir()));
38-
36+
// 2. Add Jars BEFORE JavaParserTypeSolver to prevent disk I/O thrashing for library imports
3937
if (config.getJarPaths() != null) {
4038
for (Path jarPath : config.getJarPaths()) {
4139
scanAndAddJars(typeSolver, jarPath);
4240
}
4341
}
4442

43+
// 3. We do NOT add JavaParserTypeSolver here. Instead, we use a memory-mapped AstTypeSolver
44+
// built directly from the parsed ASTs to eliminate disk I/O during resolution for large repos.
45+
46+
// Assign the shared TypeSolver for graph context, but DO NOT share the SymbolSolver which is not thread-safe.
4547
context.typeSolver = typeSolver;
46-
JavaSymbolSolver symbolSolver = new JavaSymbolSolver(typeSolver);
47-
48-
// Configure JavaParser with the Symbol Solver
49-
ParserConfiguration parserConfiguration = new ParserConfiguration()
50-
.setSymbolResolver(symbolSolver)
51-
.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_17);
5248

5349
List<Path> javaFiles;
5450
try (Stream<Path> paths = Files.walk(config.getSrcDir())) {
@@ -59,8 +55,14 @@ public void execute(Java2GraphConfig config, GraphContext context) throws Except
5955

6056
javaFiles.parallelStream().forEach(path -> {
6157
try {
62-
// Instantiate a new JavaParser per thread
63-
JavaParser javaParser = new JavaParser(parserConfiguration);
58+
// JavaSymbolSolver state is mutated during parsing and resolution; MUST be instantiated per-thread
59+
JavaSymbolSolver localSymbolSolver = new JavaSymbolSolver(typeSolver);
60+
61+
ParserConfiguration localConfig = new ParserConfiguration()
62+
.setSymbolResolver(localSymbolSolver)
63+
.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_17);
64+
65+
JavaParser javaParser = new JavaParser(localConfig);
6466
ParseResult<CompilationUnit> result = javaParser.parse(path);
6567
result.getResult().ifPresent(cu -> {
6668
context.compilationUnits.put(path.toString(), cu);
@@ -70,7 +72,42 @@ public void execute(Java2GraphConfig config, GraphContext context) throws Except
7072
}
7173
});
7274

73-
System.out.println("Finished parsing.");
75+
System.out.println("Finished parsing. Building memory-mapped TypeSolver...");
76+
AstTypeSolver astTypeSolver = new AstTypeSolver();
77+
for (CompilationUnit cu : context.compilationUnits.values()) {
78+
astTypeSolver.addCompilationUnit(cu);
79+
}
80+
typeSolver.add(astTypeSolver);
81+
}
82+
83+
private static class AstTypeSolver implements com.github.javaparser.resolution.TypeSolver {
84+
private com.github.javaparser.resolution.TypeSolver parent;
85+
private final java.util.Map<String, com.github.javaparser.ast.body.TypeDeclaration<?>> types = new java.util.HashMap<>();
86+
87+
public void addCompilationUnit(CompilationUnit cu) {
88+
for (com.github.javaparser.ast.body.TypeDeclaration<?> t : cu.findAll(com.github.javaparser.ast.body.TypeDeclaration.class)) {
89+
java.util.Optional<String> optFqn = t.getFullyQualifiedName();
90+
if (optFqn.isPresent()) {
91+
types.put(optFqn.get(), t);
92+
}
93+
}
94+
}
95+
96+
@Override
97+
public com.github.javaparser.resolution.TypeSolver getParent() { return parent; }
98+
99+
@Override
100+
public void setParent(com.github.javaparser.resolution.TypeSolver parent) { this.parent = parent; }
101+
102+
@Override
103+
public com.github.javaparser.resolution.model.SymbolReference<com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration> tryToSolveType(String name) {
104+
com.github.javaparser.ast.body.TypeDeclaration<?> t = types.get(name);
105+
if (t != null) {
106+
com.github.javaparser.resolution.declarations.ResolvedReferenceTypeDeclaration resolved = com.github.javaparser.symbolsolver.javaparsermodel.JavaParserFacade.get(getRoot()).getTypeDeclaration(t);
107+
return com.github.javaparser.resolution.model.SymbolReference.solved(resolved);
108+
}
109+
return com.github.javaparser.resolution.model.SymbolReference.unsolved();
110+
}
74111
}
75112

76113
private void scanAndAddJars(CombinedTypeSolver typeSolver, Path path) throws IOException {

src/main/java/com/neuvem/java2graph/passes/ResolvePass.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,21 @@ public class ResolvePass implements Pass {
2525

2626
@Override
2727
public void execute(Java2GraphConfig config, GraphContext context) throws Exception {
28-
System.out.println("Resolving ASTs with Advanced Symbol Resolution...");
28+
int totalFiles = context.compilationUnits.size();
29+
System.out.println("Resolving ASTs with Advanced Symbol Resolution for " + totalFiles + " files...");
30+
31+
java.util.concurrent.atomic.AtomicInteger resolvedCount = new java.util.concurrent.atomic.AtomicInteger(0);
2932

3033
context.compilationUnits.values().parallelStream().forEach(cu -> {
3134
try {
3235
cu.accept(new ResolverVisitor(context, cu), null);
3336
} catch (Throwable e) {
3437
System.err.println("Failed to resolve compilation unit: " + e.getMessage());
38+
} finally {
39+
int count = resolvedCount.incrementAndGet();
40+
if (count % 500 == 0 || count == totalFiles) {
41+
System.out.println("Resolved " + count + " / " + totalFiles + " files...");
42+
}
3543
}
3644
});
3745

0 commit comments

Comments
 (0)