diff --git a/clang/include/clang/Analysis/FlowSensitive/Logger.h b/clang/include/clang/Analysis/FlowSensitive/Logger.h index 6836488003a97..f4bd39f6ed49e 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Logger.h +++ b/clang/include/clang/Analysis/FlowSensitive/Logger.h @@ -50,7 +50,9 @@ class Logger { /// Called when we start (re-)processing a block in the CFG. /// The target program point is the entry to the specified block. /// Calls to log() describe transferBranch(), join() etc. - virtual void enterBlock(const CFGBlock &) {} + /// `PostVisit` specifies whether we're processing the block for the + /// post-visit callback. + virtual void enterBlock(const CFGBlock &, bool PostVisit) {} /// Called when we start processing an element in the current CFG block. /// The target program point is after the specified element. /// Calls to log() describe the transfer() function. diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp index a5f64021eb6ba..47915958750d1 100644 --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp @@ -146,15 +146,21 @@ class ModelDumper { }; class HTMLLogger : public Logger { + struct Iteration { + const CFGBlock *Block; + unsigned Iter; + bool PostVisit; + }; + StreamFactory Streams; std::unique_ptr OS; std::optional JOS; const ControlFlowContext *CFG; // Timeline of iterations of CFG block visitation. - std::vector> Iters; + std::vector Iters; // Number of times each CFG block has been seen. - llvm::DenseMap BlockIters; + llvm::DenseMap> BlockIters; // The messages logged in the current context but not yet written. std::string ContextLogs; // The number of elements we have visited within the current CFG block. @@ -198,8 +204,9 @@ class HTMLLogger : public Logger { JOS->attributeArray("timeline", [&] { for (const auto &E : Iters) { JOS->object([&] { - JOS->attribute("block", blockID(E.first->getBlockID())); - JOS->attribute("iter", E.second); + JOS->attribute("block", blockID(E.Block->getBlockID())); + JOS->attribute("iter", E.Iter); + JOS->attribute("post_visit", E.PostVisit); }); } }); @@ -214,8 +221,11 @@ class HTMLLogger : public Logger { *OS << llvm::StringRef(HTMLLogger_html).split("").second; } - void enterBlock(const CFGBlock &B) override { - Iters.emplace_back(&B, ++BlockIters[&B]); + void enterBlock(const CFGBlock &B, bool PostVisit) override { + llvm::SmallVector &BIter = BlockIters[&B]; + unsigned IterNum = BIter.size() + 1; + BIter.push_back({&B, IterNum, PostVisit}); + Iters.push_back({&B, IterNum, PostVisit}); ElementIndex = 0; } void enterElement(const CFGElement &E) override { @@ -243,17 +253,19 @@ class HTMLLogger : public Logger { // - meaningful names for values // - which boolean values are implied true/false by the flow condition void recordState(TypeErasedDataflowAnalysisState &State) override { - unsigned Block = Iters.back().first->getBlockID(); - unsigned Iter = Iters.back().second; + unsigned Block = Iters.back().Block->getBlockID(); + unsigned Iter = Iters.back().Iter; + bool PostVisit = Iters.back().PostVisit; JOS->attributeObject(elementIterID(Block, Iter, ElementIndex), [&] { JOS->attribute("block", blockID(Block)); JOS->attribute("iter", Iter); + JOS->attribute("post_visit", PostVisit); JOS->attribute("element", ElementIndex); // If this state immediately follows an Expr, show its built-in model. if (ElementIndex > 0) { auto S = - Iters.back().first->Elements[ElementIndex - 1].getAs(); + Iters.back().Block->Elements[ElementIndex - 1].getAs(); if (const Expr *E = S ? llvm::dyn_cast(S->getStmt()) : nullptr) { if (E->isPRValue()) { if (auto *V = State.Env.getValue(*E)) @@ -289,9 +301,16 @@ class HTMLLogger : public Logger { // Write the CFG block details. // Currently this is just the list of elements in execution order. // FIXME: an AST dump would be a useful view, too. - void writeBlock(const CFGBlock &B, unsigned Iters) { + void writeBlock(const CFGBlock &B, llvm::ArrayRef ItersForB) { JOS->attributeObject(blockID(B.getBlockID()), [&] { - JOS->attribute("iters", Iters); + JOS->attributeArray("iters", [&] { + for (const auto &Iter : ItersForB) { + JOS->object([&] { + JOS->attribute("iter", Iter.Iter); + JOS->attribute("post_visit", Iter.PostVisit); + }); + } + }); JOS->attributeArray("elements", [&] { for (const auto &Elt : B.Elements) { std::string Dump; diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.html b/clang/lib/Analysis/FlowSensitive/HTMLLogger.html index a60259a99cce0..87695623cb318 100644 --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.html +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.html @@ -41,7 +41,11 @@
Timeline
@@ -54,8 +58,11 @@
-