Skip to content

Commit

Permalink
[analyzer][AST] print() JSONify: Stmt implementation
Browse files Browse the repository at this point in the history
Summary:
This patch also adds a function called `JsonFormat()` which:
- Flattens the string so removes the new-lines.
- Escapes double quotes.

Reviewers: NoQ, xazax.hun, ravikandhadai, baloghadamsoftware, Szelethus

Reviewed By: NoQ

Subscribers: cfe-commits, szepet, rnkovacs, a.sidorin, mikhail.ramalho,
             donat.nagy, dkrupp

Tags: #clang

Differential Revision: https://reviews.llvm.org/D62494

llvm-svn: 362000
  • Loading branch information
Charusso committed May 29, 2019
1 parent 03e1a82 commit 9ee26c8
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 54 deletions.
4 changes: 4 additions & 0 deletions clang/include/clang/AST/Stmt.h
Expand Up @@ -1100,6 +1100,10 @@ class alignas(void *) Stmt {
StringRef NewlineSymbol = "\n",
const ASTContext *Context = nullptr) const;

/// Pretty-prints in JSON format.
void printJson(raw_ostream &Out, PrinterHelper *Helper,
const PrintingPolicy &Policy, bool AddQuotes) const;

/// viewAST - Visualize an AST rooted at this Stmt* using GraphViz. Only
/// works on systems with GraphViz (Mac OS X) or dot+gv installed.
void viewAST() const;
Expand Down
36 changes: 36 additions & 0 deletions clang/include/clang/Basic/JsonSupport.h
Expand Up @@ -10,6 +10,7 @@
#define LLVM_CLANG_BASIC_JSONSUPPORT_H

#include "clang/Basic/LLVM.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"


Expand All @@ -22,6 +23,41 @@ inline raw_ostream &Indent(raw_ostream &Out, const unsigned int Space,
return Out;
}

inline std::string JsonFormat(StringRef RawSR, bool AddQuotes) {
if (RawSR.empty())
return "null";

// Trim special characters.
std::string Str = RawSR.trim().str();
size_t Pos = 0;

// Escape double quotes.
while (true) {
Pos = Str.find('\"', Pos);
if (Pos == std::string::npos)
break;

// Prevent bad conversions.
size_t TempPos = (Pos != 0) ? Pos - 1 : 0;

// See whether the current double quote is escaped.
if (TempPos != Str.find("\\\"", TempPos)) {
Str.insert(Pos, "\\");
++Pos; // As we insert the escape-character move plus one.
}

++Pos;
}

// Remove new-lines.
Str.erase(std::remove(Str.begin(), Str.end(), '\n'), Str.end());

if (!AddQuotes)
return Str;

return '\"' + Str + '\"';
}

} // namespace clang

#endif // LLVM_CLANG_BASIC_JSONSUPPORT_H
20 changes: 15 additions & 5 deletions clang/lib/AST/StmtPrinter.cpp
Expand Up @@ -36,6 +36,7 @@
#include "clang/Basic/CharInfo.h"
#include "clang/Basic/ExpressionTraits.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/JsonSupport.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/Lambda.h"
#include "clang/Basic/OpenMPKinds.h"
Expand Down Expand Up @@ -2395,12 +2396,21 @@ void Stmt::dumpPretty(const ASTContext &Context) const {
printPretty(llvm::errs(), nullptr, PrintingPolicy(Context.getLangOpts()));
}

void Stmt::printPretty(raw_ostream &OS, PrinterHelper *Helper,
void Stmt::printPretty(raw_ostream &Out, PrinterHelper *Helper,
const PrintingPolicy &Policy, unsigned Indentation,
StringRef NL,
const ASTContext *Context) const {
StmtPrinter P(OS, Helper, Policy, Indentation, NL, Context);
P.Visit(const_cast<Stmt*>(this));
StringRef NL, const ASTContext *Context) const {
StmtPrinter P(Out, Helper, Policy, Indentation, NL, Context);
P.Visit(const_cast<Stmt *>(this));
}

void Stmt::printJson(raw_ostream &Out, PrinterHelper *Helper,
const PrintingPolicy &Policy, bool AddQuotes) const {
std::string Buf;
llvm::raw_string_ostream TempOut(Buf);

printPretty(TempOut, Helper, Policy);

Out << JsonFormat(TempOut.str(), AddQuotes);
}

//===----------------------------------------------------------------------===//
Expand Down
49 changes: 22 additions & 27 deletions clang/lib/Analysis/ProgramPoint.cpp
Expand Up @@ -46,8 +46,8 @@ LLVM_DUMP_METHOD void ProgramPoint::dump() const {
return printJson(llvm::errs());
}

static void printLocation(raw_ostream &Out, SourceLocation Loc,
const SourceManager &SM) {
static void printLocJson(raw_ostream &Out, SourceLocation Loc,
const SourceManager &SM) {
Out << "\"location\": ";
if (!Loc.isFileID()) {
Out << "null";
Expand All @@ -62,6 +62,8 @@ void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
const ASTContext &Context =
getLocationContext()->getAnalysisDeclContext()->getASTContext();
const SourceManager &SM = Context.getSourceManager();
const PrintingPolicy &PP = Context.getPrintingPolicy();
const bool AddQuotes = true;

Out << "\"kind\": \"";
switch (getKind()) {
Expand All @@ -78,9 +80,8 @@ void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
<< ", \"stmt_id\": ";

if (const ReturnStmt *RS = FEP->getStmt()) {
Out << RS->getID(Context) << ", \"stmt\": \"";
RS->printPretty(Out, /*Helper=*/nullptr, Context.getPrintingPolicy());
Out << '\"';
Out << RS->getID(Context) << ", \"stmt\": ";
RS->printJson(Out, nullptr, PP, AddQuotes);
} else {
Out << "null, \"stmt\": null";
}
Expand Down Expand Up @@ -118,7 +119,7 @@ void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
Out << "PreCall\", \"stmt\": \"";
PC.getDecl()->print(Out, Context.getLangOpts());
Out << "\", ";
printLocation(Out, PC.getLocation(), SM);
printLocJson(Out, PC.getLocation(), SM);
break;
}

Expand All @@ -127,7 +128,7 @@ void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
Out << "PostCall\", \"stmt\": \"";
PC.getDecl()->print(Out, Context.getLangOpts());
Out << "\", ";
printLocation(Out, PC.getLocation(), SM);
printLocJson(Out, PC.getLocation(), SM);
break;
}

Expand Down Expand Up @@ -157,23 +158,26 @@ void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {

E.getSrc()->printTerminator(Out, Context.getLangOpts());
Out << "\", ";
printLocation(Out, T->getBeginLoc(), SM);
Out << ", \"term_kind\": \"";
printLocJson(Out, T->getBeginLoc(), SM);

Out << ", \"term_kind\": \"";
if (isa<SwitchStmt>(T)) {
Out << "SwitchStmt\", \"case\": ";
if (const Stmt *Label = E.getDst()->getLabel()) {
if (const auto *C = dyn_cast<CaseStmt>(Label)) {
Out << "{ \"lhs\": ";
if (const Stmt *LHS = C->getLHS())
LHS->printPretty(Out, nullptr, Context.getPrintingPolicy());
else
if (const Stmt *LHS = C->getLHS()) {
LHS->printJson(Out, nullptr, PP, AddQuotes);
} else {
Out << "null";
}

Out << ", \"rhs\": ";
if (const Stmt *RHS = C->getRHS())
RHS->printPretty(Out, nullptr, Context.getPrintingPolicy());
else
if (const Stmt *RHS = C->getRHS()) {
RHS->printJson(Out, nullptr, PP, AddQuotes);
} else {
Out << "null";
}
Out << " }";
} else {
assert(isa<DefaultStmt>(Label));
Expand All @@ -196,23 +200,14 @@ void ProgramPoint::printJson(llvm::raw_ostream &Out, const char *NL) const {
const Stmt *S = castAs<StmtPoint>().getStmt();
assert(S != nullptr && "Expecting non-null Stmt");

llvm::SmallString<256> TempBuf;
llvm::raw_svector_ostream TempOut(TempBuf);

Out << "Statement\", \"stmt_kind\": \"" << S->getStmtClassName()
<< "\", \"stmt_id\": " << S->getID(Context)
<< ", \"pointer\": \"" << (const void *)S << "\", \"pretty\": ";

// See whether the current statement is pretty-printable.
S->printPretty(TempOut, /*Helper=*/nullptr, Context.getPrintingPolicy());
if (!TempBuf.empty()) {
Out << '\"' << TempBuf.str().trim() << "\", ";
TempBuf.clear();
} else {
Out << "null, ";
}
S->printJson(Out, nullptr, PP, AddQuotes);

printLocation(Out, S->getBeginLoc(), SM);
Out << ", ";
printLocJson(Out, S->getBeginLoc(), SM);

Out << ", \"stmt_point_kind\": ";
if (getAs<PreStmt>())
Expand Down
12 changes: 1 addition & 11 deletions clang/lib/StaticAnalyzer/Core/Environment.cpp
Expand Up @@ -235,9 +235,6 @@ void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
bool HasItem = false;
unsigned int InnerSpace = Space + 1;

llvm::SmallString<256> TempBuf;
llvm::raw_svector_ostream TempOut(TempBuf);

// Store the last ExprBinding which we will print.
BindingsTy::iterator LastI = ExprBindings.end();
for (BindingsTy::iterator I = ExprBindings.begin(); I != ExprBindings.end();
Expand Down Expand Up @@ -266,14 +263,7 @@ void Environment::printJson(raw_ostream &Out, const ASTContext &Ctx,
<< "{ \"lctx_id\": " << LC->getID()
<< ", \"stmt_id\": " << S->getID(Ctx) << ", \"pretty\": ";

// See whether the current statement is pretty-printable.
S->printPretty(TempOut, /*Helper=*/nullptr, PP);
if (!TempBuf.empty()) {
Out << '\"' << TempBuf.str().trim() << '\"';
TempBuf.clear();
} else {
Out << "null";
}
S->printJson(Out, nullptr, PP, /*AddQuotes=*/true);

Out << ", \"value\": \"" << I->second << "\" }";

Expand Down
12 changes: 1 addition & 11 deletions clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Expand Up @@ -170,17 +170,7 @@ class ConstructedObjectKey {
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";
}
S->printJson(Out, Helper, PP, /*AddQuotes=*/true);
} else {
Out << '\"' << I->getAnyMember()->getNameAsString() << '\"';
}
Expand Down

0 comments on commit 9ee26c8

Please sign in to comment.