[analyzer] print() JSONify: Constructing objects 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/D62085

llvm-svn: 361980
This commit is contained in:
Csaba Dabis 2019-05-29 15:58:26 +00:00
parent 32981637ce
commit 35e54eb31e
6 changed files with 111 additions and 45 deletions

View File

@ -376,10 +376,10 @@ public:
const LocationContext *LCtx, const LocationContext *LCtx,
const CallEvent *Call) override; const CallEvent *Call) override;
/// printState - Called by ProgramStateManager to print checker-specific data. /// printJson - Called by ProgramStateManager to print checker-specific data.
void printState(raw_ostream &Out, ProgramStateRef State, void printJson(raw_ostream &Out, ProgramStateRef State,
const LocationContext *LCtx, const char *NL, const LocationContext *LCtx, const char *NL,
unsigned int Space, bool IsDot) const override; unsigned int Space, bool IsDot) const override;
ProgramStateManager &getStateManager() override { return StateMgr; } ProgramStateManager &getStateManager() override { return StateMgr; }

View File

@ -158,10 +158,10 @@ public:
const CallEvent *Call, const CallEvent *Call,
RegionAndSymbolInvalidationTraits &HTraits) = 0; RegionAndSymbolInvalidationTraits &HTraits) = 0;
/// printState - Called by ProgramStateManager to print checker-specific data. /// printJson - Called by ProgramStateManager to print checker-specific data.
virtual void printState(raw_ostream &Out, ProgramStateRef State, virtual void printJson(raw_ostream &Out, ProgramStateRef State,
const LocationContext *LCtx, const char *NL, const LocationContext *LCtx, const char *NL,
unsigned int Space, bool IsDot) const = 0; unsigned int Space, bool IsDot) const = 0;
/// Called by CoreEngine when the analysis worklist is either empty or the /// Called by CoreEngine when the analysis worklist is either empty or the
// maximum number of analysis steps have been reached. // maximum number of analysis steps have been reached.

View File

@ -33,6 +33,7 @@
#include "clang/Analysis/ConstructionContext.h" #include "clang/Analysis/ConstructionContext.h"
#include "clang/Analysis/ProgramPoint.h" #include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/IdentifierTable.h" #include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/JsonSupport.h"
#include "clang/Basic/LLVM.h" #include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h" #include "clang/Basic/LangOptions.h"
#include "clang/Basic/PrettyStackTrace.h" #include "clang/Basic/PrettyStackTrace.h"
@ -141,21 +142,47 @@ public:
return getLocationContext()->getDecl()->getASTContext(); return getLocationContext()->getDecl()->getASTContext();
} }
void print(llvm::raw_ostream &OS, PrinterHelper *Helper, PrintingPolicy &PP) { void printJson(llvm::raw_ostream &Out, PrinterHelper *Helper,
OS << "(LC" << getLocationContext()->getID() << ','; PrintingPolicy &PP) const {
if (const Stmt *S = getItem().getStmtOrNull()) const Stmt *S = getItem().getStmtOrNull();
OS << 'S' << S->getID(getASTContext()); const CXXCtorInitializer *I = nullptr;
if (!S)
I = getItem().getCXXCtorInitializer();
// IDs
Out << "\"lctx_id\": " << getLocationContext()->getID() << ", ";
if (S)
Out << "\"stmt_id\": " << S->getID(getASTContext());
else else
OS << 'I' << getItem().getCXXCtorInitializer()->getID(getASTContext()); Out << "\"init_id\": " << I->getID(getASTContext());
OS << ',' << getItem().getKindAsString();
// Kind
Out << ", \"kind\": \"" << getItem().getKindAsString()
<< "\", \"argument_index\": ";
if (getItem().getKind() == ConstructionContextItem::ArgumentKind) if (getItem().getKind() == ConstructionContextItem::ArgumentKind)
OS << " #" << getItem().getIndex(); Out << getItem().getIndex() << '\"';
OS << ") "; else
if (const Stmt *S = getItem().getStmtOrNull()) { Out << "null";
S->printPretty(OS, Helper, PP);
// Pretty-print
Out << ", \"pretty\": \"";
if (S) {
llvm::SmallString<256> TempBuf;
llvm::raw_svector_ostream TempOut(TempBuf);
// See whether the current statement is pretty-printable.
S->printPretty(TempOut, Helper, PP);
if (!TempBuf.empty()) {
Out << TempBuf.str().trim() << '\"';
TempBuf.clear();
} else {
Out << "null";
}
} else { } else {
const CXXCtorInitializer *I = getItem().getCXXCtorInitializer(); Out << I->getAnyMember()->getNameAsString() << '\"';
OS << I->getAnyMember()->getNameAsString();
} }
} }
@ -541,33 +568,69 @@ ExprEngine::processRegionChanges(ProgramStateRef state,
LCtx, Call); LCtx, Call);
} }
static void printObjectsUnderConstructionForContext(raw_ostream &Out, static void
ProgramStateRef State, printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State,
const char *NL, const char *NL, const LocationContext *LCtx,
const LocationContext *LC) { unsigned int Space = 0, bool IsDot = false) {
PrintingPolicy PP = PrintingPolicy PP =
LC->getAnalysisDeclContext()->getASTContext().getPrintingPolicy(); LCtx->getAnalysisDeclContext()->getASTContext().getPrintingPolicy();
for (auto I : State->get<ObjectsUnderConstruction>()) {
ConstructedObjectKey Key = I.first; ++Space;
SVal Value = I.second; bool HasItem = false;
if (Key.getLocationContext() != LC)
// Store the last key.
const ConstructedObjectKey *LastKey = nullptr;
for (const auto &I : State->get<ObjectsUnderConstruction>()) {
const ConstructedObjectKey &Key = I.first;
if (Key.getLocationContext() != LCtx)
continue; continue;
Key.print(Out, nullptr, PP);
Out << " : " << Value << NL; if (!HasItem) {
Out << "[" << NL;
HasItem = true;
}
LastKey = &Key;
}
for (const auto &I : State->get<ObjectsUnderConstruction>()) {
const ConstructedObjectKey &Key = I.first;
SVal Value = I.second;
if (Key.getLocationContext() != LCtx)
continue;
Indent(Out, Space, IsDot) << "{ ";
Key.printJson(Out, nullptr, PP);
Out << ", \"value\": \"" << Value << "\" }";
if (&Key != LastKey)
Out << ',';
Out << NL;
}
if (HasItem)
Indent(Out, --Space, IsDot) << ']'; // End of "location_context".
else {
Out << "null ";
} }
} }
void ExprEngine::printState(raw_ostream &Out, ProgramStateRef State, void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State,
const LocationContext *LCtx, const char *NL, const LocationContext *LCtx, const char *NL,
unsigned int Space, bool IsDot) const { unsigned int Space, bool IsDot) const {
if (LCtx) { Indent(Out, Space, IsDot) << "\"constructing_objects\": ";
if (!State->get<ObjectsUnderConstruction>().isEmpty()) {
Out << "Objects under construction:" << NL;
LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) { if (LCtx && !State->get<ObjectsUnderConstruction>().isEmpty()) {
printObjectsUnderConstructionForContext(Out, State, NL, LC); ++Space;
}); Out << '[' << NL;
} LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
printObjectsUnderConstructionJson(Out, State, NL, LC, Space, IsDot);
});
--Space;
Indent(Out, Space, IsDot) << "]," << NL; // End of "constructing_objects".
} else {
Out << "null," << NL;
} }
getCheckerManager().runCheckersForPrintState(Out, State, NL, ""); getCheckerManager().runCheckersForPrintState(Out, State, NL, "");

View File

@ -458,7 +458,7 @@ void ProgramState::printJson(raw_ostream &Out, const LocationContext *LCtx,
printDynamicTypeInfoJson(Out, this, NL, Space, IsDot); printDynamicTypeInfoJson(Out, this, NL, Space, IsDot);
// Print checker-specific data. // Print checker-specific data.
Mgr.getOwningEngine().printState(Out, this, LCtx, NL, Space, IsDot); Mgr.getOwningEngine().printJson(Out, this, LCtx, NL, Space, IsDot);
} }
void ProgramState::printDOT(raw_ostream &Out, const LocationContext *LCtx, void ProgramState::printDOT(raw_ostream &Out, const LocationContext *LCtx,

View File

@ -16,7 +16,9 @@ void foo() {
T t; T t;
} }
// CHECK: (LC1,S{{[0-9]*}},construct into local variable) T t;\n : &t // CHECK: \"constructing_objects\": [\l&nbsp;&nbsp;\{ \"location_context\": \"#0 Call\", \"calling\": \"foo\", \"call_line\": null, \"items\": [\l&nbsp;&nbsp;&nbsp;&nbsp;\{ \"lctx_id\": 1, \"stmt_id\": 1155, \"kind\": \"construct into local variable\", \"argument_index\": null, \"pretty\": \"T t;\"
// CHECK: (LC2,I{{[0-9]*}},construct into member variable) s : &t-\>s
// CHECK: conj_$5\{int, LC3, no stmt, #1\} // CHECK: \"constructing_objects\": [\l&nbsp;&nbsp;\{ \"location_context\": \"#0 Call\", \"calling\": \"T::T\", \"call_line\": \"16\", \"items\": [\l&nbsp;&nbsp;&nbsp;&nbsp;\{ \"lctx_id\": 2, \"init_id\": 1092, \"kind\": \"construct into member variable\", \"argument_index\": null, \"pretty\": \"s\", \"value\": \"&t-\>s\"
// CHECK: \"store\": [\l&nbsp;&nbsp;\{ \"cluster\": \"t\", \"items\": [\l&nbsp;&nbsp;&nbsp;&nbsp;\{ \"kind\": \"Default\", \"offset\": 0, \"value\": \"conj_$3\{int, LC3, no stmt, #1\}\"

View File

@ -37,3 +37,4 @@ void foo(int x) {
// CHECK-NEXT: { "symbol": "reg_$0<int x>", "range": "{ [-2147483648, 13] }" } // CHECK-NEXT: { "symbol": "reg_$0<int x>", "range": "{ [-2147483648, 13] }" }
// CHECK-NEXT: ], // CHECK-NEXT: ],
// CHECK-NEXT: "dynamic_types": null, // CHECK-NEXT: "dynamic_types": null,
// CHECK-NEXT: "constructing_objects": null,