Skip to content

Commit 402e6c0

Browse files
authored
Merge pull request #138 from codellm-devkit/issue136-duplicate-key-error
Fixes for duplicate key and stack overflow errors, and updates in call site model and symbol table construction
2 parents 08d11b7 + 7b23242 commit 402e6c0

File tree

227 files changed

+8102
-8130
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

227 files changed

+8102
-8130
lines changed

build.gradle

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ plugins {
1717
id 'application'
1818
id 'org.graalvm.buildtools.native' version '0.10.4'
1919
id 'org.jetbrains.kotlin.jvm'
20+
id 'com.diffplug.spotless' version '6.25.0'
2021
}
2122

2223
// Get the version from the property file first
@@ -145,6 +146,20 @@ test {
145146
systemProperty 'testcontainers.reuse.enable', 'true'
146147
}
147148

149+
spotless {
150+
java {
151+
target 'src/**/*.java'
152+
trimTrailingWhitespace()
153+
endWithNewline()
154+
importOrder()
155+
}
156+
}
157+
158+
compileJava.dependsOn spotlessApply
159+
160+
// Optionally, automatically format before compilation
161+
// compileJava.dependsOn googleJavaFormat
162+
148163
task fatJar(type: Jar) {
149164
archiveBaseName = 'codeanalyzer'
150165
duplicatesStrategy = DuplicatesStrategy.EXCLUDE

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version=2.3.4
1+
version=2.3.5

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

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,17 @@
1212
*/
1313
package com.ibm.cldk;
1414

15+
import com.github.javaparser.Problem;
16+
import com.google.common.reflect.TypeToken;
17+
import com.google.gson.FieldNamingPolicy;
18+
import com.google.gson.Gson;
19+
import com.google.gson.GsonBuilder;
20+
import com.google.gson.JsonElement;
21+
import com.google.gson.JsonObject;
22+
import com.google.gson.JsonParser;
23+
import com.ibm.cldk.entities.JavaCompilationUnit;
24+
import com.ibm.cldk.utils.BuildProject;
25+
import com.ibm.cldk.utils.Log;
1526
import java.io.File;
1627
import java.io.FileReader;
1728
import java.io.FileWriter;
@@ -23,21 +34,7 @@
2334
import java.util.List;
2435
import java.util.Map;
2536
import java.util.stream.Collectors;
26-
2737
import org.apache.commons.lang3.tuple.Pair;
28-
29-
import com.github.javaparser.Problem;
30-
import com.google.common.reflect.TypeToken;
31-
import com.google.gson.FieldNamingPolicy;
32-
import com.google.gson.Gson;
33-
import com.google.gson.GsonBuilder;
34-
import com.google.gson.JsonElement;
35-
import com.google.gson.JsonObject;
36-
import com.google.gson.JsonParser;
37-
import com.ibm.cldk.entities.JavaCompilationUnit;
38-
import com.ibm.cldk.utils.BuildProject;
39-
import com.ibm.cldk.utils.Log;
40-
4138
import picocli.CommandLine;
4239
import picocli.CommandLine.Command;
4340
import picocli.CommandLine.Option;

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

Lines changed: 110 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,19 @@
11
package com.ibm.cldk;
22

3-
import java.io.IOException;
4-
import java.nio.file.Path;
5-
import java.nio.file.Paths;
6-
import java.util.ArrayList;
7-
import java.util.Collections;
8-
import java.util.HashMap;
9-
import java.util.HashSet;
10-
import java.util.LinkedHashMap;
11-
import java.util.List;
12-
import java.util.Map;
13-
import java.util.Objects;
14-
import java.util.Optional;
15-
import java.util.Set;
16-
import java.util.stream.Collectors;
17-
import java.util.stream.IntStream;
18-
193
import com.github.javaparser.*;
204
import com.github.javaparser.ast.*;
215
import com.github.javaparser.ast.body.*;
226
import com.github.javaparser.ast.comments.Comment;
237
import com.github.javaparser.ast.comments.JavadocComment;
248
import com.github.javaparser.ast.expr.*;
259
import com.github.javaparser.ast.nodeTypes.NodeWithJavadoc;
26-
import com.github.javaparser.ast.stmt.*;
27-
import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;
28-
import com.ibm.cldk.entities.*;
29-
import com.ibm.cldk.javaee.EntrypointsFinderFactory;
30-
import org.apache.commons.lang3.tuple.Pair;
31-
3210
import com.github.javaparser.ast.nodeTypes.NodeWithName;
11+
import com.github.javaparser.ast.stmt.*;
3312
import com.github.javaparser.ast.type.ReferenceType;
3413
import com.github.javaparser.ast.type.Type;
14+
import com.github.javaparser.printer.lexicalpreservation.LexicalPreservingPrinter;
3515
import com.github.javaparser.resolution.declarations.ResolvedMethodDeclaration;
16+
import com.github.javaparser.resolution.declarations.ResolvedMethodLikeDeclaration;
3617
import com.github.javaparser.resolution.types.ResolvedType;
3718
import com.github.javaparser.symbolsolver.JavaSymbolSolver;
3819
import com.github.javaparser.symbolsolver.resolution.typesolvers.CombinedTypeSolver;
@@ -42,10 +23,20 @@
4223
import com.github.javaparser.utils.SourceRoot;
4324
import com.google.common.collect.Table;
4425
import com.google.common.collect.Tables;
26+
import com.ibm.cldk.entities.*;
4527
import com.ibm.cldk.javaee.CRUDFinderFactory;
28+
import com.ibm.cldk.javaee.EntrypointsFinderFactory;
4629
import com.ibm.cldk.javaee.utils.enums.CRUDOperationType;
4730
import com.ibm.cldk.javaee.utils.enums.CRUDQueryType;
4831
import com.ibm.cldk.utils.Log;
32+
import java.io.IOException;
33+
import java.nio.file.Path;
34+
import java.nio.file.Paths;
35+
import java.util.*;
36+
import java.util.regex.Pattern;
37+
import java.util.stream.Collectors;
38+
import java.util.stream.IntStream;
39+
import org.apache.commons.lang3.tuple.Pair;
4940

5041
@SuppressWarnings({"unchecked", "rawtypes"})
5142
public class SymbolTable {
@@ -501,7 +492,7 @@ private static Pair<String, Callable> processCallableDeclaration(CallableDeclara
501492
callableNode.setFilePath(filePath);
502493

503494
// add callable signature
504-
callableNode.setSignature(callableDecl.getSignature().asString());
495+
callableNode.setSignature(getTypeErasureSignature(callableDecl));
505496

506497
// add comment associated with method/constructor
507498
callableNode.setComments(
@@ -581,11 +572,62 @@ private static Pair<String, Callable> processCallableDeclaration(CallableDeclara
581572
callableNode.setVariableDeclarations(getVariableDeclarations(body));
582573
callableNode.setCyclomaticComplexity(getCyclomaticComplexity(callableDecl));
583574

584-
String callableSignature = (callableDecl instanceof MethodDeclaration) ? callableDecl.getSignature().asString()
585-
: callableDecl.getSignature().asString().replace(callableDecl.getSignature().getName(), "<init>");
575+
String callableSignature = getTypeErasureSignature(callableDecl);
586576
return Pair.of(callableSignature, callableNode);
587577
}
588578

579+
/**
580+
* Returns type erasure signature for the given callable. Returns regular signature if an
581+
* error occurs in getting erased types.
582+
*
583+
* @param callableDecl: Callable to compute type erasure signature for
584+
* @return String representing type erasure or regular signature
585+
*/
586+
private static String getTypeErasureSignature(CallableDeclaration callableDecl) {
587+
try {
588+
StringBuilder signature = new StringBuilder(
589+
(callableDecl instanceof MethodDeclaration) ? callableDecl.getNameAsString() : "<init>"
590+
);
591+
List<String> erasureParameterTypes = new ArrayList<>();
592+
for (Object param : callableDecl.getParameters()) {
593+
Parameter parameter = (Parameter) param;
594+
ResolvedType resolvedType = parameter.getType().resolve();
595+
if (parameter.isVarArgs()) {
596+
erasureParameterTypes.add(resolvedType.describe() + "[]");
597+
} else {
598+
erasureParameterTypes.add(resolvedType.erasure().describe());
599+
}
600+
}
601+
signature.append("(");
602+
signature.append(String.join(", ", erasureParameterTypes));
603+
signature.append(")");
604+
return signature.toString();
605+
} catch (Throwable e) {
606+
Log.warn("Could not compute type erasure signature for "+callableDecl.getSignature().asString()+
607+
"; computing regular signature");
608+
return callableDecl.getSignature().asString();
609+
}
610+
}
611+
612+
/**
613+
* Returns type erasure signature for the given method or constructor declaration
614+
* resolved for a call site.
615+
*
616+
* @param methodDecl: Resolved method/constructor to compute type erasure signature for
617+
* @return String representing type erasure signature
618+
*/
619+
private static String getTypeErasureSignature(ResolvedMethodLikeDeclaration methodDecl) {
620+
StringBuilder signature = new StringBuilder(methodDecl.getName());
621+
List<String> erasureParameterTypes = new ArrayList<>();
622+
for (int i = 0; i < methodDecl.getNumberOfParams(); i++) {
623+
erasureParameterTypes.add(methodDecl.getParam(i).getType().erasure().describe());
624+
}
625+
signature.append("(");
626+
signature.append(String.join(", ", erasureParameterTypes));
627+
signature.append(")");
628+
return signature.toString();
629+
}
630+
589631
private static boolean isEntryPointMethod(CallableDeclaration callableDecl) {
590632
return EntrypointsFinderFactory.getEntrypointFinders()
591633
.anyMatch(finder -> finder.isEntrypointMethod(callableDecl));
@@ -835,8 +877,8 @@ private static List<CallSite> getCallSites(Optional<BlockStmt> callableBody) {
835877
// resolve callee and get signature
836878
String calleeSignature = "";
837879
try {
838-
calleeSignature = methodCallExpr.resolve().getSignature();
839-
} catch (RuntimeException exception) {
880+
calleeSignature = getTypeErasureSignature(methodCallExpr.resolve());
881+
} catch (Throwable exception) {
840882
Log.debug("Could not resolve method call: " + methodCallExpr + ": " + exception.getMessage());
841883
}
842884

@@ -845,12 +887,12 @@ private static List<CallSite> getCallSites(Optional<BlockStmt> callableBody) {
845887
try {
846888
ResolvedMethodDeclaration resolvedMethodDeclaration = methodCallExpr.resolve();
847889
accessSpecifier = resolvedMethodDeclaration.accessSpecifier();
848-
} catch (RuntimeException exception) {
890+
} catch (Throwable exception) {
849891
Log.debug("Could not resolve access specifier for method call: " + methodCallExpr + ": "
850892
+ exception.getMessage());
851893
}
852894
// resolve arguments of the method call to types
853-
List<String> arguments = methodCallExpr.getArguments().stream().map(SymbolTable::resolveExpression)
895+
List<String> argumentTypes = methodCallExpr.getArguments().stream().map(SymbolTable::resolveExpression)
854896
.collect(Collectors.toList());
855897
// Get argument string from the callsite
856898
List<String> listOfArgumentStrings = methodCallExpr.getArguments().stream().map(Expression::toString)
@@ -886,7 +928,7 @@ private static List<CallSite> getCallSites(Optional<BlockStmt> callableBody) {
886928

887929

888930
callSites.add(createCallSite(methodCallExpr, methodCallExpr.getNameAsString(), receiverName, declaringType,
889-
arguments, returnType, calleeSignature, isStaticCall, false, crudOperation, crudQuery,
931+
argumentTypes, listOfArgumentStrings, returnType, calleeSignature, isStaticCall, false, crudOperation, crudQuery,
890932
accessSpecifier));
891933
}
892934

@@ -895,14 +937,18 @@ private static List<CallSite> getCallSites(Optional<BlockStmt> callableBody) {
895937
String instantiatedType = resolveType(objectCreationExpr.getType());
896938

897939
// resolve arguments of the constructor call to types
898-
List<String> arguments = objectCreationExpr.getArguments().stream().map(SymbolTable::resolveExpression)
940+
List<String> argumentTypes = objectCreationExpr.getArguments().stream().map(SymbolTable::resolveExpression)
941+
.collect(Collectors.toList());
942+
943+
// get argument expressions for constructor call
944+
List<String> argumentExpressions = objectCreationExpr.getArguments().stream().map(Expression::toString)
899945
.collect(Collectors.toList());
900946

901947
// resolve callee and get signature
902948
String calleeSignature = "";
903949
try {
904-
calleeSignature = objectCreationExpr.resolve().getSignature();
905-
} catch (RuntimeException exception) {
950+
calleeSignature = getTypeErasureSignature(objectCreationExpr.resolve());
951+
} catch (Throwable exception) {
906952
Log.debug("Could not resolve constructor call: " + objectCreationExpr + ": " + exception.getMessage());
907953
}
908954

@@ -911,7 +957,7 @@ private static List<CallSite> getCallSites(Optional<BlockStmt> callableBody) {
911957
.add(createCallSite(objectCreationExpr, "<init>",
912958
objectCreationExpr.getScope().isPresent() ? objectCreationExpr.getScope().get().toString()
913959
: "",
914-
instantiatedType, arguments, instantiatedType, calleeSignature, false, true, null, null,
960+
instantiatedType, argumentTypes, argumentExpressions, instantiatedType, calleeSignature, false, true, null, null,
915961
AccessSpecifier.NONE));
916962
}
917963

@@ -962,17 +1008,24 @@ private static Optional<CRUDOperationType> findCRUDOperation(String declaringTyp
9621008
* @param calleeName
9631009
* @param receiverExpr
9641010
* @param receiverType
965-
* @param arguments
1011+
* @param argumentTypes
1012+
* @param argumentExpr
1013+
* @param returnType
1014+
* @param calleeSignature
9661015
* @param isStaticCall
9671016
* @param isConstructorCall
1017+
* @param crudOperation,
1018+
* @param crudQuery,
1019+
* @param accessSpecifier
9681020
* @return
9691021
*/
9701022
private static CallSite createCallSite(
9711023
Expression callExpr,
9721024
String calleeName,
9731025
String receiverExpr,
9741026
String receiverType,
975-
List<String> arguments,
1027+
List<String> argumentTypes,
1028+
List<String> argumentExpr,
9761029
String returnType,
9771030
String calleeSignature,
9781031
boolean isStaticCall,
@@ -998,7 +1051,8 @@ private static CallSite createCallSite(
9981051
callSite.setMethodName(calleeName);
9991052
callSite.setReceiverExpr(receiverExpr);
10001053
callSite.setReceiverType(receiverType);
1001-
callSite.setArgumentTypes(arguments);
1054+
callSite.setArgumentTypes(argumentTypes);
1055+
callSite.setArgumentExpr(argumentExpr);
10021056
callSite.setReturnType(returnType);
10031057
callSite.setCalleeSignature(calleeSignature);
10041058
callSite.setStaticCall(isStaticCall);
@@ -1039,7 +1093,7 @@ private static String resolveExpression(Expression expression) {
10391093
if (resolvedType.isReferenceType() || resolvedType.isUnionType()) {
10401094
return resolvedType.describe();
10411095
}
1042-
} catch (RuntimeException exception) {
1096+
} catch (Throwable exception) {
10431097
Log.debug("Could not resolve expression: " + expression + ": " + exception.getMessage());
10441098
unresolvedExpressions.add(expression.toString());
10451099
}
@@ -1060,7 +1114,7 @@ private static String resolveType(Type type) {
10601114
if (!unresolvedTypes.contains(type.asString())) {
10611115
try {
10621116
return type.resolve().describe();
1063-
} catch (RuntimeException e) {
1117+
} catch (Throwable e) {
10641118
Log.warn("Could not resolve type: " + type.asString() + ": " + e.getMessage());
10651119
unresolvedTypes.add(type.asString());
10661120
}
@@ -1079,6 +1133,20 @@ private static String resolveType(Type type) {
10791133
* project
10801134
* @throws IOException
10811135
*/
1136+
private static final String[] EXCLUDED_SOURCE_ROOTS = {
1137+
Paths.get("src", "test", "resources").toString(),
1138+
Paths.get("src", "it", "resources").toString(),
1139+
Paths.get("src", "xdocs-examples").toString()
1140+
};
1141+
private static boolean excludeSourceRoot(Path sourceRoot) {
1142+
for (String excludedSrcRoot : EXCLUDED_SOURCE_ROOTS) {
1143+
if (Pattern.compile(excludedSrcRoot).matcher(sourceRoot.toString()).find()) {
1144+
return true;
1145+
}
1146+
}
1147+
return false;
1148+
}
1149+
10821150
public static Pair<Map<String, JavaCompilationUnit>, Map<String, List<Problem>>> extractAll(Path projectRootPath)
10831151
throws IOException {
10841152
SymbolSolverCollectionStrategy symbolSolverCollectionStrategy = new SymbolSolverCollectionStrategy();
@@ -1088,6 +1156,9 @@ public static Pair<Map<String, JavaCompilationUnit>, Map<String, List<Problem>>>
10881156
Map<String, JavaCompilationUnit> symbolTable = new LinkedHashMap<>();
10891157
Map<String, List<Problem>> parseProblems = new HashMap<>();
10901158
for (SourceRoot sourceRoot : projectRoot.getSourceRoots()) {
1159+
if (excludeSourceRoot(sourceRoot.getRoot())) {
1160+
continue;
1161+
}
10911162
for (ParseResult<CompilationUnit> parseResult : sourceRoot.tryToParse()) {
10921163
if (parseResult.isSuccessful()) {
10931164
CompilationUnit compilationUnit = LexicalPreservingPrinter.setup(parseResult.getResult().get());

0 commit comments

Comments
 (0)