[analyzer] ExplodedGraph printing fixes

Fixes a number of issues:

 - Global variables are not used for communication
 - Trait should be defined on a graph, not on a node
 - Defining the trait on a graph allows us to use a correct allocator,
   no longer crashing while printing trimmed graphs

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

llvm-svn: 342413
This commit is contained in:
George Karpenkov 2018-09-17 20:46:53 +00:00
parent b1f9e4d285
commit 8639c5d565
3 changed files with 36 additions and 66 deletions

View File

@ -461,12 +461,15 @@ public:
namespace llvm {
template<> struct GraphTraits<clang::ento::ExplodedNode*> {
template <> struct GraphTraits<clang::ento::ExplodedGraph *> {
using GraphTy = clang::ento::ExplodedGraph *;
using NodeRef = clang::ento::ExplodedNode *;
using ChildIteratorType = clang::ento::ExplodedNode::succ_iterator;
using nodes_iterator = llvm::df_iterator<NodeRef>;
using nodes_iterator = llvm::df_iterator<GraphTy>;
static NodeRef getEntryNode(NodeRef N) { return N; }
static NodeRef getEntryNode(const GraphTy G) {
return *G->roots_begin();
}
static ChildIteratorType child_begin(NodeRef N) {
if (N->succ_size() == 1 && (*N->succ_begin())->isTrivial()) {
@ -482,27 +485,14 @@ namespace llvm {
return N->succ_end();
}
static nodes_iterator nodes_begin(NodeRef N) { return df_begin(N); }
static nodes_iterator nodes_begin(const GraphTy G) {
return df_begin(G);
}
static nodes_iterator nodes_end(NodeRef N) { return df_end(N); }
static nodes_iterator nodes_end(const GraphTy G) {
return df_end(G);
}
};
template<> struct GraphTraits<const clang::ento::ExplodedNode*> {
using NodeRef = const clang::ento::ExplodedNode *;
using ChildIteratorType = clang::ento::ExplodedNode::const_succ_iterator;
using nodes_iterator = llvm::df_iterator<NodeRef>;
static NodeRef getEntryNode(NodeRef N) { return N; }
static ChildIteratorType child_begin(NodeRef N) { return N->succ_begin(); }
static ChildIteratorType child_end(NodeRef N) { return N->succ_end(); }
static nodes_iterator nodes_begin(NodeRef N) { return df_begin(N); }
static nodes_iterator nodes_end(NodeRef N) { return df_end(N); }
};
} // namespace llvm
#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_EXPLODEDGRAPH_H

View File

@ -226,7 +226,7 @@ void Environment::print(raw_ostream &Out, const char *NL,
PrintingPolicy PP = Context.getPrintingPolicy();
Out << NL << NL << "Expressions by stack frame:" << NL;
Out << NL << "Expressions by stack frame:" << NL;
WithLC->dumpStack(Out, "", NL, Sep, [&](const LocationContext *LC) {
for (auto I : ExprBindings) {
if (I.first.getLocationContext() != LC)

View File

@ -2947,35 +2947,37 @@ void ExprEngine::VisitMSAsmStmt(const MSAsmStmt *A, ExplodedNode *Pred,
//===----------------------------------------------------------------------===//
#ifndef NDEBUG
static ExprEngine* GraphPrintCheckerState;
static SourceManager* GraphPrintSourceManager;
namespace llvm {
template<>
struct DOTGraphTraits<ExplodedNode*> : public DefaultDOTGraphTraits {
struct DOTGraphTraits<ExplodedGraph*> : public DefaultDOTGraphTraits {
DOTGraphTraits (bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
// FIXME: Since we do not cache error nodes in ExprEngine now, this does not
// work.
static std::string getNodeAttributes(const ExplodedNode *N, void*) {
static std::string getNodeAttributes(const ExplodedNode *N,
ExplodedGraph *G) {
return {};
}
// De-duplicate some source location pretty-printing.
static void printLocation(raw_ostream &Out, SourceLocation SLoc) {
static void printLocation(raw_ostream &Out,
SourceLocation SLoc,
const SourceManager &SM,
StringRef Postfix="\\l") {
if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getExpansionLineNumber(SLoc)
<< SM.getExpansionLineNumber(SLoc)
<< " col="
<< GraphPrintSourceManager->getExpansionColumnNumber(SLoc)
<< "\\l";
<< SM.getExpansionColumnNumber(SLoc)
<< Postfix;
}
}
static void dumpProgramPoint(ProgramPoint Loc,
const ASTContext &Context,
llvm::raw_string_ostream &Out) {
const SourceManager &SM = Context.getSourceManager();
switch (Loc.getKind()) {
case ProgramPoint::BlockEntranceKind:
Out << "Block Entrance: B"
@ -3020,7 +3022,7 @@ struct DOTGraphTraits<ExplodedNode*> : public DefaultDOTGraphTraits {
ImplicitCallPoint PC = Loc.castAs<ImplicitCallPoint>();
Out << "PreCall: ";
PC.getDecl()->print(Out, Context.getLangOpts());
printLocation(Out, PC.getLocation());
printLocation(Out, PC.getLocation(), SM);
break;
}
@ -3028,7 +3030,7 @@ struct DOTGraphTraits<ExplodedNode*> : public DefaultDOTGraphTraits {
ImplicitCallPoint PC = Loc.castAs<ImplicitCallPoint>();
Out << "PostCall: ";
PC.getDecl()->print(Out, Context.getLangOpts());
printLocation(Out, PC.getLocation());
printLocation(Out, PC.getLocation(), SM);
break;
}
@ -3056,13 +3058,7 @@ struct DOTGraphTraits<ExplodedNode*> : public DefaultDOTGraphTraits {
Out << "\\|Terminator: ";
E.getSrc()->printTerminator(Out, Context.getLangOpts());
if (SLoc.isFileID()) {
Out << "\\lline="
<< GraphPrintSourceManager->getExpansionLineNumber(SLoc)
<< " col="
<< GraphPrintSourceManager->getExpansionColumnNumber(SLoc);
}
printLocation(Out, SLoc, SM, /*Postfix=*/"");
if (isa<SwitchStmt>(T)) {
const Stmt *Label = E.getDst()->getLabel();
@ -3112,7 +3108,7 @@ struct DOTGraphTraits<ExplodedNode*> : public DefaultDOTGraphTraits {
<< S->getID(Context) << " <" << (const void *)S << "> ";
S->printPretty(Out, /*helper=*/nullptr, Context.getPrintingPolicy(),
/*Indentation=*/2, /*NewlineSymbol=*/"\\l");
printLocation(Out, S->getBeginLoc());
printLocation(Out, S->getBeginLoc(), SM, /*Postfix=*/"");
if (Loc.getAs<PreStmt>())
Out << "\\lPreStmt\\l";
@ -3134,7 +3130,7 @@ struct DOTGraphTraits<ExplodedNode*> : public DefaultDOTGraphTraits {
return N->isTrivial();
}
static std::string getNodeLabel(const ExplodedNode *N, void*){
static std::string getNodeLabel(const ExplodedNode *N, ExplodedGraph *G){
std::string sbuf;
llvm::raw_string_ostream Out(sbuf);
@ -3167,11 +3163,7 @@ struct DOTGraphTraits<ExplodedNode*> : public DefaultDOTGraphTraits {
Out << "\\l\\|";
ExplodedGraph &Graph =
static_cast<ExprEngine *>(State->getStateManager().getOwningEngine())
->getGraph();
Out << "StateID: ST" << State->getID() << ", NodeID: N" << N->getID(&Graph)
Out << "StateID: ST" << State->getID() << ", NodeID: N" << N->getID(G)
<< " <" << (const void *)N << ">\\|";
bool SameAsAllPredecessors =
@ -3205,32 +3197,20 @@ void ExprEngine::ViewGraph(bool trim) {
}
ViewGraph(Src);
}
else {
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
llvm::ViewGraph(*G.roots_begin(), "ExprEngine");
GraphPrintCheckerState = nullptr;
GraphPrintSourceManager = nullptr;
} else {
llvm::ViewGraph(&G, "ExprEngine");
}
#endif
}
void ExprEngine::ViewGraph(ArrayRef<const ExplodedNode*> Nodes) {
#ifndef NDEBUG
GraphPrintCheckerState = this;
GraphPrintSourceManager = &getContext().getSourceManager();
std::unique_ptr<ExplodedGraph> TrimmedG(G.trim(Nodes));
if (!TrimmedG.get())
if (!TrimmedG.get()) {
llvm::errs() << "warning: Trimmed ExplodedGraph is empty.\n";
else
llvm::ViewGraph(*TrimmedG->roots_begin(), "TrimmedExprEngine");
GraphPrintCheckerState = nullptr;
GraphPrintSourceManager = nullptr;
} else {
llvm::ViewGraph(TrimmedG.get(), "TrimmedExprEngine");
}
#endif
}