Skip to content

Commit 03529ab

Browse files
committed
Perform safe lexical preserving printer setup by checking for presence of
nodes with missing range; related test case (#140) Signed-off-by: Saurabh Sinha <sinha108@gmail.com>
1 parent 5ba42b9 commit 03529ab

File tree

3 files changed

+77
-5
lines changed

3 files changed

+77
-5
lines changed

src/main/java/com/ibm/cldk/SymbolTable.java

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,21 +1147,44 @@ private static boolean excludeSourceRoot(Path sourceRoot) {
11471147
return false;
11481148
}
11491149

1150+
/**
1151+
* Sets up lexical preserving printer for the given compilation unit in a safe manner by checking
1152+
* whether any node in the unit is missing ranges, which can result in exception.
1153+
*
1154+
* @param compilationUnit Compilation unit to be set with lexical preserving printer
1155+
* @return compilation unit set up with lexical preserving printer or the original compilation
1156+
* unit if the unit contains range-missing nodes
1157+
*/
1158+
private static CompilationUnit safeLexicalPreservingPrinterSetup(CompilationUnit compilationUnit) {
1159+
// setup lexical-preserving printer only if CU has no missing-range nodes
1160+
boolean hasNodeWithMissingRange = compilationUnit.findAll(Node.class).stream()
1161+
.anyMatch(n -> !n.getRange().isPresent());
1162+
if (!hasNodeWithMissingRange) {
1163+
return LexicalPreservingPrinter.setup(compilationUnit);
1164+
}
1165+
return compilationUnit;
1166+
}
1167+
11501168
public static Pair<Map<String, JavaCompilationUnit>, Map<String, List<Problem>>> extractAll(Path projectRootPath)
11511169
throws IOException {
1152-
SymbolSolverCollectionStrategy symbolSolverCollectionStrategy = new SymbolSolverCollectionStrategy();
1170+
ParserConfiguration config = new ParserConfiguration()
1171+
.setStoreTokens(true)
1172+
.setAttributeComments(true)
1173+
.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_21);
1174+
SymbolSolverCollectionStrategy symbolSolverCollectionStrategy = new SymbolSolverCollectionStrategy(config);
11531175
ProjectRoot projectRoot = symbolSolverCollectionStrategy.collect(projectRootPath);
11541176
javaSymbolSolver = (JavaSymbolSolver) symbolSolverCollectionStrategy.getParserConfiguration()
1155-
.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_21).getSymbolResolver().get();
1177+
.getSymbolResolver().get();
11561178
Map<String, JavaCompilationUnit> symbolTable = new LinkedHashMap<>();
11571179
Map<String, List<Problem>> parseProblems = new HashMap<>();
11581180
for (SourceRoot sourceRoot : projectRoot.getSourceRoots()) {
11591181
if (excludeSourceRoot(sourceRoot.getRoot())) {
11601182
continue;
11611183
}
1184+
sourceRoot.setParserConfiguration(config);
11621185
for (ParseResult<CompilationUnit> parseResult : sourceRoot.tryToParse()) {
11631186
if (parseResult.isSuccessful()) {
1164-
CompilationUnit compilationUnit = LexicalPreservingPrinter.setup(parseResult.getResult().get());
1187+
CompilationUnit compilationUnit = safeLexicalPreservingPrinterSetup(parseResult.getResult().get());
11651188
symbolTable.put(compilationUnit.getStorage().get().getPath().toString(),
11661189
processCompilationUnit(compilationUnit));
11671190
} else {
@@ -1181,13 +1204,15 @@ public static Pair<Map<String, JavaCompilationUnit>, Map<String, List<Problem>>>
11811204
combinedTypeSolver.add(new ReflectionTypeSolver());
11821205

11831206
ParserConfiguration parserConfiguration = new ParserConfiguration()
1207+
.setStoreTokens(true)
1208+
.setAttributeComments(true)
11841209
.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_21);
11851210
parserConfiguration.setSymbolResolver(new JavaSymbolSolver(combinedTypeSolver));
11861211

11871212
JavaParser javaParser = new JavaParser(parserConfiguration);
11881213
ParseResult<CompilationUnit> parseResult = javaParser.parse(code);
11891214
if (parseResult.isSuccessful()) {
1190-
CompilationUnit compilationUnit = LexicalPreservingPrinter.setup(parseResult.getResult().get());
1215+
CompilationUnit compilationUnit = safeLexicalPreservingPrinterSetup(parseResult.getResult().get());
11911216
Log.debug("Successfully parsed code. Now processing compilation unit");
11921217
symbolTable.put("<pseudo-path>", processCompilationUnit(compilationUnit));
11931218
} else {
@@ -1216,6 +1241,8 @@ public static Pair<Map<String, JavaCompilationUnit>, Map<String, List<Problem>>>
12161241
.getSymbolResolver().get();
12171242
Log.info("Setting parser language level to JAVA_21");
12181243
ParserConfiguration parserConfiguration = new ParserConfiguration()
1244+
.setStoreTokens(true)
1245+
.setAttributeComments(true)
12191246
.setLanguageLevel(ParserConfiguration.LanguageLevel.JAVA_21);
12201247
parserConfiguration.setSymbolResolver(javaSymbolSolver);
12211248

@@ -1229,7 +1256,7 @@ public static Pair<Map<String, JavaCompilationUnit>, Map<String, List<Problem>>>
12291256
for (Path javaFilePath : javaFilePaths) {
12301257
ParseResult<CompilationUnit> parseResult = javaParser.parse(javaFilePath);
12311258
if (parseResult.isSuccessful()) {
1232-
CompilationUnit compilationUnit = LexicalPreservingPrinter.setup(parseResult.getResult().get());
1259+
CompilationUnit compilationUnit = safeLexicalPreservingPrinterSetup(parseResult.getResult().get());
12331260
System.out.println("Successfully parsed file: " + javaFilePath.toString());
12341261
symbolTable.put(compilationUnit.getStorage().get().getPath().toString(),
12351262
processCompilationUnit(compilationUnit));

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ public void testExtractSingleGenricsDuplicateSignature_FunctorUtils() throws IOE
4747
Assertions.assertEquals(10, callables.size());
4848
}
4949

50+
@Test
51+
public void testExtractSingleMissingNodeRange() throws IOException {
52+
String javaCode = getJavaCodeForTestResource("test-applications/missing-node-range-test/WeakHashtableTestCase.java");
53+
Map<String, JavaCompilationUnit> symbolTable = SymbolTable.extractSingle(javaCode).getLeft();
54+
Assertions.assertEquals(1, symbolTable.size());
55+
Map<String, Type> typeDeclaration = symbolTable.values().iterator().next().getTypeDeclarations();
56+
Assertions.assertEquals(2, typeDeclaration.size());
57+
}
58+
5059
@Test
5160
public void testCallSiteArgumentExpression() throws IOException {
5261
String javaCode = getJavaCodeForTestResource("test-applications/generics-varargs-duplicate-signature-test/Validate.java");
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import java.lang.ref.ReferenceQueue;
2+
import java.lang.ref.WeakReference;
3+
import java.util.ArrayList;
4+
import java.util.Collection;
5+
import java.util.Enumeration;
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import java.util.Set;
9+
import junit.framework.TestCase;
10+
11+
public class WeakHashtableTestCase extends TestCase {
12+
13+
public static class TestThread extends Thread {
14+
15+
public TestThread(final String name) {
16+
super(name);
17+
}
18+
19+
@Override
20+
public void run() {
21+
for (int i = 0; i < RUN_LOOPS; i++) {
22+
hashtable.put("key:" + i % 10, Boolean.TRUE);
23+
if (i % 50 == 0) {
24+
yield();
25+
}
26+
}
27+
}
28+
}
29+
private static final int RUN_LOOPS = 3000;
30+
private static WeakHashtable hashtable;
31+
32+
public WeakHashtableTestCase(final String testName) {
33+
super(testName);
34+
}
35+
36+
}

0 commit comments

Comments
 (0)