Index: clang/include/clang/StaticAnalyzer/Core/CheckerManager.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -406,12 +406,15 @@ /// /// Unlike most other callbacks, any checker can simply implement the virtual /// method CheckerBase::printState if it has custom data to print. - /// \param Out The output stream + /// + /// \param Out The output stream /// \param State The state being printed - /// \param NL The preferred representation of a newline. - /// \param Sep The preferred separator between different kinds of data. + /// \param NL The preferred representation of a newline. + /// \param Sep The preferred separator between different messages. + /// \param Space The preferred space between the left side and the message. void runCheckersForPrintState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep); + const char *NL = "\n", const char *Sep = "", + unsigned int Space = 0) const; //===----------------------------------------------------------------------===// // Internal registration functions for AST traversing. Index: clang/lib/StaticAnalyzer/Core/CheckerManager.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CheckerManager.cpp +++ clang/lib/StaticAnalyzer/Core/CheckerManager.cpp @@ -14,6 +14,7 @@ #include "clang/AST/DeclBase.h" #include "clang/AST/Stmt.h" #include "clang/Analysis/ProgramPoint.h" +#include "clang/Basic/JsonSupport.h" #include "clang/Basic/LLVM.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/StaticAnalyzer/Core/Checker.h" @@ -700,9 +701,42 @@ void CheckerManager::runCheckersForPrintState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep) { - for (const auto &CheckerTag : CheckerTags) - CheckerTag.second->printState(Out, State, NL, Sep); + const char *NL, const char *Sep, + unsigned int Space) const { + Indent(Out, Space) + << "\"checker_messages\": { \"title\": \"Checker messages\", \"items\": "; + + SmallString<1024> Buf; + llvm::raw_svector_ostream TempOut(Buf); + + ++Space; + bool HasMessage = false; + for (const auto &CheckerTag : CheckerTags) { + CheckerTag.second->printState(TempOut, State, NL, Sep); + + if (Buf.empty()) + continue; + + if (!HasMessage) { + Out << '[' << NL; + HasMessage = true; + } + + Indent(Out, Space) << "{ \"checker\": \"" + << CheckerTag.second->getCheckName().getName() + << "\", \"message\": \"" << Buf.str().trim(Sep) + << "\" }," << NL; + + Buf.clear(); + } + + --Space; + if (HasMessage) + Indent(Out, Space) << "]},"; + else + Out << "null },"; + + Out << NL; } //===----------------------------------------------------------------------===// Index: clang/test/Analysis/expr-inspection.c =================================================================== --- clang/test/Analysis/expr-inspection.c +++ clang/test/Analysis/expr-inspection.c @@ -38,3 +38,5 @@ // CHECK-NEXT: ]}, // CHECK-NEXT: "dynamic_types": { "title": "Dynamic types", "items": null }, // CHECK-NEXT: "constructing_objects": { "title": "Objects under construction", "items": null }, +// CHECK-NEXT: "checker_messages": { "title": "Checker messages", "items": null }, +