-
Notifications
You must be signed in to change notification settings - Fork 273
JSON output for show-class-hierarchy #2236
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
public abstract class HierarchyTest { | ||
// These fields exist only so the classloader will load all test classes: | ||
HierarchyTestGrandchild field1; | ||
HierarchyTestChild2 field2; | ||
|
||
abstract void foo(); | ||
} | ||
|
||
class HierarchyTestChild1 extends HierarchyTest { | ||
void foo() {} | ||
} | ||
|
||
class HierarchyTestChild2 extends HierarchyTest { | ||
void foo() {} | ||
} | ||
|
||
class HierarchyTestGrandchild extends HierarchyTestChild1 | ||
implements HierarchyTestInterface1, HierarchyTestInterface2 {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
interface HierarchyTestInterface1 {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
interface HierarchyTestInterface2 {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
CORE symex-driven-lazy-loading-expected-failure | ||
HierarchyTest.class | ||
--show-class-hierarchy --json-ui | ||
activate-multi-line-match | ||
EXIT=0 | ||
SIGNAL=0 | ||
\{\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 number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
CORE symex-driven-lazy-loading-expected-failure | ||
HierarchyTest.class | ||
--show-class-hierarchy | ||
activate-multi-line-match | ||
EXIT=0 | ||
SIGNAL=0 | ||
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 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,10 +22,11 @@ Author: Daniel Kroening, [email protected] | |
|
||
#include <cbmc/bmc.h> | ||
|
||
#include <goto-instrument/cover.h> | ||
#include <goto-programs/class_hierarchy.h> | ||
#include <goto-programs/goto_trace.h> | ||
#include <goto-programs/lazy_goto_model.h> | ||
#include <goto-programs/show_properties.h> | ||
#include <goto-instrument/cover.h> | ||
|
||
#include <goto-symex/path_storage.h> | ||
|
||
|
@@ -60,6 +61,7 @@ class optionst; | |
"(string-max-input-length):" \ | ||
"(16)(32)(64)(LP64)(ILP64)(LLP64)(ILP32)(LP32)" \ | ||
OPT_SHOW_GOTO_FUNCTIONS \ | ||
OPT_SHOW_CLASS_HIERARCHY \ | ||
"(show-loops)" \ | ||
"(show-symbol-table)(show-parse-tree)" \ | ||
OPT_SHOW_PROPERTIES \ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
CORE | ||
main.c | ||
--class-hierarchy --dot | ||
--show-class-hierarchy --dot | ||
digraph class_hierarchy | ||
^EXIT=0$ | ||
^SIGNAL=0$ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
CORE | ||
main.c | ||
--class-hierarchy | ||
--show-class-hierarchy | ||
^EXIT=0$ | ||
^SIGNAL=0$ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,11 +16,12 @@ Author: Daniel Kroening, [email protected] | |
#include <util/parse_options.h> | ||
#include <util/timestamper.h> | ||
|
||
#include <goto-programs/class_hierarchy.h> | ||
#include <goto-programs/goto_functions.h> | ||
#include <goto-programs/show_goto_functions.h> | ||
#include <goto-programs/show_properties.h> | ||
#include <goto-programs/remove_calls_no_body.h> | ||
#include <goto-programs/remove_const_function_pointers.h> | ||
#include <goto-programs/show_goto_functions.h> | ||
#include <goto-programs/show_properties.h> | ||
|
||
#include <analyses/goto_check.h> | ||
|
||
|
@@ -50,7 +51,7 @@ Author: Daniel Kroening, [email protected] | |
"(max-var):(max-po-trans):(ignore-arrays)" \ | ||
"(cfg-kill)(no-dependencies)(force-loop-duplication)" \ | ||
"(call-graph)(reachable-call-graph)" \ | ||
"(class-hierarchy)" \ | ||
OPT_SHOW_CLASS_HIERARCHY \ | ||
"(no-po-rendering)(render-cluster-file)(render-cluster-function)" \ | ||
"(nondet-volatile)(isr):" \ | ||
"(stack-depth):(nondet-static)" \ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ Date: April 2016 | |
|
||
#include <ostream> | ||
|
||
#include <util/json_stream.h> | ||
#include <util/std_types.h> | ||
#include <util/symbol_table.h> | ||
|
||
|
@@ -30,6 +31,9 @@ void class_hierarchyt::operator()(const symbol_tablet &symbol_table) | |
{ | ||
const struct_typet &struct_type = to_struct_type(symbol_pair.second.type); | ||
|
||
class_map[symbol_pair.first].is_abstract = | ||
struct_type.get_bool(ID_abstract); | ||
|
||
const irept::subt &bases= | ||
struct_type.find(ID_bases).get_sub(); | ||
|
||
|
@@ -123,17 +127,23 @@ void class_hierarchyt::get_parents_trans_rec( | |
get_parents_trans_rec(child, dest); | ||
} | ||
|
||
void class_hierarchyt::output(std::ostream &out) const | ||
/// Output the class hierarchy in plain text | ||
/// \param out: the output stream | ||
/// \param children_only: print the children only and do not print the parents | ||
void class_hierarchyt::output(std::ostream &out, bool children_only) const | ||
{ | ||
for(const auto &c : class_map) | ||
{ | ||
for(const auto &pa : c.second.parents) | ||
out << "Parent of " << c.first << ": " | ||
<< pa << '\n'; | ||
|
||
out << c.first << (c.second.is_abstract ? " (abstract)" : "") << ":\n"; | ||
if(!children_only) | ||
{ | ||
out << " parents:\n"; | ||
for(const auto &pa : c.second.parents) | ||
out << " " << pa << '\n'; | ||
} | ||
out << " children:\n"; | ||
for(const auto &ch : c.second.children) | ||
out << "Child of " << c.first << ": " | ||
<< ch << '\n'; | ||
out << " " << ch << '\n'; | ||
} | ||
} | ||
|
||
|
@@ -156,3 +166,50 @@ void class_hierarchyt::output_dot(std::ostream &ostr) const | |
} | ||
ostr << "}\n"; | ||
} | ||
|
||
/// Output the class hierarchy in JSON format | ||
/// \param json_stream: the output JSON stream array | ||
/// \param children_only: print the children only and do not print the parents | ||
void class_hierarchyt::output( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: It would be nice if the doxygen comment included an example of the expected JSON output/schema... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this commit has added new functionality (the JSON output) - shouldn't this commit also include some unit/regression tests to exercise that output and validate that we are generating the expected JSON. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added tests for plain text and json in jbmc/regression/jbmc/class_hierarchy |
||
json_stream_arrayt &json_stream, | ||
bool children_only) const | ||
{ | ||
for(const auto &c : class_map) | ||
{ | ||
json_stream_objectt &json_class = json_stream.push_back_stream_object(); | ||
json_class["name"] = json_stringt(c.first); | ||
json_class["isAbstract"] = jsont::json_boolean(c.second.is_abstract); | ||
if(!children_only) | ||
{ | ||
json_stream_arrayt &json_parents = | ||
json_class.push_back_stream_array("parents"); | ||
for(const auto &pa : c.second.parents) | ||
json_parents.push_back(json_stringt(pa)); | ||
} | ||
json_stream_arrayt &json_children = | ||
json_class.push_back_stream_array("children"); | ||
for(const auto &ch : c.second.children) | ||
json_children.push_back(json_stringt(ch)); | ||
} | ||
} | ||
|
||
void show_class_hierarchy( | ||
const class_hierarchyt &hierarchy, | ||
message_handlert &message_handler, | ||
ui_message_handlert::uit ui, | ||
bool children_only) | ||
{ | ||
messaget msg(message_handler); | ||
switch(ui) | ||
{ | ||
case ui_message_handlert::uit::PLAIN: | ||
hierarchy.output(msg.result(), children_only); | ||
msg.result() << messaget::eom; | ||
break; | ||
case ui_message_handlert::uit::JSON_UI: | ||
hierarchy.output(msg.result().json_stream(), children_only); | ||
break; | ||
case ui_message_handlert::uit::XML_UI: | ||
UNIMPLEMENTED; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels like the kind of thing that could do with a test case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure what you want me to test here. Actually, that output has already proved useful to check whether we load interface/abstract class information correctly, but that can't really be put into a unit or regression test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a test that uses that part. I ask because the code was right / finished before and now this needs to be added so I think we should have a case that was sub-par / wrong / insufficient before and is now better. If it's a pain don't worry.