diff --git a/clang/include/clang/Analysis/FlowSensitive/Transfer.h b/clang/include/clang/Analysis/FlowSensitive/Transfer.h --- a/clang/include/clang/Analysis/FlowSensitive/Transfer.h +++ b/clang/include/clang/Analysis/FlowSensitive/Transfer.h @@ -17,27 +17,17 @@ #include "clang/AST/Stmt.h" #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" namespace clang { namespace dataflow { -/// Maps statements to the environments of basic blocks that contain them. -class StmtToEnvMap { -public: - virtual ~StmtToEnvMap() = default; - - /// Returns the environment of the basic block that contains `S` or nullptr if - /// there isn't one. - /// FIXME: Ensure that the result can't be null and return a const reference. - virtual const Environment *getEnvironment(const Stmt &S) const = 0; -}; - /// Evaluates `S` and updates `Env` accordingly. /// /// Requirements: /// /// `S` must not be `ParenExpr` or `ExprWithCleanups`. -void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env); +void transfer(const AnalysisContext &AC, const Stmt &S, Environment &Env); } // namespace dataflow } // namespace clang diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h --- a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -128,6 +128,27 @@ : Lattice(std::move(Lattice)), Env(std::move(Env)) {} }; +/// Holds data structures required for running dataflow analysis. +struct AnalysisContext { + AnalysisContext(const ControlFlowContext &CFCtx, + TypeErasedDataflowAnalysis &Analysis, + const Environment &InitEnv, + llvm::ArrayRef> + BlockStates) + : CFCtx(CFCtx), Analysis(Analysis), InitEnv(InitEnv), + BlockStates(BlockStates) {} + + /// Contains the CFG being analyzed. + const ControlFlowContext &CFCtx; + /// The analysis to be run. + TypeErasedDataflowAnalysis &Analysis; + /// Initial state to start the analysis. + const Environment &InitEnv; + /// Stores the state of a CFG block if it has been evaluated by the analysis. + /// The indices correspond to the block IDs. + llvm::ArrayRef> BlockStates; +}; + /// Transfers the state of a basic block by evaluating each of its elements in /// the context of `Analysis` and the states of its predecessors that are /// available in `BlockStates`. `PostVisitCFG` (if provided) will be applied to diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp --- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp +++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/FlowSensitive/Transfer.h" +#include "clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -129,10 +130,22 @@ return &UnpackedVal; } +/// Returns the environment of the basic block that contains `S` or nullptr if +/// there isn't one. +/// The result is guaranteed never to be null. +static const Environment *getEnvironment(const Stmt &S, + const AnalysisContext &AC) { + auto BlockIt = AC.CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S)); + assert(BlockIt != AC.CFCtx.getStmtToBlock().end()); + const auto &State = AC.BlockStates[BlockIt->getSecond()->getBlockID()]; + assert(State); + return &State->Env; +} + class TransferVisitor : public ConstStmtVisitor { public: - TransferVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env) - : StmtToEnv(StmtToEnv), Env(Env) {} + TransferVisitor(const AnalysisContext &AC, Environment &Env) + : AC(AC), Env(Env) {} void VisitBinaryOperator(const BinaryOperator *S) { const Expr *LHS = S->getLHS(); @@ -783,7 +796,7 @@ // `SubExpr` and its parent logic operator might be part of different basic // blocks. We try to access the value that is assigned to `SubExpr` in the // corresponding environment. - if (const Environment *SubExprEnv = StmtToEnv.getEnvironment(SubExpr)) { + if (const Environment *SubExprEnv = getEnvironment(SubExpr, AC)) { if (auto *Val = dyn_cast_or_null( SubExprEnv->getValue(SubExpr, SkipPast::Reference))) return *Val; @@ -854,12 +867,12 @@ Env.popCall(ExitState->Env); } - const StmtToEnvMap &StmtToEnv; + const AnalysisContext ∾ Environment &Env; }; -void transfer(const StmtToEnvMap &StmtToEnv, const Stmt &S, Environment &Env) { - TransferVisitor(StmtToEnv, Env).Visit(&S); +void transfer(const AnalysisContext &AC, const Stmt &S, Environment &Env) { + TransferVisitor(AC, Env).Visit(&S); } } // namespace dataflow diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -40,27 +40,6 @@ namespace clang { namespace dataflow { -class StmtToEnvMapImpl : public StmtToEnvMap { -public: - StmtToEnvMapImpl( - const ControlFlowContext &CFCtx, - llvm::ArrayRef> - BlockToState) - : CFCtx(CFCtx), BlockToState(BlockToState) {} - - const Environment *getEnvironment(const Stmt &S) const override { - auto BlockIt = CFCtx.getStmtToBlock().find(&ignoreCFGOmittedNodes(S)); - assert(BlockIt != CFCtx.getStmtToBlock().end()); - const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()]; - assert(State); - return &State->Env; - } - -private: - const ControlFlowContext &CFCtx; - llvm::ArrayRef> BlockToState; -}; - /// Returns the index of `Block` in the successors of `Pred`. static int blockIndexInPredecessor(const CFGBlock &Pred, const CFGBlock &Block) { @@ -96,9 +75,9 @@ class TerminatorVisitor : public ConstStmtVisitor { public: - TerminatorVisitor(const StmtToEnvMap &StmtToEnv, Environment &Env, + TerminatorVisitor(const AnalysisContext &AC, Environment &Env, int BlockSuccIdx) - : StmtToEnv(StmtToEnv), Env(Env), BlockSuccIdx(BlockSuccIdx) {} + : AC(AC), Env(Env), BlockSuccIdx(BlockSuccIdx) {} TerminatorVisitorRetTy VisitIfStmt(const IfStmt *S) { auto *Cond = S->getCond(); @@ -143,7 +122,7 @@ TerminatorVisitorRetTy extendFlowCondition(const Expr &Cond) { // The terminator sub-expression might not be evaluated. if (Env.getStorageLocation(Cond, SkipPast::None) == nullptr) - transfer(StmtToEnv, Cond, Env); + transfer(AC, Cond, Env); // FIXME: The flow condition must be an r-value, so `SkipPast::None` should // suffice. @@ -176,32 +155,11 @@ return {&Cond, ConditionValue}; } - const StmtToEnvMap &StmtToEnv; + const AnalysisContext ∾ Environment &Env; int BlockSuccIdx; }; -/// Holds data structures required for running dataflow analysis. -struct AnalysisContext { - AnalysisContext(const ControlFlowContext &CFCtx, - TypeErasedDataflowAnalysis &Analysis, - const Environment &InitEnv, - llvm::ArrayRef> - BlockStates) - : CFCtx(CFCtx), Analysis(Analysis), InitEnv(InitEnv), - BlockStates(BlockStates) {} - - /// Contains the CFG being analyzed. - const ControlFlowContext &CFCtx; - /// The analysis to be run. - TypeErasedDataflowAnalysis &Analysis; - /// Initial state to start the analysis. - const Environment &InitEnv; - /// Stores the state of a CFG block if it has been evaluated by the analysis. - /// The indices correspond to the block IDs. - llvm::ArrayRef> BlockStates; -}; - /// Computes the input state for a given basic block by joining the output /// states of its predecessors. /// @@ -263,9 +221,8 @@ TypeErasedDataflowAnalysisState PredState = *MaybePredState; if (Analysis.builtinOptions()) { if (const Stmt *PredTerminatorStmt = Pred->getTerminatorStmt()) { - const StmtToEnvMapImpl StmtToEnv(AC.CFCtx, AC.BlockStates); auto [Cond, CondValue] = - TerminatorVisitor(StmtToEnv, PredState.Env, + TerminatorVisitor(AC, PredState.Env, blockIndexInPredecessor(*Pred, Block)) .Visit(PredTerminatorStmt); if (Cond != nullptr) @@ -298,7 +255,7 @@ AnalysisContext &AC) { const Stmt *S = Elt.getStmt(); assert(S != nullptr); - transfer(StmtToEnvMapImpl(AC.CFCtx, AC.BlockStates), *S, InputState.Env); + transfer(AC, *S, InputState.Env); } /// Built-in transfer function for `CFGInitializer`.