From b5147937b2a9ffdc12110a5df5ba4d482f83d2a8 Mon Sep 17 00:00:00 2001 From: isuckatcs <65320245+isuckatcs@users.noreply.github.com> Date: Thu, 4 Aug 2022 19:49:05 +0200 Subject: [PATCH] [analyzer] Add more information to the Exploded Graph This patch dumps every state trait in the egraph. Also the empty state traits are no longer dumped, instead they are treated as null by the egraph rewriter script, which solves reverse compatibility issues. Differential Revision: https://reviews.llvm.org/D131187 --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp | 195 ++++++++++++++--- .../exploded-graph-rewriter/checker_messages.dot | 4 +- .../checker_messages_diff.dot | 8 +- .../exploded-graph-rewriter/constraints.dot | 4 +- .../exploded-graph-rewriter/constraints_diff.dot | 12 +- .../exploded-graph-rewriter/environment.dot | 4 +- .../exploded-graph-rewriter/environment_diff.dot | 12 +- .../program_state_traits.dot | 237 +++++++++++++++++++++ .../Analysis/exploded-graph-rewriter/store.dot | 4 +- .../exploded-graph-rewriter/store_diff.dot | 8 +- .../Analysis/exploded-graph-rewriter/topology.dot | 4 +- clang/test/Analysis/expr-inspection.c | 2 - clang/utils/analyzer/exploded-graph-rewriter.py | 74 +++++-- 13 files changed, 466 insertions(+), 102 deletions(-) create mode 100644 clang/test/Analysis/exploded-graph-rewriter/program_state_traits.dot diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 656a7c1..99aa4c5 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -693,7 +693,7 @@ printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State, continue; if (!HasItem) { - Out << "[" << NL; + Out << '[' << NL; HasItem = true; } @@ -724,12 +724,11 @@ printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State, static void printIndicesOfElementsToConstructJson( raw_ostream &Out, ProgramStateRef State, const char *NL, - const LocationContext *LCtx, const ASTContext &Context, - unsigned int Space = 0, bool IsDot = false) { + const LocationContext *LCtx, unsigned int Space = 0, bool IsDot = false) { using KeyT = std::pair; - PrintingPolicy PP = - LCtx->getAnalysisDeclContext()->getASTContext().getPrintingPolicy(); + const auto &Context = LCtx->getAnalysisDeclContext()->getASTContext(); + PrintingPolicy PP = Context.getPrintingPolicy(); ++Space; bool HasItem = false; @@ -742,7 +741,7 @@ static void printIndicesOfElementsToConstructJson( continue; if (!HasItem) { - Out << "[" << NL; + Out << '[' << NL; HasItem = true; } @@ -761,17 +760,17 @@ static void printIndicesOfElementsToConstructJson( const Expr *E = Key.first; Out << "\"stmt_id\": " << E->getID(Context); - // Kind - hack to display the current index - Out << ", \"kind\": \"Cur: " << Value - 1 << "\""; + // Kind + Out << ", \"kind\": null"; // Pretty-print Out << ", \"pretty\": "; - Out << "\"" << E->getStmtClassName() << " " + Out << "\"" << E->getStmtClassName() << ' ' << E->getSourceRange().printToString(Context.getSourceManager()) << " '" << QualType::getAsString(E->getType().split(), PP); Out << "'\""; - Out << ", \"value\": \"Next: " << Value << "\" }"; + Out << ", \"value\": \"Current index: " << Value - 1 << "\" }"; if (Key != LastKey) Out << ','; @@ -785,40 +784,168 @@ static void printIndicesOfElementsToConstructJson( } } -void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State, - const LocationContext *LCtx, const char *NL, - unsigned int Space, bool IsDot) const { - Indent(Out, Space, IsDot) << "\"constructing_objects\": "; +static void printPendingInitLoopJson(raw_ostream &Out, ProgramStateRef State, + const char *NL, + const LocationContext *LCtx, + unsigned int Space = 0, + bool IsDot = false) { + using KeyT = std::pair; - if (LCtx && !State->get().isEmpty()) { - ++Space; - Out << '[' << NL; - LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) { - printObjectsUnderConstructionJson(Out, State, NL, LC, Space, IsDot); - }); + const auto &Context = LCtx->getAnalysisDeclContext()->getASTContext(); + PrintingPolicy PP = Context.getPrintingPolicy(); - --Space; - Indent(Out, Space, IsDot) << "]," << NL; // End of "constructing_objects". - } else { - Out << "null," << NL; + ++Space; + bool HasItem = false; + + // Store the last key. + KeyT LastKey; + for (const auto &I : State->get()) { + const KeyT &Key = I.first; + if (Key.second != LCtx) + continue; + + if (!HasItem) { + Out << '[' << NL; + HasItem = true; + } + + LastKey = Key; } - Indent(Out, Space, IsDot) << "\"index_of_element\": "; - if (LCtx && !State->get().isEmpty()) { - ++Space; + for (const auto &I : State->get()) { + const KeyT &Key = I.first; + unsigned Value = I.second; + if (Key.second != LCtx) + continue; + + Indent(Out, Space, IsDot) << "{ "; + + const CXXConstructExpr *E = Key.first; + Out << "\"stmt_id\": " << E->getID(Context); + + Out << ", \"kind\": null"; + Out << ", \"pretty\": "; + Out << '\"' << E->getStmtClassName() << ' ' + << E->getSourceRange().printToString(Context.getSourceManager()) << " '" + << QualType::getAsString(E->getType().split(), PP); + Out << "'\""; + + Out << ", \"value\": \"Flattened size: " << Value << "\"}"; + + if (Key != LastKey) + Out << ','; + Out << NL; + } - auto &Context = getContext(); + if (HasItem) + Indent(Out, --Space, IsDot) << ']'; // End of "location_context". + else { + Out << "null "; + } +} + +static void +printPendingArrayDestructionsJson(raw_ostream &Out, ProgramStateRef State, + const char *NL, const LocationContext *LCtx, + unsigned int Space = 0, bool IsDot = false) { + using KeyT = const LocationContext *; + + ++Space; + bool HasItem = false; + + // Store the last key. + KeyT LastKey = nullptr; + for (const auto &I : State->get()) { + const KeyT &Key = I.first; + if (Key != LCtx) + continue; + + if (!HasItem) { + Out << '[' << NL; + HasItem = true; + } + + LastKey = Key; + } + + for (const auto &I : State->get()) { + const KeyT &Key = I.first; + if (Key != LCtx) + continue; + + Indent(Out, Space, IsDot) << "{ "; + + Out << "\"stmt_id\": null"; + Out << ", \"kind\": null"; + Out << ", \"pretty\": \"Current index: \""; + Out << ", \"value\": \"" << I.second << "\" }"; + + if (Key != LastKey) + Out << ','; + Out << NL; + } + + if (HasItem) + Indent(Out, --Space, IsDot) << ']'; // End of "location_context". + else { + Out << "null "; + } +} + +/// A helper function to generalize program state trait printing. +/// The function invokes Printer as 'Printer(Out, State, NL, LC, Space, IsDot, +/// std::forward(args)...)'. \n One possible type for Printer is +/// 'void()(raw_ostream &, ProgramStateRef, const char *, const LocationContext +/// *, unsigned int, bool, ...)' \n \param Trait The state trait to be printed. +/// \param Printer A void function that prints Trait. +/// \param Args An additional parameter pack that is passed to Print upon +/// invocation. +template +static void printStateTraitWithLocationContextJson( + raw_ostream &Out, ProgramStateRef State, const LocationContext *LCtx, + const char *NL, unsigned int Space, bool IsDot, + const char *jsonPropertyName, Printer printer, Args &&...args) { + + using RequiredType = + void (*)(raw_ostream &, ProgramStateRef, const char *, + const LocationContext *, unsigned int, bool, Args &&...); + + // Try to do as much compile time checking as possible. + // FIXME: check for invocable instead of function? + static_assert(std::is_function>::value, + "Printer is not a function!"); + static_assert(std::is_convertible::value, + "Printer doesn't have the required type!"); + + if (LCtx && !State->get().isEmpty()) { + Indent(Out, Space, IsDot) << '\"' << jsonPropertyName << "\": "; + ++Space; Out << '[' << NL; LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) { - printIndicesOfElementsToConstructJson(Out, State, NL, LC, Context, Space, - IsDot); + printer(Out, State, NL, LC, Space, IsDot, std::forward(args)...); }); --Space; - Indent(Out, Space, IsDot) << "]," << NL; // End of "index_of_element". - } else { - Out << "null," << NL; + Indent(Out, Space, IsDot) << "]," << NL; // End of "jsonPropertyName". } +} + +void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State, + const LocationContext *LCtx, const char *NL, + unsigned int Space, bool IsDot) const { + + printStateTraitWithLocationContextJson( + Out, State, LCtx, NL, Space, IsDot, "constructing_objects", + printObjectsUnderConstructionJson); + printStateTraitWithLocationContextJson( + Out, State, LCtx, NL, Space, IsDot, "index_of_element", + printIndicesOfElementsToConstructJson); + printStateTraitWithLocationContextJson( + Out, State, LCtx, NL, Space, IsDot, "pending_init_loops", + printPendingInitLoopJson); + printStateTraitWithLocationContextJson( + Out, State, LCtx, NL, Space, IsDot, "pending_destructors", + printPendingArrayDestructionsJson); getCheckerManager().runCheckersForPrintStateJson(Out, State, NL, Space, IsDot); @@ -3714,7 +3841,7 @@ struct DOTGraphTraits : public DefaultDOTGraphTraits { OtherNode->getLocation().printJson(Out, /*NL=*/"\\l"); Out << ", \"tag\": "; if (const ProgramPointTag *Tag = OtherNode->getLocation().getTag()) - Out << '\"' << Tag->getTagDescription() << "\""; + Out << '\"' << Tag->getTagDescription() << '\"'; else Out << "null"; Out << ", \"node_id\": " << OtherNode->getID() << diff --git a/clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot b/clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot index e22309d..42d45b0 100644 --- a/clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot +++ b/clang/test/Analysis/exploded-graph-rewriter/checker_messages.dot @@ -22,9 +22,7 @@ Node0x1 [shape=record,label= "program_state": { "store": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "environment": null, "checker_messages": [ { "checker": "alpha.core.FooChecker", "messages": [ diff --git a/clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot b/clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot index 4863825..d42326c 100644 --- a/clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot +++ b/clang/test/Analysis/exploded-graph-rewriter/checker_messages_diff.dot @@ -15,9 +15,7 @@ Node0x1 [shape=record,label= "environment": null, "store": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": [ { "checker": "FooChecker", "messages": [ "Foo: Bar" @@ -74,9 +72,7 @@ Node0x4 [shape=record,label= "environment": null, "store": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": [ { "checker": "FooChecker", "messages": [ "Foo: Bar", diff --git a/clang/test/Analysis/exploded-graph-rewriter/constraints.dot b/clang/test/Analysis/exploded-graph-rewriter/constraints.dot index fa4ab08..d38564c 100644 --- a/clang/test/Analysis/exploded-graph-rewriter/constraints.dot +++ b/clang/test/Analysis/exploded-graph-rewriter/constraints.dot @@ -22,9 +22,7 @@ Node0x1 [shape=record,label= "program_state": { "store": null, "environment": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": null, "constraints": [ { "symbol": "reg_$0", "range": "{ [0, 0] }" } diff --git a/clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot b/clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot index e7dfc89d..214c9a3 100644 --- a/clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot +++ b/clang/test/Analysis/exploded-graph-rewriter/constraints_diff.dot @@ -15,9 +15,7 @@ Node0x1 [shape=record,label= "program_state": { "store": null, "environment": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": null, "constraints": [ { "symbol": "reg_$0", "range": "{ [0, 10] }" } @@ -54,9 +52,7 @@ Node0x3 [shape=record,label= "program_state": { "store": null, "environment": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": null, "constraints": [ { "symbol": "reg_$0", "range": "{ [0, 5] }" } @@ -83,9 +79,7 @@ Node0x5 [shape=record,label= "store": null, "environment": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": null } } diff --git a/clang/test/Analysis/exploded-graph-rewriter/environment.dot b/clang/test/Analysis/exploded-graph-rewriter/environment.dot index d5c1fda..67f2a2a 100644 --- a/clang/test/Analysis/exploded-graph-rewriter/environment.dot +++ b/clang/test/Analysis/exploded-graph-rewriter/environment.dot @@ -44,9 +44,7 @@ Node0x1 [shape=record,label= "program_state": { "store": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": null, "environment": { "pointer": "0x2", diff --git a/clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot b/clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot index 1df005c..e237bc5 100644 --- a/clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot +++ b/clang/test/Analysis/exploded-graph-rewriter/environment_diff.dot @@ -16,9 +16,7 @@ Node0x1 [shape=record,label= "program_state": { "store": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": null, "environment": { "pointer": "0x2", @@ -72,9 +70,7 @@ Node0x6 [shape=record,label= "program_state": { "store": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": null, "environment": { "pointer": "0x2", @@ -122,9 +118,7 @@ Node0x9 [shape=record,label= "program_state": { "store": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": null, "environment": { "pointer": "0x2", diff --git a/clang/test/Analysis/exploded-graph-rewriter/program_state_traits.dot b/clang/test/Analysis/exploded-graph-rewriter/program_state_traits.dot new file mode 100644 index 0000000..8b51bee --- /dev/null +++ b/clang/test/Analysis/exploded-graph-rewriter/program_state_traits.dot @@ -0,0 +1,237 @@ +// RUN: %exploded_graph_rewriter %s | FileCheck %s + +// CHECK: Objects Under Construction: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME:
#0 Call +// CHECK-SAME: main +// CHECK-SAME:
S870 +// CHECK-SAME: +// CHECK-SAME: (construct into local variable) +// CHECK-SAME: +// CHECK-SAME: S s;&s
+Node0x1 [shape=record,label= +"{ + { + "state_id": 2, + "program_points": [ + { + "kind": "BlockEntrance", "block_id": 1, + "terminator": null, "term_kind": null, + "tag": null, "node_id": 1, + "has_report": 0, "is_sink": 0 + } + ], + "program_state": { + "store": null, + "environment": null, + "constraints": null, + "equivalence_classes": null, + "disequality_info": null, + "dynamic_types": null, + "dynamic_casts": null, + "constructing_objects": [ + { + "lctx_id": 1, "location_context": "#0 Call", "calling": "main", "location": null, "items": [ + { "stmt_id": 870, "kind": "construct into local variable", "argument_index": null, "pretty": "S s;", "value": "&s" } + ] + } + ], + "checker_messages": null + } + } +\l}"]; + +// CHECK: Indices Of Elements Under Construction: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME:
#0 Call +// CHECK-SAME: main +// CHECK-SAME:
S895 +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: CXXConstructExpr 'S[2]' +// CHECK-SAME: Current index: 0
+Node0x2 [shape=record,label= +"{ + { + "state_id": 2, + "program_points": [ + { + "kind": "BlockEntrance", "block_id": 1, + "terminator": null, "term_kind": null, + "tag": null, "node_id": 1, + "has_report": 0, "is_sink": 0 + } + ], + "program_state": { + "store": null, + "environment": null, + "constraints": null, + "equivalence_classes": null, + "disequality_info": null, + "dynamic_types": null, + "dynamic_casts": null, + "index_of_element": [ + { + "lctx_id": 1, + "location_context": "#0 Call", + "calling": "main", + "location": null, + "items": [ + { + "stmt_id": 895, + "kind": null, + "pretty": "CXXConstructExpr 'S[2]'", + "value": "Current index: 0" + } + ] + } + ], + "checker_messages": null + } + } +\l}"]; + +// CHECK: Pending Array Init Loop Expressions: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME:
#0 Call +// CHECK-SAME: main +// CHECK-SAME:
S1112 +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: CXXConstructExpr 'S' +// CHECK-SAME: Flattened size: 2
+Node0x3 [shape=record,label= +"{ + { + "state_id": 2, + "program_points": [ + { + "kind": "BlockEntrance", "block_id": 1, + "terminator": null, "term_kind": null, + "tag": null, "node_id": 1, + "has_report": 0, "is_sink": 0 + } + ], + "program_state": { + "store": null, + "environment": null, + "constraints": null, + "equivalence_classes": null, + "disequality_info": null, + "dynamic_types": null, + "dynamic_casts": null, + "pending_init_loops": [ + { + "lctx_id": 1, + "location_context": "#0 Call", + "calling": "main", + "location": null, + "items": [ + { + "stmt_id": 1112, + "kind": null, + "pretty": "CXXConstructExpr 'S'", "value": "Flattened size: 2" + } + ] + } + ], + "checker_messages": null + } + } +\l}"]; + +// CHECK: Indices of Elements Under Destruction: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME: +// CHECK-SAME:
#0 Call +// CHECK-SAME: main +// CHECK-SAME:
SNone +// CHECK-SAME: +// CHECK-SAME: Current index: 1
+Node0x4 [shape=record,label= +"{ + { + "state_id": 2, + "program_points": [ + { + "kind": "BlockEntrance", "block_id": 1, + "terminator": null, "term_kind": null, + "tag": null, "node_id": 1, + "has_report": 0, "is_sink": 0 + } + ], + "program_state": { + "store": null, + "environment": null, + "constraints": null, + "equivalence_classes": null, + "disequality_info": null, + "dynamic_types": null, + "dynamic_casts": null, + "pending_destructors": [ + { + "lctx_id": 1, + "location_context": "#0 Call", + "calling": "main", + "location": null, + "items": [ + { + "stmt_id": null, + "kind": null, + "pretty": "Current index: ", + "value": "1" + } + ] + } + ], + "checker_messages": null + } + } +\l}"]; diff --git a/clang/test/Analysis/exploded-graph-rewriter/store.dot b/clang/test/Analysis/exploded-graph-rewriter/store.dot index 01e97b6..1d95423 100644 --- a/clang/test/Analysis/exploded-graph-rewriter/store.dot +++ b/clang/test/Analysis/exploded-graph-rewriter/store.dot @@ -32,9 +32,7 @@ Node0x1 [shape=record,label= "program_state": { "environment": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": null, "store": { "pointer": "0x2", diff --git a/clang/test/Analysis/exploded-graph-rewriter/store_diff.dot b/clang/test/Analysis/exploded-graph-rewriter/store_diff.dot index 5c2fc9c..b7aeac7 100644 --- a/clang/test/Analysis/exploded-graph-rewriter/store_diff.dot +++ b/clang/test/Analysis/exploded-graph-rewriter/store_diff.dot @@ -18,9 +18,7 @@ Node0x1 [shape=record,label= "program_state": { "environment": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": null, "store": { "pointer": "0x2", @@ -73,9 +71,7 @@ Node0x4 [shape=record,label= "program_state": { "environment": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": null, "store": { "pointer": "0x5", diff --git a/clang/test/Analysis/exploded-graph-rewriter/topology.dot b/clang/test/Analysis/exploded-graph-rewriter/topology.dot index 56b4089..88ac53d 100644 --- a/clang/test/Analysis/exploded-graph-rewriter/topology.dot +++ b/clang/test/Analysis/exploded-graph-rewriter/topology.dot @@ -22,9 +22,7 @@ Node0x1 [shape=record,label= "program_state": { "environment": null, "constraints": null, - "dynamic_types": null, - "constructing_objects": null, - "index_of_element": null, + "dynamic_types": null, "checker_messages": [ { "checker": "foo", "messages": ["bar"] } ], diff --git a/clang/test/Analysis/expr-inspection.c b/clang/test/Analysis/expr-inspection.c index 92bd190..57cd2fc 100644 --- a/clang/test/Analysis/expr-inspection.c +++ b/clang/test/Analysis/expr-inspection.c @@ -46,8 +46,6 @@ void foo(int x) { // CHECK-NEXT: "disequality_info": null, // CHECK-NEXT: "dynamic_types": null, // CHECK-NEXT: "dynamic_casts": null, -// CHECK-NEXT: "constructing_objects": null, -// CHECK-NEXT: "index_of_element": null, // CHECK-NEXT: "checker_messages": null // CHECK-NEXT: } diff --git a/clang/utils/analyzer/exploded-graph-rewriter.py b/clang/utils/analyzer/exploded-graph-rewriter.py index 603bae9..bc447fe 100755 --- a/clang/utils/analyzer/exploded-graph-rewriter.py +++ b/clang/utils/analyzer/exploded-graph-rewriter.py @@ -261,48 +261,74 @@ class CheckerMessages: class ProgramState: def __init__(self, state_id, json_ps): logging.debug('Adding ProgramState ' + str(state_id)) + + store_key = 'store' + env_key = 'environment' + constraints_key = 'constraints' + dyn_ty_key = 'dynamic_types' + ctor_key = 'constructing_objects' + ind_key = 'index_of_element' + init_loop_key = 'pending_init_loops' + dtor_key = 'pending_destructors' + msg_key = 'checker_messages' if json_ps is None: json_ps = { - 'store': None, - 'environment': None, - 'constraints': None, - 'dynamic_types': None, - 'constructing_objects': None, - 'index_of_element': None, - 'checker_messages': None + store_key: None, + env_key: None, + constraints_key: None, + dyn_ty_key: None, + ctor_key: None, + ind_key: None, + init_loop_key: None, + dtor_key: None, + msg_key: None } self.state_id = state_id - self.store = Store(json_ps['store']) \ - if json_ps['store'] is not None else None + self.store = Store(json_ps[store_key]) \ + if json_ps[store_key] is not None else None self.environment = \ - GenericEnvironment(json_ps['environment']['items']) \ - if json_ps['environment'] is not None else None + GenericEnvironment(json_ps[env_key]['items']) \ + if json_ps[env_key] is not None else None self.constraints = GenericMap([ - (c['symbol'], c['range']) for c in json_ps['constraints'] - ]) if json_ps['constraints'] is not None else None + (c['symbol'], c['range']) for c in json_ps[constraints_key] + ]) if json_ps[constraints_key] is not None else None self.dynamic_types = GenericMap([ (t['region'], '%s%s' % (t['dyn_type'], ' (or a sub-class)' if t['sub_classable'] else '')) - for t in json_ps['dynamic_types']]) \ - if json_ps['dynamic_types'] is not None else None + for t in json_ps[dyn_ty_key]]) \ + if json_ps[dyn_ty_key] is not None else None + + self.checker_messages = CheckerMessages(json_ps[msg_key]) \ + if json_ps[msg_key] is not None else None + + # State traits + # + # For traits we always check if a key exists because if a trait + # has no imformation, nothing will be printed in the .dot file + # we parse. self.constructing_objects = \ - GenericEnvironment(json_ps['constructing_objects']) \ - if json_ps['constructing_objects'] is not None else None + GenericEnvironment(json_ps[ctor_key]) \ + if ctor_key in json_ps and json_ps[ctor_key] is not None else None self.index_of_element = \ - GenericEnvironment(json_ps['index_of_element']) \ - if json_ps['index_of_element'] is not None else None + GenericEnvironment(json_ps[ind_key]) \ + if ind_key in json_ps and json_ps[ind_key] is not None else None + + self.pending_init_loops = \ + GenericEnvironment(json_ps[init_loop_key]) \ + if init_loop_key in json_ps and json_ps[init_loop_key] is not None else None - self.checker_messages = CheckerMessages(json_ps['checker_messages']) \ - if json_ps['checker_messages'] is not None else None + self.pending_destructors = \ + GenericEnvironment(json_ps[dtor_key]) \ + if dtor_key in json_ps and json_ps[dtor_key] is not None else None # A deserialized exploded graph node. Has a default constructor because it @@ -801,6 +827,12 @@ class DotDumpVisitor: self.visit_environment_in_state('index_of_element', 'Indices Of Elements Under Construction', s, prev_s) + self.visit_environment_in_state('pending_init_loops', + 'Pending Array Init Loop Expressions', + s, prev_s) + self.visit_environment_in_state('pending_destructors', + 'Indices of Elements Under Destruction', + s, prev_s) self.visit_checker_messages_in_state(s, prev_s) def visit_node(self, node): -- 2.7.4