Index: clang/include/clang/StaticAnalyzer/Core/CheckerManager.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/CheckerManager.h +++ clang/include/clang/StaticAnalyzer/Core/CheckerManager.h @@ -406,16 +406,20 @@ /// /// 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. + /// \param IsDot Whether the message will be printed in 'dot' format. void runCheckersForPrintState(raw_ostream &Out, ProgramStateRef State, - const char *NL, const char *Sep); + const char *NL = "\n", unsigned int Space = 0, + bool IsDot = false) const; -//===----------------------------------------------------------------------===// -// Internal registration functions for AST traversing. -//===----------------------------------------------------------------------===// + //===----------------------------------------------------------------------===// + // Internal registration functions for AST traversing. + //===----------------------------------------------------------------------===// // Functions used by the registration mechanism, checkers should not touch // these directly. 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,54 @@ 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, + unsigned int Space, + bool IsDot) const { + Indent(Out, Space, IsDot) << "\"checker_messages\": "; + + // Create a temporary stream to see whether we have any message. + SmallString<1024> TempBuf; + llvm::raw_svector_ostream TempOut(TempBuf); + unsigned int InnerSpace = Space + 2; + + // Create the new-line in JSON with enough space. + SmallString<128> NewLineJSON; + llvm::raw_svector_ostream NLOut(NewLineJSON); + NLOut << "\", " << NL; // Inject the ending and a new line + Indent(NLOut, InnerSpace, IsDot) << "\""; // then begin the next message. + + ++Space; + bool HasMessage = false; + for (const auto &CheckerTag : CheckerTags) { + // See whether the current checker has a message. + CheckerTag.second->printState(TempOut, State, /*NL=*/NewLineJSON.c_str(), + /*Sep=*/""); + + if (TempBuf.empty()) + continue; + + if (!HasMessage) { + Out << '[' << NL; + HasMessage = true; + } + + Indent(Out, Space, IsDot) + << "{ \"checker\": \"" << CheckerTag.second->getCheckName().getName() + << "\", \"messages\": [" << NL; + Indent(Out, InnerSpace, IsDot) + << '\"' << TempBuf.str().trim() << "\"," << NL; + Indent(Out, Space, IsDot) << "]}," << NL; + + TempBuf.clear(); + } + + --Space; + if (HasMessage) + Indent(Out, Space, IsDot) << "],"; + else + Out << "null,"; + + Out << NL; } //===----------------------------------------------------------------------===// Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -618,7 +618,7 @@ Out << "null," << NL; } - getCheckerManager().runCheckersForPrintState(Out, State, NL, ""); + getCheckerManager().runCheckersForPrintState(Out, State, NL, Space, IsDot); } void ExprEngine::processEndWorklist() { 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": null, // CHECK-NEXT: "constructing_objects": null, +// CHECK-NEXT: "checker_messages": null, +