[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 CallEvent *Call) override;
/// printState - Called by ProgramStateManager to print checker-specific data.
void printState(raw_ostream &Out, ProgramStateRef State,
const LocationContext *LCtx, const char *NL,
unsigned int Space, bool IsDot) const override;
/// printJson - Called by ProgramStateManager to print checker-specific data.
void printJson(raw_ostream &Out, ProgramStateRef State,
const LocationContext *LCtx, const char *NL,
unsigned int Space, bool IsDot) const override;
ProgramStateManager &getStateManager() override { return StateMgr; }

View File

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

View File

@ -33,6 +33,7 @@
#include "clang/Analysis/ConstructionContext.h"
#include "clang/Analysis/ProgramPoint.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/JsonSupport.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/PrettyStackTrace.h"
@ -141,21 +142,47 @@ public:
return getLocationContext()->getDecl()->getASTContext();
}
void print(llvm::raw_ostream &OS, PrinterHelper *Helper, PrintingPolicy &PP) {
OS << "(LC" << getLocationContext()->getID() << ',';
if (const Stmt *S = getItem().getStmtOrNull())
OS << 'S' << S->getID(getASTContext());
void printJson(llvm::raw_ostream &Out, PrinterHelper *Helper,
PrintingPolicy &PP) const {
const Stmt *S = getItem().getStmtOrNull();
const CXXCtorInitializer *I = nullptr;
if (!S)
I = getItem().getCXXCtorInitializer();
// IDs
Out << "\"lctx_id\": " << getLocationContext()->getID() << ", ";
if (S)
Out << "\"stmt_id\": " << S->getID(getASTContext());
else
OS << 'I' << getItem().getCXXCtorInitializer()->getID(getASTContext());
OS << ',' << getItem().getKindAsString();
Out << "\"init_id\": " << I->getID(getASTContext());
// Kind
Out << ", \"kind\": \"" << getItem().getKindAsString()
<< "\", \"argument_index\": ";
if (getItem().getKind() == ConstructionContextItem::ArgumentKind)
OS << " #" << getItem().getIndex();
OS << ") ";
if (const Stmt *S = getItem().getStmtOrNull()) {
S->printPretty(OS, Helper, PP);
Out << getItem().getIndex() << '\"';
else
Out << "null";
// 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 {
const CXXCtorInitializer *I = getItem().getCXXCtorInitializer();
OS << I->getAnyMember()->getNameAsString();
Out << I->getAnyMember()->getNameAsString() << '\"';
}
}
@ -541,33 +568,69 @@ ExprEngine::processRegionChanges(ProgramStateRef state,
LCtx, Call);
}
static void printObjectsUnderConstructionForContext(raw_ostream &Out,
ProgramStateRef State,
const char *NL,
const LocationContext *LC) {
static void
printObjectsUnderConstructionJson(raw_ostream &Out, ProgramStateRef State,
const char *NL, const LocationContext *LCtx,
unsigned int Space = 0, bool IsDot = false) {
PrintingPolicy PP =
LC->getAnalysisDeclContext()->getASTContext().getPrintingPolicy();
for (auto I : State->get<ObjectsUnderConstruction>()) {
ConstructedObjectKey Key = I.first;
SVal Value = I.second;
if (Key.getLocationContext() != LC)
LCtx->getAnalysisDeclContext()->getASTContext().getPrintingPolicy();
++Space;
bool HasItem = false;
// 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;
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,
const LocationContext *LCtx, const char *NL,
unsigned int Space, bool IsDot) const {
if (LCtx) {
if (!State->get<ObjectsUnderConstruction>().isEmpty()) {
Out << "Objects under construction:" << NL;
void ExprEngine::printJson(raw_ostream &Out, ProgramStateRef State,
const LocationContext *LCtx, const char *NL,
unsigned int Space, bool IsDot) const {
Indent(Out, Space, IsDot) << "\"constructing_objects\": ";
LCtx->printJson(Out, NL, Space, IsDot, [&](const LocationContext *LC) {
printObjectsUnderConstructionForContext(Out, State, NL, LC);
});
}
if (LCtx && !State->get<ObjectsUnderConstruction>().isEmpty()) {
++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, "");

View File

@ -458,7 +458,7 @@ void ProgramState::printJson(raw_ostream &Out, const LocationContext *LCtx,
printDynamicTypeInfoJson(Out, this, NL, Space, IsDot);
// 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,

View File

@ -16,7 +16,9 @@ void foo() {
T t;
}
// CHECK: (LC1,S{{[0-9]*}},construct into local variable) T t;\n : &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\": \"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: \"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: ],
// CHECK-NEXT: "dynamic_types": null,
// CHECK-NEXT: "constructing_objects": null,