Skip to content

Commit db0b1f2

Browse files
authored
Merge pull request #1112 from smowton/smowton/feature/call_graph_improvements
Add call-graph invert function
2 parents da1dc29 + d0d046a commit db0b1f2

File tree

4 files changed

+135
-0
lines changed

4 files changed

+135
-0
lines changed

src/analyses/call_graph.cpp

+10
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ void call_grapht::add(
4949
graph.insert(std::pair<irep_idt, irep_idt>(caller, callee));
5050
}
5151

52+
/// Returns an inverted copy of this call graph
53+
/// \return Inverted (callee -> caller) call graph
54+
call_grapht call_grapht::get_inverted() const
55+
{
56+
call_grapht result;
57+
for(const auto &caller_callee : graph)
58+
result.add(caller_callee.second, caller_callee.first);
59+
return result;
60+
}
61+
5262
void call_grapht::output_dot(std::ostream &out) const
5363
{
5464
out << "digraph call_graph {\n";

src/analyses/call_graph.h

+1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class call_grapht
3131
grapht graph;
3232

3333
void add(const irep_idt &caller, const irep_idt &callee);
34+
call_grapht get_inverted() const;
3435

3536
protected:
3637
void add(const irep_idt &function,

unit/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
SRC = unit_tests.cpp \
44
catch_example.cpp \
5+
analyses/call_graph.cpp \
56
java_bytecode/java_bytecode_convert_class/convert_abstract_class.cpp \
67
solvers/refinement/string_constraint_generator_valueof/is_digit_with_radix.cpp \
78
solvers/refinement/string_constraint_generator_valueof/get_numeric_value_from_character.cpp \

unit/analyses/call_graph.cpp

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
2+
#include <iostream>
3+
4+
#include <catch.hpp>
5+
6+
#include <analyses/call_graph.h>
7+
8+
#include <util/symbol_table.h>
9+
#include <util/std_code.h>
10+
11+
#include <goto-programs/goto_convert_functions.h>
12+
13+
static symbolt create_void_function_symbol(
14+
const irep_idt &name,
15+
const codet &code)
16+
{
17+
code_typet void_function_type;
18+
symbolt function;
19+
function.name=name;
20+
function.type=void_function_type;
21+
function.mode=ID_java;
22+
function.value=code;
23+
return function;
24+
}
25+
26+
static bool multimap_key_matches(
27+
const std::multimap<irep_idt, irep_idt> &map,
28+
const irep_idt &key,
29+
const std::set<irep_idt> &values)
30+
{
31+
auto matching_values=map.equal_range(key);
32+
std::set<irep_idt> matching_set;
33+
for(auto it=matching_values.first; it!=matching_values.second; ++it)
34+
matching_set.insert(it->second);
35+
return matching_set==values;
36+
}
37+
38+
SCENARIO("call_graph",
39+
"[core][util][call_graph]")
40+
{
41+
42+
GIVEN("Some cyclic function calls")
43+
{
44+
45+
// Create code like:
46+
// void A()
47+
// {
48+
// A();
49+
// B();
50+
// }
51+
// void B()
52+
// {
53+
// C();
54+
// D();
55+
// }
56+
// void C() { }
57+
// void D() { }
58+
59+
symbol_tablet symbol_table;
60+
code_typet void_function_type;
61+
62+
{
63+
code_blockt calls;
64+
code_function_callt call1;
65+
call1.function()=symbol_exprt("A", void_function_type);
66+
code_function_callt call2;
67+
call2.function()=symbol_exprt("B", void_function_type);
68+
calls.move_to_operands(call1);
69+
calls.move_to_operands(call2);
70+
71+
symbol_table.add(create_void_function_symbol("A", calls));
72+
}
73+
74+
{
75+
code_blockt calls;
76+
code_function_callt call1;
77+
call1.function()=symbol_exprt("C", void_function_type);
78+
code_function_callt call2;
79+
call2.function()=symbol_exprt("D", void_function_type);
80+
calls.move_to_operands(call1);
81+
calls.move_to_operands(call2);
82+
83+
symbol_table.add(create_void_function_symbol("B", calls));
84+
}
85+
86+
symbol_table.add(create_void_function_symbol("C", code_skipt()));
87+
symbol_table.add(create_void_function_symbol("D", code_skipt()));
88+
89+
goto_functionst goto_functions;
90+
stream_message_handlert msg(std::cout);
91+
goto_convert(symbol_table, goto_functions, msg);
92+
93+
call_grapht call_graph_from_goto_functions(goto_functions);
94+
95+
WHEN("A call graph is constructed from the GOTO functions")
96+
{
97+
THEN("We expect A -> { A, B }, B -> { C, D }")
98+
{
99+
const auto &check_graph=call_graph_from_goto_functions.graph;
100+
REQUIRE(check_graph.size()==4);
101+
REQUIRE(multimap_key_matches(check_graph, "A", {"A", "B"}));
102+
REQUIRE(multimap_key_matches(check_graph, "B", {"C", "D"}));
103+
}
104+
}
105+
106+
WHEN("The call graph is inverted")
107+
{
108+
call_grapht inverse_call_graph_from_goto_functions=
109+
call_graph_from_goto_functions.get_inverted();
110+
THEN("We expect A -> { A }, B -> { A }, C -> { B }, D -> { B }")
111+
{
112+
const auto &check_graph=inverse_call_graph_from_goto_functions.graph;
113+
REQUIRE(check_graph.size()==4);
114+
REQUIRE(multimap_key_matches(check_graph, "A", {"A"}));
115+
REQUIRE(multimap_key_matches(check_graph, "B", {"A"}));
116+
REQUIRE(multimap_key_matches(check_graph, "C", {"B"}));
117+
REQUIRE(multimap_key_matches(check_graph, "D", {"B"}));
118+
}
119+
}
120+
121+
}
122+
123+
}

0 commit comments

Comments
 (0)