Index: include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/ConstraintManager.h @@ -162,10 +162,9 @@ 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) {} Index: include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/SMTConstraintManager.h +++ 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 @@ return State->set(CZ); } - void print(ProgramStateRef St, raw_ostream &OS, const char *nl, - const char *sep) override { - - auto CZ = St->get(); + void printJson(raw_ostream &Out, ProgramStateRef State, const char *NL = "\n", + unsigned int Space = 0, bool IsDot = false) const override { + ConstraintSMTType Constraints = State->get(); + + Indent(Out, Space, IsDot) << "\"constraints\": "; + if (Constraints.isEmpty()) { + Out << "null," << NL; + return; + } - OS << nl << sep << "Constraints:"; - for (auto I = CZ.begin(), E = CZ.end(); I != E; ++I) { - OS << nl << ' ' << I->first << " : "; - I->second->print(OS); + ++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; } - OS << nl; + + --Space; + Indent(Out, Space, IsDot) << "],"; } bool haveEqualConstraints(ProgramStateRef S1, Index: lib/StaticAnalyzer/Core/ProgramState.cpp =================================================================== --- lib/StaticAnalyzer/Core/ProgramState.cpp +++ lib/StaticAnalyzer/Core/ProgramState.cpp @@ -452,7 +452,7 @@ 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); Index: lib/StaticAnalyzer/Core/RangeConstraintManager.cpp =================================================================== --- lib/StaticAnalyzer/Core/RangeConstraintManager.cpp +++ 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 @@ 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 @@ return New.isEmpty() ? nullptr : State->set(Sym, New); } -//===------------------------------------------------------------------------=== +//===----------------------------------------------------------------------===// // Pretty-printing. -//===------------------------------------------------------------------------===/ - -void RangeConstraintManager::print(ProgramStateRef St, raw_ostream &Out, - const char *nl, const char *sep) { - - ConstraintRangeTy Ranges = St->get(); +//===----------------------------------------------------------------------===// - if (Ranges.isEmpty()) { - Out << nl << sep << "Ranges are empty." << nl; +void RangeConstraintManager::printJson(raw_ostream &Out, ProgramStateRef State, + const char *NL, unsigned int Space, + bool IsDot) const { + ConstraintRangeTy Constraints = State->get(); + + 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; } Index: test/Analysis/expr-inspection.c =================================================================== --- test/Analysis/expr-inspection.c +++ test/Analysis/expr-inspection.c @@ -33,6 +33,7 @@ // 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] }