Skip to content

Commit 7dbfded

Browse files
authored
Merge pull request #141 from codellm-devkit/fix/239-240-duplicate-key-node-range-errors
Fix/239 240 duplicate key node range errors
2 parents 402e6c0 + 03529ab commit 7dbfded

File tree

4 files changed

+166
-7
lines changed

4 files changed

+166
-7
lines changed

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

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ private static String getTypeErasureSignature(CallableDeclaration callableDecl)
593593
Parameter parameter = (Parameter) param;
594594
ResolvedType resolvedType = parameter.getType().resolve();
595595
if (parameter.isVarArgs()) {
596-
erasureParameterTypes.add(resolvedType.describe() + "[]");
596+
erasureParameterTypes.add(resolvedType.erasure().describe() + "[]");
597597
} else {
598598
erasureParameterTypes.add(resolvedType.erasure().describe());
599599
}
@@ -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: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ private String getJavaCodeForTestResource(String resourcePath) {
2626
}
2727

2828
@Test
29-
public void testExtractSingleGenricsDuplicateSignature() throws IOException {
29+
public void testExtractSingleGenricsDuplicateSignature_Validate() throws IOException {
3030
String javaCode = getJavaCodeForTestResource("test-applications/generics-varargs-duplicate-signature-test/Validate.java");
3131
Map<String, JavaCompilationUnit> symbolTable = SymbolTable.extractSingle(javaCode).getLeft();
3232
Assertions.assertEquals(1, symbolTable.size());
@@ -36,6 +36,26 @@ public void testExtractSingleGenricsDuplicateSignature() throws IOException {
3636
Assertions.assertEquals(17, callables.size());
3737
}
3838

39+
@Test
40+
public void testExtractSingleGenricsDuplicateSignature_FunctorUtils() throws IOException {
41+
String javaCode = getJavaCodeForTestResource("test-applications/generics-varargs-duplicate-signature-test/FunctorUtils.java");
42+
Map<String, JavaCompilationUnit> symbolTable = SymbolTable.extractSingle(javaCode).getLeft();
43+
Assertions.assertEquals(1, symbolTable.size());
44+
Map<String, Type> typeDeclaration = symbolTable.values().iterator().next().getTypeDeclarations();
45+
Assertions.assertEquals(1, typeDeclaration.size());
46+
Map<String, Callable> callables = typeDeclaration.values().iterator().next().getCallableDeclarations();
47+
Assertions.assertEquals(10, callables.size());
48+
}
49+
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+
3959
@Test
4060
public void testCallSiteArgumentExpression() throws IOException {
4161
String javaCode = getJavaCodeForTestResource("test-applications/generics-varargs-duplicate-signature-test/Validate.java");
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import java.util.Collection;
2+
import java.util.Objects;
3+
import java.util.function.Consumer;
4+
import java.util.function.Function;
5+
import org.apache.commons.collections4.Predicate;
6+
7+
final class FunctorUtils {
8+
9+
private static <T> T[] clone(final T... array) {
10+
return array != null ? array.clone() : null;
11+
}
12+
13+
static <R extends java.util.function.Predicate<T>, P extends java.util.function.Predicate<? super T>, T> R coerce(final P predicate) {
14+
return (R) predicate;
15+
}
16+
17+
static <R extends Function<I, O>, P extends Function<? super I, ? extends O>, I, O> R coerce(final P transformer) {
18+
return (R) transformer;
19+
}
20+
21+
static <T extends Consumer<?>> T[] copy(final T... consumers) {
22+
return clone(consumers);
23+
}
24+
25+
static <T extends java.util.function.Predicate<?>> T[] copy(final T... predicates) {
26+
return clone(predicates);
27+
}
28+
29+
static <T extends Function<?, ?>> T[] copy(final T... transformers) {
30+
return clone(transformers);
31+
}
32+
33+
static <T> Predicate<? super T>[] validate(final Collection<? extends java.util.function.Predicate<? super T>> predicates) {
34+
Objects.requireNonNull(predicates, "predicates");
35+
// convert to array like this to guarantee iterator() ordering
36+
@SuppressWarnings("unchecked") // OK
37+
final Predicate<? super T>[] preds = new Predicate[predicates.size()];
38+
int i = 0;
39+
for (final java.util.function.Predicate<? super T> predicate : predicates) {
40+
preds[i] = (Predicate<? super T>) predicate;
41+
if (preds[i] == null) {
42+
throw new NullPointerException("predicates[" + i + "]");
43+
}
44+
i++;
45+
}
46+
return preds;
47+
}
48+
49+
static void validate(final Consumer<?>... consumers) {
50+
Objects.requireNonNull(consumers, "consumers");
51+
for (int i = 0; i < consumers.length; i++) {
52+
if (consumers[i] == null) {
53+
throw new NullPointerException("closures[" + i + "]");
54+
}
55+
}
56+
}
57+
58+
static void validate(final Function<?, ?>... functions) {
59+
Objects.requireNonNull(functions, "functions");
60+
for (int i = 0; i < functions.length; i++) {
61+
if (functions[i] == null) {
62+
throw new NullPointerException("functions[" + i + "]");
63+
}
64+
}
65+
}
66+
67+
static void validate(final java.util.function.Predicate<?>... predicates) {
68+
Objects.requireNonNull(predicates, "predicates");
69+
for (int i = 0; i < predicates.length; i++) {
70+
if (predicates[i] == null) {
71+
throw new NullPointerException("predicates[" + i + "]");
72+
}
73+
}
74+
}
75+
76+
}
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)