diff --git a/gradle.properties b/gradle.properties index 7ad95fa..2e81983 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=2.3.0 +version=2.3.1 diff --git a/src/main/java/com/ibm/cldk/CodeAnalyzer.java b/src/main/java/com/ibm/cldk/CodeAnalyzer.java index 1a1f54f..057fa5e 100644 --- a/src/main/java/com/ibm/cldk/CodeAnalyzer.java +++ b/src/main/java/com/ibm/cldk/CodeAnalyzer.java @@ -86,8 +86,8 @@ public class CodeAnalyzer implements Runnable { public static String projectRootPom; @Option(names = { "-a", - "--analysis-level" }, description = "Level of analysis to perform. Options: 1 (for just symbol table) or 2 (for call graph). Default: 1") - private static int analysisLevel = 1; + "--analysis-level" }, description = "Level of analysis to perform. Options: 1 (for just symbol table); 2 (for call graph). Default: 1") + public static int analysisLevel = 1; @Option(names = { "--include-test-classes" }, hidden = true, description = "Print logs to console.") public static boolean includeTestClasses = false; @@ -209,7 +209,7 @@ private static void analyze() throws Exception { // 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)); + combinedJsonObject.add("call_graph", gson.toJsonTree(sdgEdges)); } } // Cleanup library dependencies directory diff --git a/src/main/java/com/ibm/cldk/SymbolTable.java b/src/main/java/com/ibm/cldk/SymbolTable.java index 8783594..b1219e3 100644 --- a/src/main/java/com/ibm/cldk/SymbolTable.java +++ b/src/main/java/com/ibm/cldk/SymbolTable.java @@ -71,7 +71,6 @@ import com.ibm.cldk.javaee.utils.enums.CRUDOperationType; import com.ibm.cldk.javaee.utils.enums.CRUDQueryType; import com.ibm.cldk.utils.Log; -import org.jetbrains.annotations.NotNull; @SuppressWarnings("rawtypes") public class SymbolTable { @@ -241,7 +240,6 @@ private static JavaCompilationUnit processCompilationUnit(CompilationUnit parseR } else { // TODO: handle AnnotationDeclaration, RecordDeclaration // set the common type attributes only - Log.warn("Found unsupported type declaration: " + typeDecl.toString()); typeNode = new com.ibm.cldk.entities.Type(); } diff --git a/src/main/java/com/ibm/cldk/SystemDependencyGraph.java b/src/main/java/com/ibm/cldk/SystemDependencyGraph.java index 2bed573..ff8b988 100644 --- a/src/main/java/com/ibm/cldk/SystemDependencyGraph.java +++ b/src/main/java/com/ibm/cldk/SystemDependencyGraph.java @@ -52,6 +52,7 @@ import java.util.function.Supplier; import java.util.stream.Collectors; +import static com.ibm.cldk.CodeAnalyzer.analysisLevel; import static com.ibm.cldk.utils.AnalysisUtils.*; @@ -114,76 +115,13 @@ private static JSONExporter getGraphExporter( /** * Convert SDG to a formal Graph representation. * - * @param entryPoints - * @param sdg * @param callGraph - * @param edgeLabels * @return */ - private static org.jgrapht.Graph buildGraph( - Supplier> entryPoints, - Graph sdg, CallGraph callGraph, - BiFunction edgeLabels) { + private static org.jgrapht.Graph buildOnlyCallGraph(CallGraph callGraph) { org.jgrapht.Graph graph = new DefaultDirectedGraph<>( AbstractGraphEdge.class); - - // We'll use forward and backward search on the DFS to identify which CFG nodes - // are dominant - // This is a forward DFS search (or exit time first search) - int dfsNumber = 0; - Map dfsFinish = HashMapFactory.make(); - Iterator search = DFS.iterateFinishTime(sdg, entryPoints.get()); - - while (search.hasNext()) { - dfsFinish.put(search.next(), dfsNumber++); - } - - // This is a reverse DFS search (or entry time first search) - int reverseDfsNumber = 0; - Map dfsStart = HashMapFactory.make(); - Iterator reverseSearch = DFS.iterateDiscoverTime(sdg, entryPoints.get()); - - while (reverseSearch.hasNext()) { - dfsStart.put(reverseSearch.next(), reverseDfsNumber++); - } - - // Populate graph - sdg.stream() - .filter(dfsFinish::containsKey) - .sorted(Comparator.comparingInt(dfsFinish::get)) - .forEach(p -> sdg.getSuccNodes(p).forEachRemaining(s -> { - if (dfsFinish.containsKey(s) - && dfsStart.get(p) != null && dfsStart.get(s) != null - && !((dfsStart.get(p) >= dfsStart.get(s)) - && (dfsFinish.get(p) <= dfsFinish.get(s))) - && !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())); - // 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); - if (cgEdge == null || !cgEdge.equals(graphEdge)) { - graph.addEdge( - source_vertex, - target_vertex, - graphEdge); - } else { - graphEdge.incrementWeight(); - } - } - } - })); - callGraph.getEntrypointNodes() .forEach(p -> { // Get call statements that may execute in a given method @@ -264,7 +202,6 @@ public static List construct( try { System.setOut(new PrintStream(NullOutputStream.INSTANCE)); System.setErr(new PrintStream(NullOutputStream.INSTANCE)); -// builder = Util.makeRTABuilder(new JavaLanguage(), options, cache, cha); builder = Util.makeRTABuilder(options, cache, cha); callGraph = builder.makeCallGraph(options, null); } finally { @@ -283,40 +220,14 @@ public static List construct( } }); + org.jgrapht.Graph graph; + + graph = buildOnlyCallGraph(callGraph); - // Build SDG graph - Log.info("Building System Dependency Graph."); - SDG sdg = new SDG<>( - callGraph, - builder.getPointerAnalysis(), - new ModRef<>(), - Slicer.DataDependenceOptions.NO_HEAP_NO_EXCEPTIONS, - Slicer.ControlDependenceOptions.NO_EXCEPTIONAL_EDGES); - - // Prune the Graph to keep only application classes. - Graph prunedGraph = GraphSlicer.prune(sdg, - statement -> (statement.getNode() - .getMethod() - .getDeclaringClass() - .getClassLoader() - .getReference() - .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( - sdgEntryPointsSupplier, - prunedGraph, callGraph, - (p, s) -> String.valueOf(sdg.getEdgeLabels(p, s).iterator().next()) - ); - - List edges = sdgGraph.edgeSet().stream() + List edges = graph.edgeSet().stream() .map(abstractGraphEdge -> { - CallableVertex source = sdgGraph.getEdgeSource(abstractGraphEdge); - CallableVertex target = sdgGraph.getEdgeTarget(abstractGraphEdge); + CallableVertex source = graph.getEdgeSource(abstractGraphEdge); + CallableVertex target = graph.getEdgeTarget(abstractGraphEdge); if (abstractGraphEdge instanceof CallEdge) { return new CallDependency(source, target, abstractGraphEdge); } else { diff --git a/src/test/java/com/ibm/cldk/CodeAnalyzerIntegrationTest.java b/src/test/java/com/ibm/cldk/CodeAnalyzerIntegrationTest.java index 2fcbc83..1a45910 100644 --- a/src/test/java/com/ibm/cldk/CodeAnalyzerIntegrationTest.java +++ b/src/test/java/com/ibm/cldk/CodeAnalyzerIntegrationTest.java @@ -143,8 +143,8 @@ void callGraphShouldHaveKnownEdges() throws Exception { // Read the output JSON Gson gson = new Gson(); JsonObject jsonObject = gson.fromJson(runCodeAnalyzerOnCallGraphTest.getStdout(), JsonObject.class); - JsonArray systemDepGraph = jsonObject.getAsJsonArray("system_dependency_graph"); - Assertions.assertTrue(StreamSupport.stream(systemDepGraph.spliterator(), false) + JsonArray callGraph = jsonObject.getAsJsonArray("call_graph"); + Assertions.assertTrue(StreamSupport.stream(callGraph.spliterator(), false) .map(JsonElement::getAsJsonObject) .anyMatch(entry -> "CALL_DEP".equals(entry.get("type").getAsString()) &&