From 5df5eb8816361d8be84a5f99cda4344dbcb01f87 Mon Sep 17 00:00:00 2001 From: Csaba Dabis Date: Wed, 29 May 2019 15:43:26 +0000 Subject: [PATCH] [analyzer] print() JSONify: Constraints implementation Summary: - Reviewers: NoQ, xazax.hun, ravikandhadai, baloghadamsoftware, Szelethus Reviewed By: NoQ Subscribers: szepet, rnkovacs, a.sidorin, mikhail.ramalho, donat.nagy, dkrupp Tags: #clang Differential Revision: https://reviews.llvm.org/D62082 llvm-svn: 361978 --- .../Core/PathSensitive/ConstraintManager.h | 7 ++-- .../Core/PathSensitive/SMTConstraintManager.h | 34 +++++++++++---- .../lib/StaticAnalyzer/Core/ProgramState.cpp | 2 +- .../Core/RangeConstraintManager.cpp | 41 ++++++++++++------- clang/test/Analysis/expr-inspection.c | 5 ++- 5 files changed, 58 insertions(+), 31 deletions(-) diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h index 5b69299f7831..1baf8c57de86 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -162,10 +162,9 @@ public: virtual ProgramStateRef removeDeadBindings(ProgramStateRef state, SymbolReaper& SymReaper) = 0; - virtual void print(ProgramStateRef state, - raw_ostream &Out, - const char* nl, - const char *sep) = 0; + virtual void printJson(raw_ostream &Out, ProgramStateRef State, + const char *NL, unsigned int Space, + bool IsDot) const = 0; virtual void EndPath(ProgramStateRef state) {} diff --git a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h index fe097b92b3ae..1712501b13bd 100644 --- a/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h +++ b/clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONSTRAINTMANAGER_H #define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_SMTCONSTRAINTMANAGER_H +#include "clang/Basic/JsonSupport.h" #include "clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h" @@ -208,17 +209,32 @@ public: return State->set(CZ); } - void print(ProgramStateRef St, raw_ostream &OS, const char *nl, - const char *sep) override { + void printJson(raw_ostream &Out, ProgramStateRef State, const char *NL = "\n", + unsigned int Space = 0, bool IsDot = false) const override { + ConstraintSMTType Constraints = State->get(); - auto CZ = St->get(); - - OS << nl << sep << "Constraints:"; - for (auto I = CZ.begin(), E = CZ.end(); I != E; ++I) { - OS << nl << ' ' << I->first << " : "; - I->second->print(OS); + Indent(Out, Space, IsDot) << "\"constraints\": "; + if (Constraints.isEmpty()) { + Out << "null," << NL; + return; } - OS << nl; + + ++Space; + Out << '[' << NL; + for (ConstraintSMTType::iterator I = Constraints.begin(); + I != Constraints.end(); ++I) { + Indent(Out, Space, IsDot) + << "{ \"symbol\": \"" << I->first << "\", \"range\": \""; + I->second->print(Out); + Out << "\" }"; + + if (std::next(I) != Constraints.end()) + Out << ','; + Out << NL; + } + + --Space; + Indent(Out, Space, IsDot) << "],"; } bool haveEqualConstraints(ProgramStateRef S1, diff --git a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp index 911b96db2c99..090801f1abbf 100644 --- a/clang/lib/StaticAnalyzer/Core/ProgramState.cpp +++ b/clang/lib/StaticAnalyzer/Core/ProgramState.cpp @@ -452,7 +452,7 @@ void ProgramState::printJson(raw_ostream &Out, const LocationContext *LCtx, Env.printJson(Out, Context, LCtx, NL, Space, IsDot); // Print out the constraints. - Mgr.getConstraintManager().print(this, Out, NL, Sep); + Mgr.getConstraintManager().printJson(Out, this, NL, Space, IsDot); // Print out the tracked dynamic types. printDynamicTypeInfo(this, Out, NL, Sep); diff --git a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp index 5c3eb0d66a03..64724227395d 100644 --- a/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ b/clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/Basic/JsonSupport.h" #include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" @@ -261,8 +262,8 @@ public: ProgramStateRef removeDeadBindings(ProgramStateRef State, SymbolReaper &SymReaper) override; - void print(ProgramStateRef State, raw_ostream &Out, const char *nl, - const char *sep) override; + void printJson(raw_ostream &Out, ProgramStateRef State, const char *NL = "\n", + unsigned int Space = 0, bool IsDot = false) const override; //===------------------------------------------------------------------===// // Implementation for interface from RangedConstraintManager. @@ -754,25 +755,35 @@ ProgramStateRef RangeConstraintManager::assumeSymOutsideInclusiveRange( return New.isEmpty() ? nullptr : State->set(Sym, New); } -//===------------------------------------------------------------------------=== +//===----------------------------------------------------------------------===// // Pretty-printing. -//===------------------------------------------------------------------------===/ +//===----------------------------------------------------------------------===// -void RangeConstraintManager::print(ProgramStateRef St, raw_ostream &Out, - const char *nl, const char *sep) { +void RangeConstraintManager::printJson(raw_ostream &Out, ProgramStateRef State, + const char *NL, unsigned int Space, + bool IsDot) const { + ConstraintRangeTy Constraints = State->get(); - ConstraintRangeTy Ranges = St->get(); - - if (Ranges.isEmpty()) { - Out << nl << sep << "Ranges are empty." << nl; + Indent(Out, Space, IsDot) << "\"constraints\": "; + if (Constraints.isEmpty()) { + Out << "null," << NL; return; } - Out << nl << sep << "Ranges of symbol values:"; - for (ConstraintRangeTy::iterator I = Ranges.begin(), E = Ranges.end(); I != E; - ++I) { - Out << nl << ' ' << I.getKey() << " : "; + ++Space; + Out << '[' << NL; + for (ConstraintRangeTy::iterator I = Constraints.begin(); + I != Constraints.end(); ++I) { + Indent(Out, Space, IsDot) + << "{ \"symbol\": \"" << I.getKey() << "\", \"range\": \""; I.getData().print(Out); + Out << "\" }"; + + if (std::next(I) != Constraints.end()) + Out << ','; + Out << NL; } - Out << nl; + + --Space; + Indent(Out, Space, IsDot) << "]," << NL; } diff --git a/clang/test/Analysis/expr-inspection.c b/clang/test/Analysis/expr-inspection.c index fe3191eec9e9..461252d53726 100644 --- a/clang/test/Analysis/expr-inspection.c +++ b/clang/test/Analysis/expr-inspection.c @@ -33,6 +33,7 @@ void foo(int x) { // CHECK-NEXT: { "lctx_id": 1, "stmt_id": 847, "pretty": "clang_analyzer_printState", "value": "&code{clang_analyzer_printState}" } // CHECK-NEXT: ]} // CHECK-NEXT: ], +// CHECK-NEXT: "constraints": [ +// CHECK-NEXT: { "symbol": "reg_$0", "range": "{ [-2147483648, 13] }" } +// CHECK-NEXT: ], -// CHECK: Ranges of symbol values: -// CHECK-NEXT: reg_$0 : { [-2147483648, 13] }