diff --git a/src/main/java/com/ibm/cldk/CodeAnalyzer.java b/src/main/java/com/ibm/cldk/CodeAnalyzer.java index 413c641b..72190251 100644 --- a/src/main/java/com/ibm/cldk/CodeAnalyzer.java +++ b/src/main/java/com/ibm/cldk/CodeAnalyzer.java @@ -82,158 +82,167 @@ public class CodeAnalyzer implements Runnable { private static final String outputFileName = "analysis.json"; public static Gson gson = new GsonBuilder() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .setPrettyPrinting() - .disableHtmlEscaping() - .create(); - /** - * The entry point of application. - * - * @param args the input arguments - */ - public static void main(String[] args) { - int exitCode = new CommandLine(new CodeAnalyzer()).execute(args); - System.exit(exitCode); - } + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .setPrettyPrinting() + .disableHtmlEscaping() + .create(); + /** + * The entry point of application. + * + * @param args the input arguments + */ + public static void main(String[] args) { + int exitCode = new CommandLine(new CodeAnalyzer()).execute(args); + System.exit(exitCode); + } - @Override - public void run() { - // Set log level based on quiet option - Log.setVerbosity(verbose); - try { - analyze(); - } catch (Exception e) { - throw new RuntimeException(e); + @Override + public void run() { + // Set log level based on quiet option + Log.setVerbosity(verbose); + try { + analyze(); + } catch (Exception e) { + throw new RuntimeException(e); + } } - } - private static void analyze() throws Exception { - - JsonObject combinedJsonObject = new JsonObject(); - Map symbolTable; - projectRootPom = projectRootPom == null ? input : projectRootPom; - // First of all if, sourceAnalysis is provided, we will analyze the source code instead of the project. - if (sourceAnalysis != null) { - // Construct symbol table for source code - Log.debug("Single file analysis."); - Pair, Map>> symbolTableExtractionResult = SymbolTable.extractSingle(sourceAnalysis); - symbolTable = symbolTableExtractionResult.getLeft(); - } else { - // download library dependencies of project for type resolution - String dependencies = null; - try {if (BuildProject.downloadLibraryDependencies(input, projectRootPom)) { - dependencies = String.valueOf(BuildProject.libDownloadPath); + private static void analyze() throws Exception { + + JsonObject combinedJsonObject = new JsonObject(); + Map symbolTable; + projectRootPom = projectRootPom == null ? input : projectRootPom; + // First of all if, sourceAnalysis is provided, we will analyze the source code instead of the project. + if (sourceAnalysis != null) { + // Construct symbol table for source code + Log.debug("Single file analysis."); + Pair, Map>> symbolTableExtractionResult = SymbolTable.extractSingle(sourceAnalysis); + symbolTable = symbolTableExtractionResult.getLeft(); } else { - Log.warn("Failed to download library dependencies of project"); - } - } catch (IllegalStateException illegalStateException) { - Log.warn("Failed to download library dependencies of project"); - } + // download library dependencies of project for type resolution + String dependencies = null; + try {if (BuildProject.downloadLibraryDependencies(input, projectRootPom)) { + dependencies = String.valueOf(BuildProject.libDownloadPath); + } else { + Log.warn("Failed to download library dependencies of project"); + } + } catch (IllegalStateException illegalStateException) { + Log.warn("Failed to download library dependencies of project"); + } - boolean analysisFileExists = output != null && Files.exists(Paths.get(output + File.separator + outputFileName)); + boolean analysisFileExists = output != null && Files.exists(Paths.get(output + File.separator + outputFileName)); - // if target files are specified, compute symbol table information for the given files - if (targetFiles != null) { - Log.info(targetFiles.size() + "target files specified for analysis: " + targetFiles); + // if target files are specified, compute symbol table information for the given files + if (targetFiles != null) { + Log.info(targetFiles.size() + "target files specified for analysis: " + targetFiles); - // if target files specified for analysis level 2, downgrade to analysis level 1 - if (analysisLevel > 1) { - Log.warn("Incremental analysis is supported at analysis level 1 only; " + - "performing analysis level 1 for target files"); - analysisLevel = 1; - } + // if target files specified for analysis level 2, downgrade to analysis level 1 + if (analysisLevel > 1) { + Log.warn("Incremental analysis is supported at analysis level 1 only; " + + "performing analysis level 1 for target files"); + analysisLevel = 1; + } - // Previous code was pointing to toList, which has been introduced in Java 16 - // symbolTable = SymbolTable.extract(Paths.get(input), targetFiles.stream().map(Paths::get).toList()).getLeft(); - // extract symbol table for the specified files - symbolTable = SymbolTable.extract(Paths.get(input), targetFiles.stream().map(Paths::get).collect(Collectors.toList())).getLeft(); - - // if analysis file exists, update it with new symbol table information for the specified fiels - if (analysisFileExists) { - // read symbol table information from existing analysis file - Map existingSymbolTable = readSymbolTableFromFile( - new File(output, outputFileName)); - if (existingSymbolTable != null) { - // for each file, tag its symbol table information as "updated" and update existing symbol table - for (String targetFile : targetFiles) { - String targetPathAbs = Paths.get(targetFile).toAbsolutePath().toString(); - JavaCompilationUnit javaCompilationUnit = symbolTable.get(targetPathAbs); - javaCompilationUnit.setModified(true); - existingSymbolTable.put(targetPathAbs, javaCompilationUnit); + // Previous code was pointing to toList, which has been introduced in Java 16 + // symbolTable = SymbolTable.extract(Paths.get(input), targetFiles.stream().map(Paths::get).toList()).getLeft(); + // extract symbol table for the specified files + symbolTable = SymbolTable.extract(Paths.get(input), targetFiles.stream().map(Paths::get).collect(Collectors.toList())).getLeft(); + + // if analysis file exists, update it with new symbol table information for the specified fiels + if (analysisFileExists) { + // read symbol table information from existing analysis file + Map existingSymbolTable = readSymbolTableFromFile( + new File(output, outputFileName)); + if (existingSymbolTable != null) { + // for each file, tag its symbol table information as "updated" and update existing symbol table + for (String targetFile : targetFiles) { + String targetPathAbs = Paths.get(targetFile).toAbsolutePath().toString(); + JavaCompilationUnit javaCompilationUnit = symbolTable.get(targetPathAbs); + javaCompilationUnit.setModified(true); + existingSymbolTable.put(targetPathAbs, javaCompilationUnit); + } } + symbolTable = existingSymbolTable; } - symbolTable = existingSymbolTable; } - } - else { - // construct symbol table for project, write parse problems to file in output directory if specified - Pair, Map>> symbolTableExtractionResult = - SymbolTable.extractAll(Paths.get(input)); + else { + // construct symbol table for project, write parse problems to file in output directory if specified + Pair, Map>> symbolTableExtractionResult = + SymbolTable.extractAll(Paths.get(input)); - symbolTable = symbolTableExtractionResult.getLeft(); - } + symbolTable = symbolTableExtractionResult.getLeft(); + } - if (analysisLevel > 1) { - // Save SDG, and Call graph as JSON - // If noBuild is not true, and build is also not provided, we will use "auto" as the build command - build = build == null ? "auto" : build; - // Is noBuild is true, we will not build the project - build = noBuild ? null : build; - List sdgEdges = SystemDependencyGraph.construct(input, dependencies, build); - combinedJsonObject.add("system_dependency_graph", gson.toJsonTree(sdgEdges)); + if (analysisLevel > 1) { + // Save SDG, and Call graph as JSON + // If noBuild is not true, and build is also not provided, we will use "auto" as the build command + build = build == null ? "auto" : build; + // Is noBuild is true, we will not build the project + build = noBuild ? null : build; + String sdgAsJSONString = SystemDependencyGraph.construct(input, dependencies, build); + JsonElement sdgAsJSONElement = gson.fromJson(sdgAsJSONString, JsonElement.class); + JsonObject sdgAsJSONObject = sdgAsJSONElement.getAsJsonObject(); + JsonElement edges = sdgAsJSONObject.get("edges"); + + // We don't really need these fields, so we'll remove it. + sdgAsJSONObject.remove("nodes"); + sdgAsJSONObject.remove("creator"); + sdgAsJSONObject.remove("version"); + // Remove the 'edges' element and move the list of edges up one level + combinedJsonObject.add("system_dependency_graph", edges); + } } + // Cleanup library dependencies directory + BuildProject.cleanLibraryDependencies(); + + // Convert the JavaCompilationUnit to JSON and add to consolidated json object + String symbolTableJSONString = gson.toJson(symbolTable); + JsonElement symbolTableJSON = gson.fromJson(symbolTableJSONString, JsonElement.class); + combinedJsonObject.add("symbol_table", symbolTableJSON); + + // Add version number to the output JSON + try { + String[] versions = new VersionProvider().getVersion(); + if (versions.length > 0) { + combinedJsonObject.addProperty("version", versions[0]); + } else { + combinedJsonObject.addProperty("version", "unknown"); + } + } catch (Exception e) { + combinedJsonObject.addProperty("version", "error retrieving version"); + } + String consolidatedJSONString = gson.toJson(combinedJsonObject); + emit(consolidatedJSONString); } - // Cleanup library dependencies directory - BuildProject.cleanLibraryDependencies(); - - // Convert the JavaCompilationUnit to JSON and add to consolidated json object - String symbolTableJSONString = gson.toJson(symbolTable); - JsonElement symbolTableJSON = gson.fromJson(symbolTableJSONString, JsonElement.class); - combinedJsonObject.add("symbol_table", symbolTableJSON); - - // Add version number to the output JSON - try { - String[] versions = new VersionProvider().getVersion(); - if (versions.length > 0) { - combinedJsonObject.addProperty("version", versions[0]); + + private static void emit(String consolidatedJSONString) throws IOException { + if (output == null) { + System.out.println(consolidatedJSONString); } else { - combinedJsonObject.addProperty("version", "unknown"); + Path outputPath = Paths.get(output); + if (!Files.exists(outputPath)) { + Files.createDirectories(outputPath); + } + // If output is not null, export to a file + File file = new File(output, "analysis.json"); + try (FileWriter fileWriter = new FileWriter(file)) { + fileWriter.write(consolidatedJSONString); + Log.done("Analysis output saved at " + output); + } catch (IOException e) { + Log.error("Error writing to file: " + e.getMessage()); + } } - } catch (Exception e) { - combinedJsonObject.addProperty("version", "error retrieving version"); } - String consolidatedJSONString = gson.toJson(combinedJsonObject); - emit(consolidatedJSONString); - } - private static void emit(String consolidatedJSONString) throws IOException { - if (output == null) { - System.out.println(consolidatedJSONString); - } else { - Path outputPath = Paths.get(output); - if (!Files.exists(outputPath)) { - Files.createDirectories(outputPath); - } - // If output is not null, export to a file - File file = new File(output, "analysis.json"); - try (FileWriter fileWriter = new FileWriter(file)) { - fileWriter.write(consolidatedJSONString); - Log.done("Analysis output saved at " + output); + private static Map readSymbolTableFromFile(File analysisJsonFile) { + Type symbolTableType = new TypeToken>() {}.getType(); + try (FileReader reader = new FileReader(analysisJsonFile)) { + JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); + return gson.fromJson(jsonObject.get("symbol_table"), symbolTableType); } catch (IOException e) { - Log.error("Error writing to file: " + e.getMessage()); + Log.error("Error reading analysis file: " + e.getMessage()); } + return null; } - } - - private static Map readSymbolTableFromFile(File analysisJsonFile) { - Type symbolTableType = new TypeToken>() {}.getType(); - try (FileReader reader = new FileReader(analysisJsonFile)) { - JsonObject jsonObject = JsonParser.parseReader(reader).getAsJsonObject(); - return gson.fromJson(jsonObject.get("symbol_table"), symbolTableType); - } catch (IOException e) { - Log.error("Error reading analysis file: " + e.getMessage()); - } - return null; - } } \ No newline at end of file diff --git a/src/main/java/com/ibm/cldk/SystemDependencyGraph.java b/src/main/java/com/ibm/cldk/SystemDependencyGraph.java index b8bc0c2a..f252d01d 100644 --- a/src/main/java/com/ibm/cldk/SystemDependencyGraph.java +++ b/src/main/java/com/ibm/cldk/SystemDependencyGraph.java @@ -15,7 +15,7 @@ import com.ibm.cldk.entities.AbstractGraphEdge; import com.ibm.cldk.entities.CallEdge; -import com.ibm.cldk.entities.CallableVertex; +import com.ibm.cldk.entities.Callable; import com.ibm.cldk.entities.SystemDepEdge; import com.ibm.cldk.utils.AnalysisUtils; import com.ibm.cldk.utils.Log; @@ -40,60 +40,20 @@ import com.ibm.wala.util.graph.Graph; import com.ibm.wala.util.graph.GraphSlicer; import com.ibm.wala.util.graph.traverse.DFS; -import lombok.Data; -import lombok.EqualsAndHashCode; import org.apache.commons.io.output.NullOutputStream; +import org.apache.commons.lang3.tuple.Pair; import org.jgrapht.graph.DefaultDirectedGraph; import org.jgrapht.nio.json.JSONExporter; import java.io.IOException; import java.io.PrintStream; +import java.io.StringWriter; import java.util.*; import java.util.function.BiFunction; import java.util.function.Supplier; -import java.util.stream.Collectors; - -import static com.ibm.cldk.utils.AnalysisUtils.createAndPutNewCallableInSymbolTable; -import static com.ibm.cldk.utils.AnalysisUtils.getCallableFromSymbolTable; - - -@Data -abstract class Dependency { - public CallableVertex source; - public CallableVertex target; -} - -@Data -@EqualsAndHashCode(callSuper = true) -class SDGDependency extends Dependency { - public String sourceKind; - public String destinationKind; - public String type; - public String weight; - - public SDGDependency(CallableVertex source, CallableVertex target, SystemDepEdge edge) { - super.source = source; - super.target = target; - this.sourceKind = edge.getSourceKind(); - this.destinationKind = edge.getDestinationKind(); - this.type = edge.getType(); - this.weight = String.valueOf(edge.getWeight()); - } -} - -@Data -@EqualsAndHashCode(callSuper = true) -class CallDependency extends Dependency { - public String type; - public String weight; - - public CallDependency(CallableVertex source, CallableVertex target, AbstractGraphEdge edge) { - this.source = source; - this.target = target; - this.type = edge.toString(); - this.weight = String.valueOf(edge.getWeight()); - } -} + +import static com.ibm.cldk.CodeAnalyzer.gson; +import static com.ibm.cldk.utils.AnalysisUtils.*; /** * The type Sdg 2 json. @@ -106,10 +66,18 @@ public class SystemDependencyGraph { * @return the graph exporter */ - private static JSONExporter getGraphExporter() { - JSONExporter exporter = new JSONExporter<>(); + + private static JSONExporter, AbstractGraphEdge> getGraphExporter() { + JSONExporter, AbstractGraphEdge> exporter = new JSONExporter<>( + pair -> { + Map vertex = new HashMap<>(); + vertex.put("class_interface_declarations", pair.getLeft()); + vertex.put("callable", gson.toJson(pair.getRight())); + return gson.toJson(vertex); + } + ); +// exporter.setVertexAttributeProvider(v -> v.getRight().getAttributes()); exporter.setEdgeAttributeProvider(AbstractGraphEdge::getAttributes); - exporter.setVertexAttributeProvider(CallableVertex::getAttributes); return exporter; } @@ -122,12 +90,12 @@ private static JSONExporter getGraphExporter( * @param edgeLabels * @return */ - private static org.jgrapht.Graph buildGraph( + private static org.jgrapht.Graph, AbstractGraphEdge> buildGraph( Supplier> entryPoints, Graph sdg, CallGraph callGraph, BiFunction edgeLabels) { - org.jgrapht.Graph graph = new DefaultDirectedGraph<>( + org.jgrapht.Graph, AbstractGraphEdge> graph = new DefaultDirectedGraph<>( AbstractGraphEdge.class); // We'll use forward and backward search on the DFS to identify which CFG nodes @@ -162,22 +130,21 @@ private static org.jgrapht.Graph buildGraph( && !p.getNode().getMethod().equals(s.getNode().getMethod())) { // Add the source nodes to the graph as vertices - Map source = Optional.ofNullable(getCallableFromSymbolTable(p.getNode().getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(p.getNode().getMethod())); + Pair source = Optional.ofNullable(getCallableFromSymbolTable(p.getNode().getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(p.getNode().getMethod())); + graph.addVertex(source); + // Add the target nodes to the graph as vertices - Map target = Optional.ofNullable(getCallableFromSymbolTable(s.getNode().getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(s.getNode().getMethod())); - - if (source != null && target != null) { - CallableVertex source_vertex = new CallableVertex(source); - CallableVertex target_vertex = new CallableVertex(target); - graph.addVertex(source_vertex); - graph.addVertex(target_vertex); - String edgeType = edgeLabels.apply(p, s); - SystemDepEdge graphEdge = new SystemDepEdge(p, s, edgeType); - SystemDepEdge cgEdge = (SystemDepEdge) graph.getEdge(source_vertex, target_vertex); + Pair target = Optional.ofNullable(getCallableFromSymbolTable(s.getNode().getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(s.getNode().getMethod())); + graph.addVertex(target); + + String edgeType = edgeLabels.apply(p, s); + SystemDepEdge graphEdge = new SystemDepEdge(p, s, edgeType); + SystemDepEdge cgEdge = (SystemDepEdge) graph.getEdge(source, target); + if (source.getRight() != null && target.getRight() != null) { if (cgEdge == null || !cgEdge.equals(graphEdge)) { graph.addEdge( - source_vertex, - target_vertex, + source, + target, graphEdge); } else { graphEdge.incrementWeight(); @@ -196,22 +163,21 @@ private static org.jgrapht.Graph buildGraph( .forEach(o -> { // Add the source nodes to the graph as vertices - Map source = Optional.ofNullable(getCallableFromSymbolTable(p.getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(p.getMethod())); - CallableVertex source_vertex = new CallableVertex(source); + Pair source = Optional.ofNullable(getCallableFromSymbolTable(p.getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(p.getMethod())); + graph.addVertex(source); // Add the target nodes to the graph as vertices - Map target = Optional.ofNullable(getCallableFromSymbolTable(o.getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(o.getMethod())); - CallableVertex target_vertex = new CallableVertex(target); + Pair target = Optional.ofNullable(getCallableFromSymbolTable(o.getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(o.getMethod())); + graph.addVertex(target); + + if (!source.equals(target) && source.getRight() != null && target.getRight() != null) { - if (!source.equals(target) && target != null) { // Get the edge between the source and the target - graph.addVertex(source_vertex); - graph.addVertex(target_vertex); - AbstractGraphEdge cgEdge = graph.getEdge(source_vertex, target_vertex); + AbstractGraphEdge cgEdge = graph.getEdge(source, target); if (cgEdge instanceof CallEdge) { ((CallEdge) cgEdge).incrementWeight(); } else { - graph.addEdge(source_vertex, target_vertex, new CallEdge()); + graph.addEdge(source, target, new CallEdge()); } } }); @@ -226,7 +192,7 @@ private static org.jgrapht.Graph buildGraph( * * @param input the input * @param dependencies the dependencies - * @param build The build options + * @param build The build options * @return A List of triples containing the source, destination, and edge type * @throws IOException the io exception * @throws ClassHierarchyException the class hierarchy exception @@ -234,7 +200,7 @@ private static org.jgrapht.Graph buildGraph( * @throws CallGraphBuilderCancelException the call graph builder cancel * exception */ - public static List construct( + public static String construct( String input, String dependencies, String build) throws IOException, ClassHierarchyException, IllegalArgumentException, CallGraphBuilderCancelException { @@ -277,7 +243,12 @@ public static List construct( + Math.ceil((double) (System.currentTimeMillis() - start_time) / 1000) + " seconds."); // set cyclomatic complexity for callables in the symbol table - AnalysisUtils.setCyclomaticComplexity(callGraph); + callGraph.forEach(cgNode -> { + Callable callable = getCallableFromSymbolTable(cgNode.getMethod()).getRight(); + if (callable != null) { + callable.setCyclomaticComplexity(getCyclomaticComplexity(cgNode.getIR())); + } + }); // Build SDG graph Log.info("Building System Dependency Graph."); @@ -295,31 +266,22 @@ public static List construct( .getDeclaringClass() .getClassLoader() .getReference() - .equals(ClassLoaderReference.Application)) - ); + .equals(ClassLoaderReference.Application))); // A supplier to get entries Supplier> sdgEntryPointsSupplier = () -> callGraph.getEntrypointNodes().stream() .map(n -> (Statement) new MethodEntryStatement(n)).iterator(); - org.jgrapht.Graph sdgGraph = buildGraph( + org.jgrapht.Graph, AbstractGraphEdge> sdgGraph = buildGraph( sdgEntryPointsSupplier, prunedGraph, callGraph, - (p, s) -> String.valueOf(sdg.getEdgeLabels(p, s).iterator().next()) - ); + (p, s) -> String.valueOf(sdg.getEdgeLabels(p, s).iterator().next())); - List edges = sdgGraph.edgeSet().stream() - .map(abstractGraphEdge -> { - CallableVertex source = sdgGraph.getEdgeSource(abstractGraphEdge); - CallableVertex target = sdgGraph.getEdgeTarget(abstractGraphEdge); - if (abstractGraphEdge instanceof CallEdge) { - return new CallDependency(source, target, abstractGraphEdge); - } else { - return new SDGDependency(source, target, (SystemDepEdge) abstractGraphEdge); - } - }) - .collect(Collectors.toList()); + JSONExporter, AbstractGraphEdge> graphExporter = getGraphExporter(); + + StringWriter sdgWriter = new StringWriter(); + graphExporter.exportGraph(sdgGraph, sdgWriter); - return edges; + return sdgWriter.toString(); } } \ No newline at end of file diff --git a/src/main/java/com/ibm/cldk/utils/AnalysisUtils.java b/src/main/java/com/ibm/cldk/utils/AnalysisUtils.java index d69ca1b5..a9e3e8f3 100644 --- a/src/main/java/com/ibm/cldk/utils/AnalysisUtils.java +++ b/src/main/java/com/ibm/cldk/utils/AnalysisUtils.java @@ -19,7 +19,6 @@ import com.ibm.cldk.entities.ParameterInCallable; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IMethod; -import com.ibm.wala.ipa.callgraph.CallGraph; import com.ibm.wala.ipa.callgraph.Entrypoint; import com.ibm.wala.ipa.callgraph.impl.DefaultEntrypoint; import com.ibm.wala.ipa.cha.IClassHierarchy; @@ -45,7 +44,7 @@ public class AnalysisUtils { /** * The constant classAttr. */ - public static Map createAndPutNewCallableInSymbolTable(IMethod method) { + public static Pair createAndPutNewCallableInSymbolTable(IMethod method) { // Get the class name, with a . representation. String declaringClassSignature = method.getDeclaringClass().getName().toString().substring(1).replace("/", ".").replace("$", "."); @@ -58,13 +57,11 @@ public static Map createAndPutNewCallableInSymbolTable(IMethod m String methodSignature = String.join("", methodName, "(", String.join(", ", Optional.of(arguments).orElseGet(Collections::emptyList)), ")"); Callable newCallable = new Callable(); - newCallable.setFilePath(""); newCallable.setImplicit(true); newCallable.setConstructor(methodName.contains("")); newCallable.setComment(""); newCallable.setModifiers(Stream.of(method.isPublic() ? "public" : null, method.isProtected() ? "protected" : null, method.isPrivate() ? "private" : null, method.isAbstract() ? "abstract" : null, method.isStatic() ? "static" : null, method.isFinal() ? "final" : null, method.isSynchronized() ? "synchronized" : null, method.isNative() ? "native" : null, method.isSynthetic() ? "synthetic" : null, method.isBridge() ? "bridge" : null).filter(Objects::nonNull).collect(Collectors.toList())); newCallable.setCode(""); - newCallable.setSignature(methodSignature); newCallable.setDeclaration(methodSignature); newCallable.setEndLine(-1); newCallable.setStartLine(-1); @@ -80,18 +77,8 @@ public static Map createAndPutNewCallableInSymbolTable(IMethod m newCallable.setAnnotations(method.getAnnotations().stream().map(annotation -> annotation.toString().replace("[", "(").replace("]", ")").replace("Annotation type ", "@")).collect(Collectors.toList())); declaredMethodsAndConstructors.put(declaringClassSignature, methodSignature, newCallable); - String signature = newCallable.getSignature(); - if (signature.contains("")) { - signature = signature.replace("", declaringClassSignature.substring(declaringClassSignature.lastIndexOf(".") + 1)); - } else if (signature.contains("")) { - signature = signature.replace("", declaringClassSignature.substring(declaringClassSignature.lastIndexOf(".") + 1)); - } - return Map.ofEntries( - Map.entry("typeDeclaration", declaringClassSignature), - Map.entry("filePath", "<>"), - Map.entry("signature", signature), - Map.entry("callableDeclaration", newCallable.getDeclaration()) - ); + + return Pair.of(declaringClassSignature, newCallable); } /** @@ -117,24 +104,8 @@ public static int getCyclomaticComplexity(IR ir) { return conditionalBranchCount + switchBranchCount + catchBlockCount + 1; } - public static void setCyclomaticComplexity(CallGraph callGraph) { - callGraph.forEach( - cgNode -> { - if (cgNode.getMethod() != null) { - IMethod method = cgNode.getMethod(); - String declaringClassSignature = method.getDeclaringClass().getName().toString().substring(1).replace("/", ".").replace("$", "."); - List arguments = Arrays.stream(Type.getMethodType(method.getDescriptor().toString()).getArgumentTypes()).map(Type::getClassName).collect(Collectors.toList()); - String methodSignature = String.join("", method.getName().toString(), "(", String.join(", ", Optional.of(arguments).orElseGet(Collections::emptyList)), ")"); - Callable callable = declaredMethodsAndConstructors.get(declaringClassSignature, methodSignature); - if (callable != null) { - callable.setCyclomaticComplexity(getCyclomaticComplexity(cgNode.getIR())); - } - } - } - ); - } + public static Pair getCallableFromSymbolTable(IMethod method) { - public static Map getCallableFromSymbolTable(IMethod method) { // Get the class name, with a . representation. String declaringClassSignature = method.getDeclaringClass().getName().toString().substring(1).replace("/", ".").replace("$", "."); @@ -143,24 +114,8 @@ public static Map getCallableFromSymbolTable(IMethod method) { // Get the method signature. String methodSignature = String.join("", method.getName().toString(), "(", String.join(", ", Optional.of(arguments).orElseGet(Collections::emptyList)), ")"); - Callable callable = declaredMethodsAndConstructors.get(declaringClassSignature, methodSignature); - - if (callable == null) - return null; - else{ - String signature = callable.getSignature(); - if (signature.contains("")) { - signature = signature.replace("", declaringClassSignature.substring(declaringClassSignature.lastIndexOf(".") + 1)); - } else if (signature.contains("")) { - signature = signature.replace("", declaringClassSignature.substring(declaringClassSignature.lastIndexOf(".") + 1)); - } - return Map.ofEntries( - Map.entry("typeDeclaration", declaringClassSignature), - Map.entry("filePath", callable.getFilePath()), - Map.entry("signature", signature), - Map.entry("callableDeclaration", callable.getSignature()) - ); - } + + return Pair.of(declaringClassSignature, declaredMethodsAndConstructors.get(declaringClassSignature, methodSignature)); } /**