Skip to content

Commit fa1c1ee

Browse files
authored
Fix missing edges when converting cs callgraph to ci callgraph (#190)
1 parent 8247d11 commit fa1c1ee

File tree

2 files changed

+106
-2
lines changed

2 files changed

+106
-2
lines changed

src/main/java/pascal/taie/analysis/pta/core/cs/CSCallGraph.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,15 @@ public Stream<Edge<CSCallSite, CSMethod>> edgesInTo(CSMethod csMethod) {
129129
@Override
130130
public Stream<Edge<CSCallSite, CSMethod>> edges() {
131131
return reachableMethods.stream()
132-
.flatMap(this::callSitesIn)
133-
.flatMap(this::edgesOutOf);
132+
.flatMap(this::edgesInTo);
133+
}
134+
135+
/**
136+
* @implNote This implementation may be inefficient, please use with care
137+
*/
138+
@Override
139+
public int getNumberOfEdges() {
140+
return Math.toIntExact(edges().count());
134141
}
135142

136143
@Override
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Tai-e: A Static Analysis Framework for Java
3+
*
4+
* Copyright (C) 2022 Tian Tan <[email protected]>
5+
* Copyright (C) 2022 Yue Li <[email protected]>
6+
*
7+
* This file is part of Tai-e.
8+
*
9+
* Tai-e is free software: you can redistribute it and/or modify
10+
* it under the terms of the GNU Lesser General Public License
11+
* as published by the Free Software Foundation, either version 3
12+
* of the License, or (at your option) any later version.
13+
*
14+
* Tai-e is distributed in the hope that it will be useful,but WITHOUT
15+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16+
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
17+
* Public License for more details.
18+
*
19+
* You should have received a copy of the GNU Lesser General Public
20+
* License along with Tai-e. If not, see <https://www.gnu.org/licenses/>.
21+
*/
22+
23+
package pascal.taie.analysis.graph.callgraph;
24+
25+
import org.junit.jupiter.params.ParameterizedTest;
26+
import org.junit.jupiter.params.provider.ValueSource;
27+
import pascal.taie.Main;
28+
import pascal.taie.World;
29+
import pascal.taie.analysis.pta.PointerAnalysis;
30+
import pascal.taie.analysis.pta.PointerAnalysisResult;
31+
import pascal.taie.analysis.pta.core.cs.element.CSCallSite;
32+
import pascal.taie.analysis.pta.core.cs.element.CSMethod;
33+
import pascal.taie.ir.stmt.Invoke;
34+
import pascal.taie.language.classes.JMethod;
35+
import pascal.taie.util.collection.Sets;
36+
37+
import java.util.Collection;
38+
import java.util.stream.Stream;
39+
40+
import static org.junit.jupiter.api.Assertions.assertEquals;
41+
42+
public class CallGraphTest {
43+
44+
@ParameterizedTest
45+
@ValueSource(strings = {
46+
"New",
47+
"Assign",
48+
"StoreLoad",
49+
"Call",
50+
"Assign2",
51+
})
52+
void test(String mainClass) {
53+
Main.main("-pp",
54+
"-cp", "src/test/resources/pta/basic",
55+
"-cp", "src/test/resources/pta",
56+
"-m", mainClass,
57+
"-a", "pta");
58+
PointerAnalysisResult pta = World.get().getResult(PointerAnalysis.ID);
59+
CallGraph<CSCallSite, CSMethod> csGraph = pta.getCSCallGraph();
60+
CallGraph<Invoke, JMethod> ciGraph = pta.getCallGraph();
61+
62+
assertSizeEquals(csGraph.reachableMethods(), ciGraph.reachableMethods());
63+
assertSizeEquals(csGraph.entryMethods(), ciGraph.entryMethods());
64+
65+
assertEquals(csGraph.getNumberOfEdges(), csGraph.edges().count());
66+
assertEquals(csGraph.getNumberOfMethods(), csGraph.reachableMethods().count());
67+
assertEquals(csGraph.getNumberOfNodes(), csGraph.getNumberOfMethods());
68+
69+
assertEquals(ciGraph.getNumberOfEdges(), ciGraph.edges().count());
70+
assertEquals(ciGraph.getNumberOfMethods(), ciGraph.reachableMethods().count());
71+
assertEquals(ciGraph.getNumberOfNodes(), ciGraph.getNumberOfMethods());
72+
73+
for (CSMethod csMethod : csGraph) {
74+
JMethod method = csMethod.getMethod();
75+
assertSizeEquals(csGraph.getSuccsOf(csMethod), ciGraph.getSuccsOf(method));
76+
assertSizeEquals(csGraph.getPredsOf(csMethod), ciGraph.getPredsOf(method));
77+
78+
assertSizeEquals(csGraph.getCallersOf(csMethod), ciGraph.getCallersOf(method));
79+
assertSizeEquals(csGraph.getCalleesOfM(csMethod), ciGraph.getCalleesOfM(method));
80+
81+
for (CSCallSite csCallSite : csGraph.getCallersOf(csMethod)) {
82+
Invoke callSite = csCallSite.getCallSite();
83+
assertSizeEquals(csGraph.getCalleesOf(csCallSite), ciGraph.getCalleesOf(callSite));
84+
}
85+
}
86+
}
87+
88+
private static <T1, T2> void assertSizeEquals(Collection<T1> expected, Collection<T2> actual) {
89+
// `CSCallGraph.getCalleesOf()` uses `Views.toMappedSet`. Such sets may contain duplicate
90+
// elements by design. Here we wrap it with another set to avoid duplicates.
91+
assertEquals(Sets.newSet(expected).size(), Sets.newSet(actual).size());
92+
}
93+
94+
private static <T1, T2> void assertSizeEquals(Stream<T1> expected, Stream<T2> actual) {
95+
assertEquals(expected.distinct().count(), actual.distinct().count());
96+
}
97+
}

0 commit comments

Comments
 (0)