Skip to content

Commit 34b0ac6

Browse files
Merge pull request diffblue#2236 from diffblue/show-class-hierarchy
JSON output for show-class-hierarchy
2 parents 8e8e450 + 2f4c6ad commit 34b0ac6

20 files changed

+154
-32
lines changed
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
public abstract class HierarchyTest {
2+
// These fields exist only so the classloader will load all test classes:
3+
HierarchyTestGrandchild field1;
4+
HierarchyTestChild2 field2;
5+
6+
abstract void foo();
7+
}
8+
9+
class HierarchyTestChild1 extends HierarchyTest {
10+
void foo() {}
11+
}
12+
13+
class HierarchyTestChild2 extends HierarchyTest {
14+
void foo() {}
15+
}
16+
17+
class HierarchyTestGrandchild extends HierarchyTestChild1
18+
implements HierarchyTestInterface1, HierarchyTestInterface2 {}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
interface HierarchyTestInterface1 {}
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
interface HierarchyTestInterface2 {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE symex-driven-lazy-loading-expected-failure
2+
HierarchyTest.class
3+
--show-class-hierarchy --json-ui
4+
activate-multi-line-match
5+
EXIT=0
6+
SIGNAL=0
7+
\{\n *"isAbstract": true,\n *"name": "java::HierarchyTest",\n *"parents": \[\n *"java::java.lang.Object"\n *\],\n *"children": \[\n *"java::HierarchyTestChild(1|2)",\n *"java::HierarchyTestChild(1|2)"\n *\]\n *\},\n *\{\n *"isAbstract": false,\n *"name": "java::HierarchyTestGrandchild",\n *"parents": \[\n *"java::HierarchyTestChild1",\n *"java::HierarchyTestInterface1",\n *"java::HierarchyTestInterface2"\n *\],\n *"children": \[\n *\]\n *\},\n *\{\n *"isAbstract": false,\n *"name": "java::HierarchyTestChild2",\n *"parents": \[\n *"java::HierarchyTest"\n *\],\n *"children": \[\n *\]\n *\},\n *\{\n *"isAbstract": false,\n *"name": "java::HierarchyTestChild1",\n *"parents": \[\n *"java::HierarchyTest"\n *\],\n *"children": \[\n *"java::HierarchyTestGrandchild"\n *\]\n *\},\n *\{\n *"isAbstract": true,\n *"name": "java::HierarchyTestInterface1",\n *"parents": \[\n *"java::java.lang.Object"\n *\],\n *"children": \[\n *"java::HierarchyTestGrandchild"\n *\]\n *\},\n *\{\n *"isAbstract": true,\n *"name": "java::HierarchyTestInterface2",\n *"parents": \[\n *"java::java.lang.Object"\n *\],\n *"children": \[\n *"java::HierarchyTestGrandchild"\n *\]\n *\},
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE symex-driven-lazy-loading-expected-failure
2+
HierarchyTest.class
3+
--show-class-hierarchy
4+
activate-multi-line-match
5+
EXIT=0
6+
SIGNAL=0
7+
java::HierarchyTest \(abstract\):\n *parents:\n *java::java\.lang\.Object\n *children:\n *java::HierarchyTestChild(1|2)\n *java::HierarchyTestChild(1|2)\njava::HierarchyTestGrandchild:\n *parents:\n *java::HierarchyTestChild1\n *java::HierarchyTestInterface1\n *java::HierarchyTestInterface2\n *children:\njava::HierarchyTestChild2:\n *parents:\n *java::HierarchyTest\n *children:\njava::HierarchyTestChild1:\n *parents:\n *java::HierarchyTest\n *children:\n *java::HierarchyTestGrandchild\njava::HierarchyTestInterface1 \(abstract\):\n *parents:\n *java::java\.lang\.Object\n *children:\n *java::HierarchyTestGrandchild\njava::HierarchyTestInterface2 \(abstract\):\n *parents:\n *java::java\.lang\.Object\n *children:\n *java::HierarchyTestGrandchild

jbmc/src/jbmc/jbmc_parse_options.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,16 @@ int jbmc_parse_optionst::get_goto_program(
645645
*this, options, get_message_handler());
646646
lazy_goto_model.initialize(cmdline);
647647

648+
// Show the class hierarchy
649+
if(cmdline.isset("show-class-hierarchy"))
650+
{
651+
class_hierarchyt hierarchy;
652+
hierarchy(lazy_goto_model.symbol_table);
653+
show_class_hierarchy(
654+
hierarchy, get_message_handler(), ui_message_handler.get_ui());
655+
return CPROVER_EXIT_SUCCESS;
656+
}
657+
648658
// Add failed symbols for any symbol created prior to loading any
649659
// particular function:
650660
add_failed_symbols(lazy_goto_model.symbol_table);
@@ -1079,6 +1089,7 @@ void jbmc_parse_optionst::help()
10791089
" --show-symbol-table show loaded symbol table\n"
10801090
HELP_SHOW_GOTO_FUNCTIONS
10811091
" --drop-unused-functions drop functions trivially unreachable from main function\n" // NOLINT(*)
1092+
HELP_SHOW_CLASS_HIERARCHY
10821093
"\n"
10831094
"Program instrumentation options:\n"
10841095
HELP_GOTO_CHECK

jbmc/src/jbmc/jbmc_parse_options.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ Author: Daniel Kroening, [email protected]
2222

2323
#include <cbmc/bmc.h>
2424

25+
#include <goto-instrument/cover.h>
26+
#include <goto-programs/class_hierarchy.h>
2527
#include <goto-programs/goto_trace.h>
2628
#include <goto-programs/lazy_goto_model.h>
2729
#include <goto-programs/show_properties.h>
28-
#include <goto-instrument/cover.h>
2930

3031
#include <goto-symex/path_storage.h>
3132

@@ -60,6 +61,7 @@ class optionst;
6061
"(string-max-input-length):" \
6162
"(16)(32)(64)(LP64)(ILP64)(LLP64)(ILP32)(LP32)" \
6263
OPT_SHOW_GOTO_FUNCTIONS \
64+
OPT_SHOW_CLASS_HIERARCHY \
6365
"(show-loops)" \
6466
"(show-symbol-table)(show-parse-tree)" \
6567
OPT_SHOW_PROPERTIES \

jbmc/unit/java_bytecode/goto-programs/class_hierarchy_output.cpp

+6-14
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,15 @@
1717
void require_parent_child_relationship(
1818
const std::string &parent_raw,
1919
const std::string &child_raw,
20-
const std::string &output,
2120
const std::string &output_dot)
2221
{
2322
std::string parent = "java::" + parent_raw;
2423
std::string child = "java::" + child_raw;
2524

26-
std::stringstream
27-
plain_child_expectation, plain_parent_expectation, dot_expectation;
25+
std::stringstream dot_expectation;
2826

29-
plain_child_expectation << "Child of " << parent << ": " << child;
30-
plain_parent_expectation << "Parent of " << child << ": " << parent;
3127
dot_expectation << "\"" << child << "\" -> \"" << parent << "\"";
3228

33-
REQUIRE(output.find(plain_child_expectation.str()) != std::string::npos);
34-
REQUIRE(output.find(plain_parent_expectation.str()) != std::string::npos);
3529
REQUIRE(output_dot.find(dot_expectation.str()) != std::string::npos);
3630
}
3731

@@ -47,20 +41,18 @@ SCENARIO(
4741
std::stringstream output_dot_stream;
4842

4943
hierarchy(symbol_table);
50-
hierarchy.output(output_stream);
5144
hierarchy.output_dot(output_dot_stream);
5245

53-
std::string output = output_stream.str();
5446
std::string output_dot = output_dot_stream.str();
5547

5648
require_parent_child_relationship(
57-
"HierarchyTest", "HierarchyTestChild1", output, output_dot);
49+
"HierarchyTest", "HierarchyTestChild1", output_dot);
5850
require_parent_child_relationship(
59-
"HierarchyTest", "HierarchyTestChild2", output, output_dot);
51+
"HierarchyTest", "HierarchyTestChild2", output_dot);
6052
require_parent_child_relationship(
61-
"HierarchyTestChild1", "HierarchyTestGrandchild", output, output_dot);
53+
"HierarchyTestChild1", "HierarchyTestGrandchild", output_dot);
6254
require_parent_child_relationship(
63-
"HierarchyTestInterface1", "HierarchyTestGrandchild", output, output_dot);
55+
"HierarchyTestInterface1", "HierarchyTestGrandchild", output_dot);
6456
require_parent_child_relationship(
65-
"HierarchyTestInterface2", "HierarchyTestGrandchild", output, output_dot);
57+
"HierarchyTestInterface2", "HierarchyTestGrandchild", output_dot);
6658
}
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
CORE
22
main.c
3-
--class-hierarchy --dot
3+
--show-class-hierarchy --dot
44
digraph class_hierarchy
55
^EXIT=0$
66
^SIGNAL=0$
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
CORE
22
main.c
3-
--class-hierarchy
3+
--show-class-hierarchy
44
^EXIT=0$
55
^SIGNAL=0$

src/goto-instrument/goto_instrument_parse_options.cpp

+5-4
Original file line numberDiff line numberDiff line change
@@ -652,16 +652,17 @@ int goto_instrument_parse_optionst::doit()
652652
return 0;
653653
}
654654

655-
if(cmdline.isset("class-hierarchy"))
655+
if(cmdline.isset("show-class-hierarchy"))
656656
{
657657
class_hierarchyt hierarchy;
658658
hierarchy(goto_model.symbol_table);
659659
if(cmdline.isset("dot"))
660660
hierarchy.output_dot(std::cout);
661661
else
662-
hierarchy.output(std::cout);
662+
show_class_hierarchy(
663+
hierarchy, get_message_handler(), ui_message_handler.get_ui());
663664

664-
return 0;
665+
return CPROVER_EXIT_SUCCESS;
665666
}
666667

667668
if(cmdline.isset("dot"))
@@ -1472,7 +1473,7 @@ void goto_instrument_parse_optionst::help()
14721473
" --call-graph show graph of function calls\n"
14731474
// NOLINTNEXTLINE(whitespace/line_length)
14741475
" --reachable-call-graph show graph of function calls potentially reachable from main function\n"
1475-
" --class-hierarchy show class hierarchy\n"
1476+
HELP_SHOW_CLASS_HIERARCHY
14761477
// NOLINTNEXTLINE(whitespace/line_length)
14771478
" --show-threaded show instructions that may be executed by more than one thread\n"
14781479
"\n"

src/goto-instrument/goto_instrument_parse_options.h

+4-3
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ Author: Daniel Kroening, [email protected]
1616
#include <util/parse_options.h>
1717
#include <util/timestamper.h>
1818

19+
#include <goto-programs/class_hierarchy.h>
1920
#include <goto-programs/goto_functions.h>
20-
#include <goto-programs/show_goto_functions.h>
21-
#include <goto-programs/show_properties.h>
2221
#include <goto-programs/remove_calls_no_body.h>
2322
#include <goto-programs/remove_const_function_pointers.h>
23+
#include <goto-programs/show_goto_functions.h>
24+
#include <goto-programs/show_properties.h>
2425

2526
#include <analyses/goto_check.h>
2627

@@ -50,7 +51,7 @@ Author: Daniel Kroening, [email protected]
5051
"(max-var):(max-po-trans):(ignore-arrays)" \
5152
"(cfg-kill)(no-dependencies)(force-loop-duplication)" \
5253
"(call-graph)(reachable-call-graph)" \
53-
"(class-hierarchy)" \
54+
OPT_SHOW_CLASS_HIERARCHY \
5455
"(no-po-rendering)(render-cluster-file)(render-cluster-function)" \
5556
"(nondet-volatile)(isr):" \
5657
"(stack-depth):(nondet-static)" \

src/goto-programs/class_hierarchy.cpp

+64-7
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Date: April 2016
1515

1616
#include <ostream>
1717

18+
#include <util/json_stream.h>
1819
#include <util/std_types.h>
1920
#include <util/symbol_table.h>
2021

@@ -30,6 +31,9 @@ void class_hierarchyt::operator()(const symbol_tablet &symbol_table)
3031
{
3132
const struct_typet &struct_type = to_struct_type(symbol_pair.second.type);
3233

34+
class_map[symbol_pair.first].is_abstract =
35+
struct_type.get_bool(ID_abstract);
36+
3337
const irept::subt &bases=
3438
struct_type.find(ID_bases).get_sub();
3539

@@ -123,17 +127,23 @@ void class_hierarchyt::get_parents_trans_rec(
123127
get_parents_trans_rec(child, dest);
124128
}
125129

126-
void class_hierarchyt::output(std::ostream &out) const
130+
/// Output the class hierarchy in plain text
131+
/// \param out: the output stream
132+
/// \param children_only: print the children only and do not print the parents
133+
void class_hierarchyt::output(std::ostream &out, bool children_only) const
127134
{
128135
for(const auto &c : class_map)
129136
{
130-
for(const auto &pa : c.second.parents)
131-
out << "Parent of " << c.first << ": "
132-
<< pa << '\n';
133-
137+
out << c.first << (c.second.is_abstract ? " (abstract)" : "") << ":\n";
138+
if(!children_only)
139+
{
140+
out << " parents:\n";
141+
for(const auto &pa : c.second.parents)
142+
out << " " << pa << '\n';
143+
}
144+
out << " children:\n";
134145
for(const auto &ch : c.second.children)
135-
out << "Child of " << c.first << ": "
136-
<< ch << '\n';
146+
out << " " << ch << '\n';
137147
}
138148
}
139149

@@ -156,3 +166,50 @@ void class_hierarchyt::output_dot(std::ostream &ostr) const
156166
}
157167
ostr << "}\n";
158168
}
169+
170+
/// Output the class hierarchy in JSON format
171+
/// \param json_stream: the output JSON stream array
172+
/// \param children_only: print the children only and do not print the parents
173+
void class_hierarchyt::output(
174+
json_stream_arrayt &json_stream,
175+
bool children_only) const
176+
{
177+
for(const auto &c : class_map)
178+
{
179+
json_stream_objectt &json_class = json_stream.push_back_stream_object();
180+
json_class["name"] = json_stringt(c.first);
181+
json_class["isAbstract"] = jsont::json_boolean(c.second.is_abstract);
182+
if(!children_only)
183+
{
184+
json_stream_arrayt &json_parents =
185+
json_class.push_back_stream_array("parents");
186+
for(const auto &pa : c.second.parents)
187+
json_parents.push_back(json_stringt(pa));
188+
}
189+
json_stream_arrayt &json_children =
190+
json_class.push_back_stream_array("children");
191+
for(const auto &ch : c.second.children)
192+
json_children.push_back(json_stringt(ch));
193+
}
194+
}
195+
196+
void show_class_hierarchy(
197+
const class_hierarchyt &hierarchy,
198+
message_handlert &message_handler,
199+
ui_message_handlert::uit ui,
200+
bool children_only)
201+
{
202+
messaget msg(message_handler);
203+
switch(ui)
204+
{
205+
case ui_message_handlert::uit::PLAIN:
206+
hierarchy.output(msg.result(), children_only);
207+
msg.result() << messaget::eom;
208+
break;
209+
case ui_message_handlert::uit::JSON_UI:
210+
hierarchy.output(msg.result().json_stream(), children_only);
211+
break;
212+
case ui_message_handlert::uit::XML_UI:
213+
UNIMPLEMENTED;
214+
}
215+
}

src/goto-programs/class_hierarchy.h

+25-1
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,19 @@ Date: April 2016
2020

2121
#include <util/graph.h>
2222
#include <util/irep.h>
23+
#include <util/ui_message.h>
24+
25+
// clang-format off
26+
#define OPT_SHOW_CLASS_HIERARCHY \
27+
"(show-class-hierarchy)"
28+
29+
#define HELP_SHOW_CLASS_HIERARCHY \
30+
" --show-class-hierarchy show the class hierarchy\n"
31+
// clang-format on
2332

2433
class symbol_tablet;
34+
class json_stream_arrayt;
35+
class message_handlert;
2536

2637
class class_hierarchyt
2738
{
@@ -32,6 +43,7 @@ class class_hierarchyt
3243
{
3344
public:
3445
idst parents, children;
46+
bool is_abstract;
3547
};
3648

3749
typedef std::map<irep_idt, entryt> class_mapt;
@@ -55,8 +67,9 @@ class class_hierarchyt
5567
return result;
5668
}
5769

58-
void output(std::ostream &) const;
70+
void output(std::ostream &, bool children_only) const;
5971
void output_dot(std::ostream &) const;
72+
void output(json_stream_arrayt &, bool children_only) const;
6073

6174
protected:
6275
void get_children_trans_rec(const irep_idt &, idst &) const;
@@ -93,4 +106,15 @@ class class_hierarchy_grapht : public grapht<class_hierarchy_graph_nodet>
93106
nodes_by_namet nodes_by_name;
94107
};
95108

109+
/// Output the class hierarchy
110+
/// \param hierarchy: the class hierarchy to be printed
111+
/// \param message_handler: the message handler
112+
/// \param ui: the UI format
113+
/// \param children_only: print the children only and do not print the parents
114+
void show_class_hierarchy(
115+
const class_hierarchyt &hierarchy,
116+
message_handlert &message_handler,
117+
ui_message_handlert::uit ui,
118+
bool children_only = false);
119+
96120
#endif // CPROVER_GOTO_PROGRAMS_CLASS_HIERARCHY_H

0 commit comments

Comments
 (0)