diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt index 40ab76fa26a9e..70687c23b15e6 100644 --- a/clang/docs/tools/clang-formatted-files.txt +++ b/clang/docs/tools/clang-formatted-files.txt @@ -122,6 +122,7 @@ clang/include/clang/Analysis/MacroExpansionContext.h clang/include/clang/Analysis/Analyses/CalledOnceCheck.h clang/include/clang/Analysis/Analyses/CFGReachabilityAnalysis.h clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h +clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -306,7 +307,7 @@ clang/include/clang-c/Index.h clang/lib/Analysis/CalledOnceCheck.cpp clang/lib/Analysis/CloneDetection.cpp clang/lib/Analysis/CodeInjector.cpp -clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp +clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp clang/lib/Analysis/FlowSensitive/DebugSupport.cpp diff --git a/clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h b/clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h new file mode 100644 index 0000000000000..420f13ce11bfd --- /dev/null +++ b/clang/include/clang/Analysis/FlowSensitive/AdornedCFG.h @@ -0,0 +1,96 @@ +//===-- AdornedCFG.h ------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines an AdornedCFG class that is used by dataflow analyses that +// run over Control-Flow Graphs (CFGs). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ADORNEDCFG_H +#define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ADORNEDCFG_H + +#include "clang/AST/ASTContext.h" +#include "clang/AST/Decl.h" +#include "clang/AST/Stmt.h" +#include "clang/Analysis/CFG.h" +#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/Support/Error.h" +#include +#include + +namespace clang { +namespace dataflow { + +/// Holds CFG with additional information derived from it that is needed to +/// perform dataflow analysis. +class AdornedCFG { +public: + /// Builds an `AdornedCFG` from a `FunctionDecl`. + /// `Func.doesThisDeclarationHaveABody()` must be true, and + /// `Func.isTemplated()` must be false. + static llvm::Expected build(const FunctionDecl &Func); + + /// Builds an `AdornedCFG` from an AST node. `D` is the function in which + /// `S` resides. `D.isTemplated()` must be false. + static llvm::Expected build(const Decl &D, Stmt &S, + ASTContext &C); + + /// Returns the `Decl` containing the statement used to construct the CFG, if + /// available. + const Decl &getDecl() const { return ContainingDecl; } + + /// Returns the CFG that is stored in this context. + const CFG &getCFG() const { return *Cfg; } + + /// Returns a mapping from statements to basic blocks that contain them. + const llvm::DenseMap &getStmtToBlock() const { + return StmtToBlock; + } + + /// Returns whether `B` is reachable from the entry block. + bool isBlockReachable(const CFGBlock &B) const { + return BlockReachable[B.getBlockID()]; + } + + /// Returns whether `B` contains an expression that is consumed in a + /// different block than `B` (i.e. the parent of the expression is in a + /// different block). + /// This happens if there is control flow within a full-expression (triggered + /// by `&&`, `||`, or the conditional operator). Note that the operands of + /// these operators are not the only expressions that can be consumed in a + /// different block. For example, in the function call + /// `f(&i, cond() ? 1 : 0)`, `&i` is in a different block than the `CallExpr`. + bool containsExprConsumedInDifferentBlock(const CFGBlock &B) const { + return ContainsExprConsumedInDifferentBlock.contains(&B); + } + +private: + AdornedCFG( + const Decl &D, std::unique_ptr Cfg, + llvm::DenseMap StmtToBlock, + llvm::BitVector BlockReachable, + llvm::DenseSet ContainsExprConsumedInDifferentBlock) + : ContainingDecl(D), Cfg(std::move(Cfg)), + StmtToBlock(std::move(StmtToBlock)), + BlockReachable(std::move(BlockReachable)), + ContainsExprConsumedInDifferentBlock( + std::move(ContainsExprConsumedInDifferentBlock)) {} + + /// The `Decl` containing the statement used to construct the CFG. + const Decl &ContainingDecl; + std::unique_ptr Cfg; + llvm::DenseMap StmtToBlock; + llvm::BitVector BlockReachable; + llvm::DenseSet ContainsExprConsumedInDifferentBlock; +}; + +} // namespace dataflow +} // namespace clang + +#endif // LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_ADORNEDCFG_H diff --git a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h index 9a0a00f3c0134..3972962d0b2da 100644 --- a/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/ControlFlowContext.h @@ -6,89 +6,20 @@ // //===----------------------------------------------------------------------===// // -// This file defines a ControlFlowContext class that is used by dataflow -// analyses that run over Control-Flow Graphs (CFGs). +// This file defines a deprecated alias for AdornedCFG. // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H #define LLVM_CLANG_ANALYSIS_FLOWSENSITIVE_CONTROLFLOWCONTEXT_H -#include "clang/AST/ASTContext.h" -#include "clang/AST/Decl.h" -#include "clang/AST/Stmt.h" -#include "clang/Analysis/CFG.h" -#include "llvm/ADT/BitVector.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/Support/Error.h" -#include -#include +#include "clang/Analysis/FlowSensitive/AdornedCFG.h" namespace clang { namespace dataflow { -/// Holds CFG and other derived context that is needed to perform dataflow -/// analysis. -class ControlFlowContext { -public: - /// Builds a ControlFlowContext from a `FunctionDecl`. - /// `Func.doesThisDeclarationHaveABody()` must be true, and - /// `Func.isTemplated()` must be false. - static llvm::Expected build(const FunctionDecl &Func); - - /// Builds a ControlFlowContext from an AST node. `D` is the function in which - /// `S` resides. `D.isTemplated()` must be false. - static llvm::Expected build(const Decl &D, Stmt &S, - ASTContext &C); - - /// Returns the `Decl` containing the statement used to construct the CFG, if - /// available. - const Decl &getDecl() const { return ContainingDecl; } - - /// Returns the CFG that is stored in this context. - const CFG &getCFG() const { return *Cfg; } - - /// Returns a mapping from statements to basic blocks that contain them. - const llvm::DenseMap &getStmtToBlock() const { - return StmtToBlock; - } - - /// Returns whether `B` is reachable from the entry block. - bool isBlockReachable(const CFGBlock &B) const { - return BlockReachable[B.getBlockID()]; - } - - /// Returns whether `B` contains an expression that is consumed in a - /// different block than `B` (i.e. the parent of the expression is in a - /// different block). - /// This happens if there is control flow within a full-expression (triggered - /// by `&&`, `||`, or the conditional operator). Note that the operands of - /// these operators are not the only expressions that can be consumed in a - /// different block. For example, in the function call - /// `f(&i, cond() ? 1 : 0)`, `&i` is in a different block than the `CallExpr`. - bool containsExprConsumedInDifferentBlock(const CFGBlock &B) const { - return ContainsExprConsumedInDifferentBlock.contains(&B); - } - -private: - ControlFlowContext( - const Decl &D, std::unique_ptr Cfg, - llvm::DenseMap StmtToBlock, - llvm::BitVector BlockReachable, - llvm::DenseSet ContainsExprConsumedInDifferentBlock) - : ContainingDecl(D), Cfg(std::move(Cfg)), - StmtToBlock(std::move(StmtToBlock)), - BlockReachable(std::move(BlockReachable)), - ContainsExprConsumedInDifferentBlock( - std::move(ContainsExprConsumedInDifferentBlock)) {} - - /// The `Decl` containing the statement used to construct the CFG. - const Decl &ContainingDecl; - std::unique_ptr Cfg; - llvm::DenseMap StmtToBlock; - llvm::BitVector BlockReachable; - llvm::DenseSet ContainsExprConsumedInDifferentBlock; -}; +// This is a deprecated alias. Use `AdornedCFG` instead. +using ControlFlowContext = AdornedCFG; } // namespace dataflow } // namespace clang diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h index 3c84704d0d6ce..67eccdd030dcd 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -22,7 +22,7 @@ #include "clang/AST/ASTContext.h" #include "clang/Analysis/CFG.h" -#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/AdornedCFG.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/DataflowLattice.h" #include "clang/Analysis/FlowSensitive/MatchSwitch.h" @@ -195,8 +195,7 @@ template llvm::Expected>>> runDataflowAnalysis( - const ControlFlowContext &CFCtx, AnalysisT &Analysis, - const Environment &InitEnv, + const AdornedCFG &ACFG, AnalysisT &Analysis, const Environment &InitEnv, std::function &)> PostVisitCFG = nullptr, @@ -218,7 +217,7 @@ runDataflowAnalysis( } auto TypeErasedBlockStates = runTypeErasedDataflowAnalysis( - CFCtx, Analysis, InitEnv, PostVisitCFGClosure, MaxBlockVisits); + ACFG, Analysis, InitEnv, PostVisitCFGClosure, MaxBlockVisits); if (!TypeErasedBlockStates) return TypeErasedBlockStates.takeError(); @@ -280,8 +279,7 @@ llvm::Expected> diagnoseFunction( Diagnoser, std::int64_t MaxSATIterations = 1'000'000'000, std::int32_t MaxBlockVisits = 20'000) { - llvm::Expected Context = - ControlFlowContext::build(FuncDecl); + llvm::Expected Context = AdornedCFG::build(FuncDecl); if (!Context) return Context.takeError(); diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h index 98bdf037880ab..909a91059438c 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysisContext.h @@ -18,8 +18,8 @@ #include "clang/AST/Decl.h" #include "clang/AST/Expr.h" #include "clang/AST/TypeOrdering.h" +#include "clang/Analysis/FlowSensitive/AdornedCFG.h" #include "clang/Analysis/FlowSensitive/Arena.h" -#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" #include "clang/Analysis/FlowSensitive/Solver.h" #include "clang/Analysis/FlowSensitive/StorageLocation.h" #include "clang/Analysis/FlowSensitive/Value.h" @@ -183,9 +183,9 @@ class DataflowAnalysisContext { LLVM_DUMP_METHOD void dumpFlowCondition(Atom Token, llvm::raw_ostream &OS = llvm::dbgs()); - /// Returns the `ControlFlowContext` registered for `F`, if any. Otherwise, + /// Returns the `AdornedCFG` registered for `F`, if any. Otherwise, /// returns null. - const ControlFlowContext *getControlFlowContext(const FunctionDecl *F); + const AdornedCFG *getAdornedCFG(const FunctionDecl *F); const Options &getOptions() { return Opts; } @@ -296,7 +296,7 @@ class DataflowAnalysisContext { llvm::DenseMap FlowConditionConstraints; const Formula *Invariant = nullptr; - llvm::DenseMap FunctionContexts; + llvm::DenseMap FunctionContexts; // Fields modeled by environments covered by this context. FieldSet ModeledFields; diff --git a/clang/include/clang/Analysis/FlowSensitive/Logger.h b/clang/include/clang/Analysis/FlowSensitive/Logger.h index f4bd39f6ed49e..f2e64810d0050 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Logger.h +++ b/clang/include/clang/Analysis/FlowSensitive/Logger.h @@ -15,7 +15,7 @@ namespace clang::dataflow { // Forward declarations so we can use Logger anywhere in the framework. -class ControlFlowContext; +class AdornedCFG; class TypeErasedDataflowAnalysis; struct TypeErasedDataflowAnalysisState; @@ -40,8 +40,8 @@ class Logger { /// Called by the framework as we start analyzing a new function or statement. /// Forms a pair with endAnalysis(). - virtual void beginAnalysis(const ControlFlowContext &, - TypeErasedDataflowAnalysis &) {} + virtual void beginAnalysis(const AdornedCFG &, TypeErasedDataflowAnalysis &) { + } virtual void endAnalysis() {} // At any time during the analysis, we're computing the state for some target diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h index 7713df747cb76..ed148250d8eb2 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h +++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h @@ -29,12 +29,12 @@ class StmtToEnvMap { // `CurState` is the pending state currently associated with this block. These // are supplied separately as the pending state for the current block may not // yet be represented in `BlockToState`. - StmtToEnvMap(const ControlFlowContext &CFCtx, + StmtToEnvMap(const AdornedCFG &ACFG, llvm::ArrayRef> BlockToState, unsigned CurBlockID, const TypeErasedDataflowAnalysisState &CurState) - : CFCtx(CFCtx), BlockToState(BlockToState), CurBlockID(CurBlockID), + : ACFG(ACFG), BlockToState(BlockToState), CurBlockID(CurBlockID), CurState(CurState) {} /// Returns the environment of the basic block that contains `S`. @@ -42,7 +42,7 @@ class StmtToEnvMap { const Environment *getEnvironment(const Stmt &S) const; private: - const ControlFlowContext &CFCtx; + const AdornedCFG &ACFG; llvm::ArrayRef> BlockToState; unsigned CurBlockID; const TypeErasedDataflowAnalysisState &CurState; diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h index a0ca7440230b0..b3722bf3ec80a 100644 --- a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -21,7 +21,7 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/Stmt.h" #include "clang/Analysis/CFG.h" -#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/AdornedCFG.h" #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/DataflowLattice.h" @@ -146,7 +146,7 @@ struct TypeErasedDataflowAnalysisState { /// from converging. llvm::Expected>> runTypeErasedDataflowAnalysis( - const ControlFlowContext &CFCtx, TypeErasedDataflowAnalysis &Analysis, + const AdornedCFG &ACFG, TypeErasedDataflowAnalysis &Analysis, const Environment &InitEnv, std::function diff --git a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp b/clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp similarity index 89% rename from clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp rename to clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp index 7c9f8fbb0a700..3813b8c3ee8a2 100644 --- a/clang/lib/Analysis/FlowSensitive/ControlFlowContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/AdornedCFG.cpp @@ -1,4 +1,4 @@ -//===- ControlFlowContext.cpp ---------------------------------------------===// +//===- AdornedCFG.cpp ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// // -// This file defines a ControlFlowContext class that is used by dataflow -// analyses that run over Control-Flow Graphs (CFGs). +// This file defines an `AdornedCFG` class that is used by dataflow analyses +// that run over Control-Flow Graphs (CFGs). // //===----------------------------------------------------------------------===// -#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/AdornedCFG.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" #include "clang/AST/Stmt.h" @@ -126,8 +126,7 @@ buildContainsExprConsumedInDifferentBlock( return Result; } -llvm::Expected -ControlFlowContext::build(const FunctionDecl &Func) { +llvm::Expected AdornedCFG::build(const FunctionDecl &Func) { if (!Func.doesThisDeclarationHaveABody()) return llvm::createStringError( std::make_error_code(std::errc::invalid_argument), @@ -136,8 +135,8 @@ ControlFlowContext::build(const FunctionDecl &Func) { return build(Func, *Func.getBody(), Func.getASTContext()); } -llvm::Expected -ControlFlowContext::build(const Decl &D, Stmt &S, ASTContext &C) { +llvm::Expected AdornedCFG::build(const Decl &D, Stmt &S, + ASTContext &C) { if (D.isTemplated()) return llvm::createStringError( std::make_error_code(std::errc::invalid_argument), @@ -175,9 +174,9 @@ ControlFlowContext::build(const Decl &D, Stmt &S, ASTContext &C) { llvm::DenseSet ContainsExprConsumedInDifferentBlock = buildContainsExprConsumedInDifferentBlock(*Cfg, StmtToBlock); - return ControlFlowContext(D, std::move(Cfg), std::move(StmtToBlock), - std::move(BlockReachable), - std::move(ContainsExprConsumedInDifferentBlock)); + return AdornedCFG(D, std::move(Cfg), std::move(StmtToBlock), + std::move(BlockReachable), + std::move(ContainsExprConsumedInDifferentBlock)); } } // namespace dataflow diff --git a/clang/lib/Analysis/FlowSensitive/CMakeLists.txt b/clang/lib/Analysis/FlowSensitive/CMakeLists.txt index 5af4ecfc9efa5..a3b5d9adc24bd 100644 --- a/clang/lib/Analysis/FlowSensitive/CMakeLists.txt +++ b/clang/lib/Analysis/FlowSensitive/CMakeLists.txt @@ -1,6 +1,6 @@ add_clang_library(clangAnalysisFlowSensitive + AdornedCFG.cpp Arena.cpp - ControlFlowContext.cpp DataflowAnalysisContext.cpp DataflowEnvironment.cpp Formula.cpp diff --git a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp index f4c4af022f51f..d520539dd2535 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowAnalysisContext.cpp @@ -288,8 +288,8 @@ void DataflowAnalysisContext::dumpFlowCondition(Atom Token, } } -const ControlFlowContext * -DataflowAnalysisContext::getControlFlowContext(const FunctionDecl *F) { +const AdornedCFG * +DataflowAnalysisContext::getAdornedCFG(const FunctionDecl *F) { // Canonicalize the key: F = F->getDefinition(); if (F == nullptr) @@ -299,10 +299,10 @@ DataflowAnalysisContext::getControlFlowContext(const FunctionDecl *F) { return &It->second; if (F->doesThisDeclarationHaveABody()) { - auto CFCtx = ControlFlowContext::build(*F); + auto ACFG = AdornedCFG::build(*F); // FIXME: Handle errors. - assert(CFCtx); - auto Result = FunctionContexts.insert({F, std::move(*CFCtx)}); + assert(ACFG); + auto Result = FunctionContexts.insert({F, std::move(*ACFG)}); return &Result.first->second; } diff --git a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp index 6afd66d9dc6ac..397a8d87e114d 100644 --- a/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp +++ b/clang/lib/Analysis/FlowSensitive/HTMLLogger.cpp @@ -54,7 +54,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/AdornedCFG.h" #include "clang/Analysis/FlowSensitive/DebugSupport.h" #include "clang/Analysis/FlowSensitive/Logger.h" #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" @@ -162,7 +162,7 @@ class HTMLLogger : public Logger { llvm::raw_string_ostream JStringStream{JSON}; llvm::json::OStream JOS{JStringStream, /*Indent=*/2}; - const ControlFlowContext *CFC; + const AdornedCFG *ACFG; // Timeline of iterations of CFG block visitation. std::vector Iters; // Indexes in `Iters` of the iterations for each block. @@ -176,15 +176,15 @@ class HTMLLogger : public Logger { public: explicit HTMLLogger(StreamFactory Streams) : Streams(std::move(Streams)) {} - void beginAnalysis(const ControlFlowContext &CFC, + void beginAnalysis(const AdornedCFG &ACFG, TypeErasedDataflowAnalysis &A) override { OS = Streams(); - this->CFC = &CFC; + this->ACFG = &ACFG; *OS << llvm::StringRef(HTMLLogger_html).split("").first; - BlockConverged.resize(CFC.getCFG().getNumBlockIDs()); + BlockConverged.resize(ACFG.getCFG().getNumBlockIDs()); - const auto &D = CFC.getDecl(); + const auto &D = ACFG.getDecl(); const auto &SM = A.getASTContext().getSourceManager(); *OS << ""; if (const auto *ND = dyn_cast<NamedDecl>(&D)) @@ -345,7 +345,7 @@ class HTMLLogger : public Logger { // tokens are associated with, and even which BB element (so that clicking // can select the right element). void writeCode() { - const auto &AST = CFC->getDecl().getASTContext(); + const auto &AST = ACFG->getDecl().getASTContext(); bool Invalid = false; // Extract the source code from the original file. @@ -353,7 +353,7 @@ class HTMLLogger : public Logger { // indentation to worry about), but we need the boundaries of particular // AST nodes and the printer doesn't provide this. auto Range = clang::Lexer::makeFileCharRange( - CharSourceRange::getTokenRange(CFC->getDecl().getSourceRange()), + CharSourceRange::getTokenRange(ACFG->getDecl().getSourceRange()), AST.getSourceManager(), AST.getLangOpts()); if (Range.isInvalid()) return; @@ -419,7 +419,7 @@ class HTMLLogger : public Logger { // Construct one TokenInfo per character in a flat array. // This is inefficient (chars in a token all have the same info) but simple. std::vector<TokenInfo> State(Code.size()); - for (const auto *Block : CFC->getCFG()) { + for (const auto *Block : ACFG->getCFG()) { unsigned EltIndex = 0; for (const auto& Elt : *Block) { ++EltIndex; @@ -480,7 +480,7 @@ class HTMLLogger : public Logger { // out to `dot` to turn it into an SVG. void writeCFG() { *OS << "<template data-copy='cfg'>\n"; - if (auto SVG = renderSVG(buildCFGDot(CFC->getCFG()))) + if (auto SVG = renderSVG(buildCFGDot(ACFG->getCFG()))) *OS << *SVG; else *OS << "Can't draw CFG: " << toString(SVG.takeError()); diff --git a/clang/lib/Analysis/FlowSensitive/Logger.cpp b/clang/lib/Analysis/FlowSensitive/Logger.cpp index 8c401df62e445..8f40768171c94 100644 --- a/clang/lib/Analysis/FlowSensitive/Logger.cpp +++ b/clang/lib/Analysis/FlowSensitive/Logger.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/FlowSensitive/Logger.h" -#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/AdornedCFG.h" #include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" #include "llvm/Support/WithColor.h" @@ -33,17 +33,17 @@ struct TextualLogger final : Logger { TextualLogger(llvm::raw_ostream &OS) : OS(OS), ShowColors(llvm::WithColor::defaultAutoDetectFunction()(OS)) {} - virtual void beginAnalysis(const ControlFlowContext &CFG, + virtual void beginAnalysis(const AdornedCFG &ACFG, TypeErasedDataflowAnalysis &Analysis) override { { llvm::WithColor Header(OS, llvm::raw_ostream::Colors::RED, /*Bold=*/true); OS << "=== Beginning data flow analysis ===\n"; } - auto &D = CFG.getDecl(); + auto &D = ACFG.getDecl(); D.print(OS); OS << "\n"; D.dump(OS); - CurrentCFG = &CFG.getCFG(); + CurrentCFG = &ACFG.getCFG(); CurrentCFG->print(OS, Analysis.getASTContext().getLangOpts(), ShowColors); CurrentAnalysis = &Analysis; } diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp index 04aa2831df055..a9d94d772455d 100644 --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -20,7 +20,7 @@ #include "clang/AST/OperationKinds.h" #include "clang/AST/Stmt.h" #include "clang/AST/StmtVisitor.h" -#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/AdornedCFG.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" #include "clang/Analysis/FlowSensitive/NoopAnalysis.h" #include "clang/Analysis/FlowSensitive/RecordOps.h" @@ -38,9 +38,9 @@ namespace clang { namespace dataflow { const Environment *StmtToEnvMap::getEnvironment(const Stmt &S) const { - auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S)); - assert(BlockIt != CFCtx.getStmtToBlock().end()); - if (!CFCtx.isBlockReachable(*BlockIt->getSecond())) + auto BlockIt = ACFG.getStmtToBlock().find(&ignoreCFGOmittedNodes(S)); + assert(BlockIt != ACFG.getStmtToBlock().end()); + if (!ACFG.isBlockReachable(*BlockIt->getSecond())) return nullptr; if (BlockIt->getSecond()->getBlockID() == CurBlockID) return &CurState.Env; @@ -836,27 +836,26 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> { Env.canDescend(Options.ContextSensitiveOpts->Depth, F))) return; - const ControlFlowContext *CFCtx = - Env.getDataflowAnalysisContext().getControlFlowContext(F); - if (!CFCtx) + const AdornedCFG *ACFG = Env.getDataflowAnalysisContext().getAdornedCFG(F); + if (!ACFG) return; // FIXME: We don't support context-sensitive analysis of recursion, so // we should return early here if `F` is the same as the `FunctionDecl` // holding `S` itself. - auto ExitBlock = CFCtx->getCFG().getExit().getBlockID(); + auto ExitBlock = ACFG->getCFG().getExit().getBlockID(); auto CalleeEnv = Env.pushCall(S); // FIXME: Use the same analysis as the caller for the callee. Note, // though, that doing so would require support for changing the analysis's // ASTContext. - auto Analysis = NoopAnalysis(CFCtx->getDecl().getASTContext(), + auto Analysis = NoopAnalysis(ACFG->getDecl().getASTContext(), DataflowAnalysisOptions{Options}); auto BlockToOutputState = - dataflow::runDataflowAnalysis(*CFCtx, Analysis, CalleeEnv); + dataflow::runDataflowAnalysis(*ACFG, Analysis, CalleeEnv); assert(BlockToOutputState); assert(ExitBlock < BlockToOutputState->size()); diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index 939247c047c66..721a11c209853 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -150,20 +150,19 @@ class TerminatorVisitor /// Holds data structures required for running dataflow analysis. struct AnalysisContext { - AnalysisContext(const ControlFlowContext &CFCtx, - TypeErasedDataflowAnalysis &Analysis, + AnalysisContext(const AdornedCFG &ACFG, TypeErasedDataflowAnalysis &Analysis, const Environment &InitEnv, llvm::ArrayRef<std::optional<TypeErasedDataflowAnalysisState>> BlockStates) - : CFCtx(CFCtx), Analysis(Analysis), InitEnv(InitEnv), + : ACFG(ACFG), Analysis(Analysis), InitEnv(InitEnv), Log(*InitEnv.getDataflowAnalysisContext().getOptions().Log), BlockStates(BlockStates) { - Log.beginAnalysis(CFCtx, Analysis); + Log.beginAnalysis(ACFG, Analysis); } ~AnalysisContext() { Log.endAnalysis(); } /// Contains the CFG being analyzed. - const ControlFlowContext &CFCtx; + const AdornedCFG &ACFG; /// The analysis to be run. TypeErasedDataflowAnalysis &Analysis; /// Initial state to start the analysis. @@ -176,19 +175,19 @@ struct AnalysisContext { class PrettyStackTraceAnalysis : public llvm::PrettyStackTraceEntry { public: - PrettyStackTraceAnalysis(const ControlFlowContext &CFCtx, const char *Message) - : CFCtx(CFCtx), Message(Message) {} + PrettyStackTraceAnalysis(const AdornedCFG &ACFG, const char *Message) + : ACFG(ACFG), Message(Message) {} void print(raw_ostream &OS) const override { OS << Message << "\n"; OS << "Decl:\n"; - CFCtx.getDecl().dump(OS); + ACFG.getDecl().dump(OS); OS << "CFG:\n"; - CFCtx.getCFG().print(OS, LangOptions(), false); + ACFG.getCFG().print(OS, LangOptions(), false); } private: - const ControlFlowContext &CFCtx; + const AdornedCFG &ACFG; const char *Message; }; @@ -303,7 +302,7 @@ computeBlockInputState(const CFGBlock &Block, AnalysisContext &AC) { // See `NoreturnDestructorTest` for concrete examples. if (Block.succ_begin()->getReachableBlock() != nullptr && Block.succ_begin()->getReachableBlock()->hasNoReturnElement()) { - auto &StmtToBlock = AC.CFCtx.getStmtToBlock(); + auto &StmtToBlock = AC.ACFG.getStmtToBlock(); auto StmtBlock = StmtToBlock.find(Block.getTerminatorStmt()); assert(StmtBlock != StmtToBlock.end()); llvm::erase(Preds, StmtBlock->getSecond()); @@ -319,7 +318,7 @@ computeBlockInputState(const CFGBlock &Block, AnalysisContext &AC) { // all predecessors have expression state consumed in a different block. Environment::ExprJoinBehavior JoinBehavior = Environment::DiscardExprState; for (const CFGBlock *Pred : Preds) { - if (Pred && AC.CFCtx.containsExprConsumedInDifferentBlock(*Pred)) { + if (Pred && AC.ACFG.containsExprConsumedInDifferentBlock(*Pred)) { JoinBehavior = Environment::KeepExprState; break; } @@ -368,7 +367,7 @@ builtinTransferStatement(unsigned CurBlockID, const CFGStmt &Elt, AnalysisContext &AC) { const Stmt *S = Elt.getStmt(); assert(S != nullptr); - transfer(StmtToEnvMap(AC.CFCtx, AC.BlockStates, CurBlockID, InputState), *S, + transfer(StmtToEnvMap(AC.ACFG, AC.BlockStates, CurBlockID, InputState), *S, InputState.Env); } @@ -511,9 +510,8 @@ transferCFGBlock(const CFGBlock &Block, AnalysisContext &AC, // takes a `CFGElement` as input, but some expressions only show up as a // terminator condition, but not as a `CFGElement`. The condition of an if // statement is one such example. - transfer( - StmtToEnvMap(AC.CFCtx, AC.BlockStates, Block.getBlockID(), State), - *TerminatorCond, State.Env); + transfer(StmtToEnvMap(AC.ACFG, AC.BlockStates, Block.getBlockID(), State), + *TerminatorCond, State.Env); // If the transfer function didn't produce a value, create an atom so that // we have *some* value for the condition expression. This ensures that @@ -528,13 +526,13 @@ transferCFGBlock(const CFGBlock &Block, AnalysisContext &AC, llvm::Expected<std::vector<std::optional<TypeErasedDataflowAnalysisState>>> runTypeErasedDataflowAnalysis( - const ControlFlowContext &CFCtx, TypeErasedDataflowAnalysis &Analysis, + const AdornedCFG &ACFG, TypeErasedDataflowAnalysis &Analysis, const Environment &InitEnv, std::function<void(const CFGElement &, const TypeErasedDataflowAnalysisState &)> PostVisitCFG, std::int32_t MaxBlockVisits) { - PrettyStackTraceAnalysis CrashInfo(CFCtx, "runTypeErasedDataflowAnalysis"); + PrettyStackTraceAnalysis CrashInfo(ACFG, "runTypeErasedDataflowAnalysis"); std::optional<Environment> MaybeStartingEnv; if (InitEnv.callStackSize() == 1) { @@ -544,7 +542,7 @@ runTypeErasedDataflowAnalysis( const Environment &StartingEnv = MaybeStartingEnv ? *MaybeStartingEnv : InitEnv; - const clang::CFG &CFG = CFCtx.getCFG(); + const clang::CFG &CFG = ACFG.getCFG(); PostOrderCFGView POV(&CFG); ForwardDataflowWorklist Worklist(CFG, &POV); @@ -557,7 +555,7 @@ runTypeErasedDataflowAnalysis( StartingEnv.fork()}; Worklist.enqueueSuccessors(&Entry); - AnalysisContext AC(CFCtx, Analysis, StartingEnv, BlockStates); + AnalysisContext AC(ACFG, Analysis, StartingEnv, BlockStates); std::int32_t BlockVisits = 0; while (const CFGBlock *Block = Worklist.dequeue()) { LLVM_DEBUG(llvm::dbgs() @@ -615,7 +613,7 @@ runTypeErasedDataflowAnalysis( // state set to `std::nullopt` at this point) to also analyze dead code. if (PostVisitCFG) { - for (const CFGBlock *Block : CFCtx.getCFG()) { + for (const CFGBlock *Block : ACFG.getCFG()) { // Skip blocks that were not evaluated. if (!BlockStates[Block->getBlockID()]) continue; diff --git a/clang/unittests/Analysis/FlowSensitive/DeterminismTest.cpp b/clang/unittests/Analysis/FlowSensitive/DeterminismTest.cpp index 5ba26a0832036..e794bd4943f23 100644 --- a/clang/unittests/Analysis/FlowSensitive/DeterminismTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DeterminismTest.cpp @@ -8,7 +8,7 @@ #include "TestingSupport.h" #include "clang/AST/Decl.h" -#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/AdornedCFG.h" #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" @@ -34,14 +34,14 @@ std::string analyzeAndPrintExitCondition(llvm::StringRef Code) { const auto *Target = cast<FunctionDecl>(test::findValueDecl(AST.context(), "target")); Environment InitEnv(DACtx, *Target); - auto CFCtx = cantFail(ControlFlowContext::build(*Target)); + auto ACFG = cantFail(AdornedCFG::build(*Target)); NoopAnalysis Analysis(AST.context(), DataflowAnalysisOptions{}); - auto Result = runDataflowAnalysis(CFCtx, Analysis, InitEnv); + auto Result = runDataflowAnalysis(ACFG, Analysis, InitEnv); EXPECT_FALSE(!Result) << Result.takeError(); - Atom FinalFC = (*Result)[CFCtx.getCFG().getExit().getBlockID()] + Atom FinalFC = (*Result)[ACFG.getCFG().getExit().getBlockID()] ->Env.getFlowConditionToken(); std::string Textual; llvm::raw_string_ostream OS(Textual); diff --git a/clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp b/clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp index 57920c49a7d3d..88630119ba8a1 100644 --- a/clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/LoggerTest.cpp @@ -57,7 +57,7 @@ class TestLogger : public Logger { private: llvm::raw_string_ostream OS; - void beginAnalysis(const ControlFlowContext &, + void beginAnalysis(const AdornedCFG &, TypeErasedDataflowAnalysis &) override { logText("beginAnalysis()"); } diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h index b7cf6cc966edb..e3c7ff685f572 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h @@ -28,7 +28,7 @@ #include "clang/ASTMatchers/ASTMatchers.h" #include "clang/ASTMatchers/ASTMatchersInternal.h" #include "clang/Analysis/CFG.h" -#include "clang/Analysis/FlowSensitive/ControlFlowContext.h" +#include "clang/Analysis/FlowSensitive/AdornedCFG.h" #include "clang/Analysis/FlowSensitive/DataflowAnalysis.h" #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" @@ -100,7 +100,7 @@ struct AnalysisOutputs { const FunctionDecl *Target; /// Contains the control flow graph built from the body of the `Target` /// function and is analyzed. - const ControlFlowContext &CFCtx; + const AdornedCFG &ACFG; /// The analysis to be run. TypeErasedDataflowAnalysis &Analysis; /// Initial state to start the analysis. @@ -261,9 +261,10 @@ checkDataflow(AnalysisInputs<AnalysisT> AI, llvm::errc::invalid_argument, "Could not find the target function."); // Build the control flow graph for the target function. - auto MaybeCFCtx = ControlFlowContext::build(*Target); - if (!MaybeCFCtx) return MaybeCFCtx.takeError(); - auto &CFCtx = *MaybeCFCtx; + auto MaybeACFG = AdornedCFG::build(*Target); + if (!MaybeACFG) + return MaybeACFG.takeError(); + auto &ACFG = *MaybeACFG; // Initialize states for running dataflow analysis. DataflowAnalysisContext DACtx(AI.SolverFactory(), @@ -271,7 +272,7 @@ checkDataflow(AnalysisInputs<AnalysisT> AI, Environment InitEnv(DACtx, *Target); auto Analysis = AI.MakeAnalysis(Context, InitEnv); - AnalysisOutputs AO{AnnotatedCode, Context, Target, CFCtx, + AnalysisOutputs AO{AnnotatedCode, Context, Target, ACFG, Analysis, InitEnv, {}}; // Additional test setup. @@ -283,7 +284,7 @@ checkDataflow(AnalysisInputs<AnalysisT> AI, // the post-analysis states for the CFG blocks that have been evaluated. llvm::Expected<std::vector<std::optional<TypeErasedDataflowAnalysisState>>> MaybeBlockStates = - runTypeErasedDataflowAnalysis(CFCtx, Analysis, InitEnv, + runTypeErasedDataflowAnalysis(ACFG, Analysis, InitEnv, TypeErasedPostVisitCFG, MaxBlockVisitsInAnalysis); if (!MaybeBlockStates) return MaybeBlockStates.takeError(); diff --git a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp index 9d05a0d6ca401..bea00ab1a1f06 100644 --- a/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -66,20 +66,20 @@ class DataflowAnalysisTest : public Test { AST->getASTContext())); assert(Func != nullptr); - CFCtx = std::make_unique<ControlFlowContext>( - llvm::cantFail(ControlFlowContext::build(*Func))); + ACFG = + std::make_unique<AdornedCFG>(llvm::cantFail(AdornedCFG::build(*Func))); AnalysisT Analysis = MakeAnalysis(AST->getASTContext()); DACtx = std::make_unique<DataflowAnalysisContext>( std::make_unique<WatchedLiteralsSolver>()); Environment Env(*DACtx, *Func); - return runDataflowAnalysis(*CFCtx, Analysis, Env); + return runDataflowAnalysis(*ACFG, Analysis, Env); } /// Returns the `CFGBlock` containing `S` (and asserts that it exists). const CFGBlock *blockForStmt(const Stmt &S) { - const CFGBlock *Block = CFCtx->getStmtToBlock().lookup(&S); + const CFGBlock *Block = ACFG->getStmtToBlock().lookup(&S); assert(Block != nullptr); return Block; } @@ -105,7 +105,7 @@ class DataflowAnalysisTest : public Test { } std::unique_ptr<ASTUnit> AST; - std::unique_ptr<ControlFlowContext> CFCtx; + std::unique_ptr<AdornedCFG> ACFG; std::unique_ptr<DataflowAnalysisContext> DACtx; };