Skip to content

Commit fe59c40

Browse files
authored
Merge pull request #60 from IBM/1.1.0
1.1.0
2 parents e2bbf7d + 270a1d4 commit fe59c40

14 files changed

+293
-98
lines changed

build.gradle

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ dependencies {
7878

7979
implementation 'org.apache.logging.log4j:log4j-api:2.18.0'
8080
implementation 'org.apache.logging.log4j:log4j-core:2.18.0'
81-
def walaVersion = '1.6.6'
81+
def walaVersion = '1.6.7'
8282

8383
compileOnly 'org.projectlombok:lombok:1.18.30'
8484
annotationProcessor 'org.projectlombok:lombok:1.18.30'

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version=1.0.1
1+
version=1.1.0

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

+2-11
Original file line numberDiff line numberDiff line change
@@ -174,17 +174,8 @@ private static void analyze() throws Exception {
174174
build = build == null ? "auto" : build;
175175
// Is noBuild is true, we will not build the project
176176
build = noBuild ? null : build;
177-
String sdgAsJSONString = SystemDependencyGraph.construct(input, dependencies, build);
178-
JsonElement sdgAsJSONElement = gson.fromJson(sdgAsJSONString, JsonElement.class);
179-
JsonObject sdgAsJSONObject = sdgAsJSONElement.getAsJsonObject();
180-
JsonElement edges = sdgAsJSONObject.get("edges");
181-
182-
// We don't really need these fields, so we'll remove it.
183-
sdgAsJSONObject.remove("nodes");
184-
sdgAsJSONObject.remove("creator");
185-
sdgAsJSONObject.remove("version");
186-
// Remove the 'edges' element and move the list of edges up one level
187-
combinedJsonObject.add("system_dependency_graph", edges);
177+
List<Dependency> sdgEdges = SystemDependencyGraph.construct(input, dependencies, build);
178+
combinedJsonObject.add("system_dependency_graph", gson.toJsonTree(sdgEdges));
188179
}
189180
}
190181
// Cleanup library dependencies directory

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

+5-2
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ private static JavaCompilationUnit processCompilationUnit(CompilationUnit parseR
194194
typeNode.setCallableDeclarations(typeDecl.findAll(CallableDeclaration.class).stream()
195195
.filter(c -> c.getParentNode().isPresent() && c.getParentNode().get() == typeDecl)
196196
.map(meth -> {
197-
Pair<String, Callable> callableDeclaration = processCallableDeclaration(meth, fieldNames, typeName);
197+
Pair<String, Callable> callableDeclaration = processCallableDeclaration(meth, fieldNames, typeName, parseResult.getStorage().map(s -> s.getPath().toString()).orElse("<in-memory>"));
198198
declaredMethodsAndConstructors.put(typeName, callableDeclaration.getLeft(), callableDeclaration.getRight());
199199
return callableDeclaration;
200200
}).collect(Collectors.toMap(p -> p.getLeft(), p -> p.getRight())));
@@ -249,9 +249,12 @@ private static ParameterInCallable processParameterDeclaration(Parameter paramDe
249249
*/
250250
@SuppressWarnings("unchecked")
251251
private static Pair<String, Callable> processCallableDeclaration(CallableDeclaration callableDecl,
252-
List<String> classFields, String typeName) {
252+
List<String> classFields, String typeName, String filePath) {
253253
Callable callableNode = new Callable();
254254

255+
// Set file path
256+
callableNode.setFilePath(filePath);
257+
255258
// add callable signature
256259
callableNode.setSignature(callableDecl.getSignature().asString());
257260

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

+93-55
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
import com.ibm.cldk.entities.AbstractGraphEdge;
1717
import com.ibm.cldk.entities.CallEdge;
18-
import com.ibm.cldk.entities.Callable;
18+
import com.ibm.cldk.entities.CallableVertex;
1919
import com.ibm.cldk.entities.SystemDepEdge;
2020
import com.ibm.cldk.utils.AnalysisUtils;
2121
import com.ibm.cldk.utils.Log;
@@ -40,20 +40,60 @@
4040
import com.ibm.wala.util.graph.Graph;
4141
import com.ibm.wala.util.graph.GraphSlicer;
4242
import com.ibm.wala.util.graph.traverse.DFS;
43+
import lombok.Data;
44+
import lombok.EqualsAndHashCode;
4345
import org.apache.commons.io.output.NullOutputStream;
44-
import org.apache.commons.lang3.tuple.Pair;
4546
import org.jgrapht.graph.DefaultDirectedGraph;
4647
import org.jgrapht.nio.json.JSONExporter;
4748

4849
import java.io.IOException;
4950
import java.io.PrintStream;
50-
import java.io.StringWriter;
5151
import java.util.*;
5252
import java.util.function.BiFunction;
5353
import java.util.function.Supplier;
54-
55-
import static com.ibm.cldk.CodeAnalyzer.gson;
56-
import static com.ibm.cldk.utils.AnalysisUtils.*;
54+
import java.util.stream.Collectors;
55+
56+
import static com.ibm.cldk.utils.AnalysisUtils.createAndPutNewCallableInSymbolTable;
57+
import static com.ibm.cldk.utils.AnalysisUtils.getCallableFromSymbolTable;
58+
59+
60+
@Data
61+
abstract class Dependency {
62+
public CallableVertex source;
63+
public CallableVertex target;
64+
}
65+
66+
@Data
67+
@EqualsAndHashCode(callSuper = true)
68+
class SDGDependency extends Dependency {
69+
public String sourceKind;
70+
public String destinationKind;
71+
public String type;
72+
public String weight;
73+
74+
public SDGDependency(CallableVertex source, CallableVertex target, SystemDepEdge edge) {
75+
super.source = source;
76+
super.target = target;
77+
this.sourceKind = edge.getSourceKind();
78+
this.destinationKind = edge.getDestinationKind();
79+
this.type = edge.getType();
80+
this.weight = String.valueOf(edge.getWeight());
81+
}
82+
}
83+
84+
@Data
85+
@EqualsAndHashCode(callSuper = true)
86+
class CallDependency extends Dependency {
87+
public String type;
88+
public String weight;
89+
90+
public CallDependency(CallableVertex source, CallableVertex target, AbstractGraphEdge edge) {
91+
this.source = source;
92+
this.target = target;
93+
this.type = edge.toString();
94+
this.weight = String.valueOf(edge.getWeight());
95+
}
96+
}
5797

5898
/**
5999
* The type Sdg 2 json.
@@ -66,18 +106,10 @@ public class SystemDependencyGraph {
66106
* @return the graph exporter
67107
*/
68108

69-
70-
private static JSONExporter<Pair<String, Callable>, AbstractGraphEdge> getGraphExporter() {
71-
JSONExporter<Pair<String, Callable>, AbstractGraphEdge> exporter = new JSONExporter<>(
72-
pair -> {
73-
Map <String, String> vertex = new HashMap<>();
74-
vertex.put("class_interface_declarations", pair.getLeft());
75-
vertex.put("callable", gson.toJson(pair.getRight()));
76-
return gson.toJson(vertex);
77-
}
78-
);
79-
// exporter.setVertexAttributeProvider(v -> v.getRight().getAttributes());
109+
private static JSONExporter<CallableVertex, AbstractGraphEdge> getGraphExporter() {
110+
JSONExporter<CallableVertex, AbstractGraphEdge> exporter = new JSONExporter<>();
80111
exporter.setEdgeAttributeProvider(AbstractGraphEdge::getAttributes);
112+
exporter.setVertexAttributeProvider(CallableVertex::getAttributes);
81113
return exporter;
82114
}
83115

@@ -90,12 +122,12 @@ private static JSONExporter<Pair<String, Callable>, AbstractGraphEdge> getGraphE
90122
* @param edgeLabels
91123
* @return
92124
*/
93-
private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buildGraph(
125+
private static org.jgrapht.Graph<CallableVertex, AbstractGraphEdge> buildGraph(
94126
Supplier<Iterator<Statement>> entryPoints,
95127
Graph<Statement> sdg, CallGraph callGraph,
96128
BiFunction<Statement, Statement, String> edgeLabels) {
97129

98-
org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> graph = new DefaultDirectedGraph<>(
130+
org.jgrapht.Graph<CallableVertex, AbstractGraphEdge> graph = new DefaultDirectedGraph<>(
99131
AbstractGraphEdge.class);
100132

101133
// We'll use forward and backward search on the DFS to identify which CFG nodes
@@ -130,21 +162,22 @@ private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buil
130162
&& !p.getNode().getMethod().equals(s.getNode().getMethod())) {
131163

132164
// Add the source nodes to the graph as vertices
133-
Pair<String, Callable> source = Optional.ofNullable(getCallableFromSymbolTable(p.getNode().getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(p.getNode().getMethod()));
134-
graph.addVertex(source);
135-
165+
Map<String, String> source = Optional.ofNullable(getCallableFromSymbolTable(p.getNode().getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(p.getNode().getMethod()));
136166
// Add the target nodes to the graph as vertices
137-
Pair<String, Callable> target = Optional.ofNullable(getCallableFromSymbolTable(s.getNode().getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(s.getNode().getMethod()));
138-
graph.addVertex(target);
139-
140-
String edgeType = edgeLabels.apply(p, s);
141-
SystemDepEdge graphEdge = new SystemDepEdge(p, s, edgeType);
142-
SystemDepEdge cgEdge = (SystemDepEdge) graph.getEdge(source, target);
143-
if (source.getRight() != null && target.getRight() != null) {
167+
Map<String, String> target = Optional.ofNullable(getCallableFromSymbolTable(s.getNode().getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(s.getNode().getMethod()));
168+
169+
if (source != null && target != null) {
170+
CallableVertex source_vertex = new CallableVertex(source);
171+
CallableVertex target_vertex = new CallableVertex(target);
172+
graph.addVertex(source_vertex);
173+
graph.addVertex(target_vertex);
174+
String edgeType = edgeLabels.apply(p, s);
175+
SystemDepEdge graphEdge = new SystemDepEdge(p, s, edgeType);
176+
SystemDepEdge cgEdge = (SystemDepEdge) graph.getEdge(source_vertex, target_vertex);
144177
if (cgEdge == null || !cgEdge.equals(graphEdge)) {
145178
graph.addEdge(
146-
source,
147-
target,
179+
source_vertex,
180+
target_vertex,
148181
graphEdge);
149182
} else {
150183
graphEdge.incrementWeight();
@@ -163,21 +196,22 @@ private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buil
163196
.forEach(o -> {
164197

165198
// Add the source nodes to the graph as vertices
166-
Pair<String, Callable> source = Optional.ofNullable(getCallableFromSymbolTable(p.getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(p.getMethod()));
167-
graph.addVertex(source);
199+
Map<String, String> source = Optional.ofNullable(getCallableFromSymbolTable(p.getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(p.getMethod()));
200+
CallableVertex source_vertex = new CallableVertex(source);
168201

169202
// Add the target nodes to the graph as vertices
170-
Pair<String, Callable> target = Optional.ofNullable(getCallableFromSymbolTable(o.getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(o.getMethod()));
171-
graph.addVertex(target);
172-
173-
if (!source.equals(target) && source.getRight() != null && target.getRight() != null) {
203+
Map<String, String> target = Optional.ofNullable(getCallableFromSymbolTable(o.getMethod())).orElseGet(() -> createAndPutNewCallableInSymbolTable(o.getMethod()));
204+
CallableVertex target_vertex = new CallableVertex(target);
174205

206+
if (!source.equals(target) && target != null) {
175207
// Get the edge between the source and the target
176-
AbstractGraphEdge cgEdge = graph.getEdge(source, target);
208+
graph.addVertex(source_vertex);
209+
graph.addVertex(target_vertex);
210+
AbstractGraphEdge cgEdge = graph.getEdge(source_vertex, target_vertex);
177211
if (cgEdge instanceof CallEdge) {
178212
((CallEdge) cgEdge).incrementWeight();
179213
} else {
180-
graph.addEdge(source, target, new CallEdge());
214+
graph.addEdge(source_vertex, target_vertex, new CallEdge());
181215
}
182216
}
183217
});
@@ -192,15 +226,15 @@ private static org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> buil
192226
*
193227
* @param input the input
194228
* @param dependencies the dependencies
195-
* @param build The build options
229+
* @param build The build options
196230
* @return A List of triples containing the source, destination, and edge type
197231
* @throws IOException the io exception
198232
* @throws ClassHierarchyException the class hierarchy exception
199233
* @throws IllegalArgumentException the illegal argument exception
200234
* @throws CallGraphBuilderCancelException the call graph builder cancel
201235
* exception
202236
*/
203-
public static String construct(
237+
public static List<Dependency> construct(
204238
String input, String dependencies, String build)
205239
throws IOException, ClassHierarchyException, IllegalArgumentException, CallGraphBuilderCancelException {
206240

@@ -243,12 +277,7 @@ public static String construct(
243277
+ Math.ceil((double) (System.currentTimeMillis() - start_time) / 1000) + " seconds.");
244278

245279
// set cyclomatic complexity for callables in the symbol table
246-
callGraph.forEach(cgNode -> {
247-
Callable callable = getCallableFromSymbolTable(cgNode.getMethod()).getRight();
248-
if (callable != null) {
249-
callable.setCyclomaticComplexity(getCyclomaticComplexity(cgNode.getIR()));
250-
}
251-
});
280+
AnalysisUtils.setCyclomaticComplexity(callGraph);
252281

253282
// Build SDG graph
254283
Log.info("Building System Dependency Graph.");
@@ -266,22 +295,31 @@ public static String construct(
266295
.getDeclaringClass()
267296
.getClassLoader()
268297
.getReference()
269-
.equals(ClassLoaderReference.Application)));
298+
.equals(ClassLoaderReference.Application))
299+
);
270300

271301
// A supplier to get entries
272302
Supplier<Iterator<Statement>> sdgEntryPointsSupplier = () -> callGraph.getEntrypointNodes().stream()
273303
.map(n -> (Statement) new MethodEntryStatement(n)).iterator();
274304

275-
org.jgrapht.Graph<Pair<String, Callable>, AbstractGraphEdge> sdgGraph = buildGraph(
305+
org.jgrapht.Graph<CallableVertex, AbstractGraphEdge> sdgGraph = buildGraph(
276306
sdgEntryPointsSupplier,
277307
prunedGraph, callGraph,
278-
(p, s) -> String.valueOf(sdg.getEdgeLabels(p, s).iterator().next()));
279-
280-
JSONExporter<Pair<String, Callable>, AbstractGraphEdge> graphExporter = getGraphExporter();
308+
(p, s) -> String.valueOf(sdg.getEdgeLabels(p, s).iterator().next())
309+
);
281310

282-
StringWriter sdgWriter = new StringWriter();
283-
graphExporter.exportGraph(sdgGraph, sdgWriter);
311+
List<Dependency> edges = sdgGraph.edgeSet().stream()
312+
.map(abstractGraphEdge -> {
313+
CallableVertex source = sdgGraph.getEdgeSource(abstractGraphEdge);
314+
CallableVertex target = sdgGraph.getEdgeTarget(abstractGraphEdge);
315+
if (abstractGraphEdge instanceof CallEdge) {
316+
return new CallDependency(source, target, abstractGraphEdge);
317+
} else {
318+
return new SDGDependency(source, target, (SystemDepEdge) abstractGraphEdge);
319+
}
320+
})
321+
.collect(Collectors.toList());
284322

285-
return sdgWriter.toString();
323+
return edges;
286324
}
287325
}

src/main/java/com/ibm/cldk/entities/AbstractGraphEdge.java

+21-19
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,34 @@
1818
import com.ibm.wala.shrike.shrikeCT.InvalidClassFileException;
1919
import com.ibm.wala.ssa.IR;
2020
import com.ibm.wala.ssa.SSAInstruction;
21+
import lombok.Getter;
2122
import org.jgrapht.nio.Attribute;
22-
2323
import java.io.Serializable;
2424
import java.util.Map;
2525

26+
import static com.ibm.cldk.CodeAnalyzer.gson;
27+
2628
/**
2729
* The type Abstract graph edge.
2830
*/
31+
@Getter
2932
public abstract class AbstractGraphEdge implements Serializable {
3033
/**
3134
* The Context.
35+
* -- GETTER --
36+
* Gets context.
37+
*
38+
* @return the context
39+
3240
*/
3341
public final String context;
3442
/**
3543
* The Weight.
44+
* -- GETTER --
45+
* Gets weight.
46+
*
47+
* @return the weight
48+
3649
*/
3750
public Integer weight = 1;
3851

@@ -59,15 +72,6 @@ public void incrementWeight() {
5972
this.weight += 1;
6073
}
6174

62-
/**
63-
* Gets context.
64-
*
65-
* @return the context
66-
*/
67-
public String getContext() {
68-
return this.context;
69-
}
70-
7175
/**
7276
* Gets id.
7377
*
@@ -77,15 +81,6 @@ public Integer getId() {
7781
return this.hashCode();
7882
}
7983

80-
/**
81-
* Gets weight.
82-
*
83-
* @return the weight
84-
*/
85-
public Integer getWeight() {
86-
return this.weight;
87-
}
88-
8984
/**
9085
* Gets statement position.
9186
*
@@ -112,10 +107,17 @@ Integer getStatementPosition(Statement statement) {
112107
return pos;
113108
}
114109

110+
@Override
111+
public String toString() {
112+
return gson.toJson(this);
113+
}
114+
115115
/**
116116
* Gets attributes.
117117
*
118118
* @return the attributes
119119
*/
120120
public abstract Map<String, Attribute> getAttributes();
121+
122+
public abstract Map<String, String> getAttributesMap();
121123
}

0 commit comments

Comments
 (0)