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,6 +17,7 @@ #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 { @@ -24,12 +25,18 @@ /// Maps statements to the environments of basic blocks that contain them. class StmtToEnvMap { public: - virtual ~StmtToEnvMap() = default; - - /// Retrieves the environment of the basic block that contains `S`. - /// If `S` is reachable, returns a non-null pointer to the environment. - /// If `S` is not reachable, returns nullptr. - virtual const Environment *getEnvironment(const Stmt &S) const = 0; + StmtToEnvMap(const ControlFlowContext &CFCtx, + llvm::ArrayRef> + BlockToState) + : CFCtx(CFCtx), BlockToState(BlockToState) {} + + /// Returns the environment of the basic block that contains `S`. + /// The result is guaranteed never to be null. + const Environment *getEnvironment(const Stmt &S) const; + +private: + const ControlFlowContext &CFCtx; + llvm::ArrayRef> BlockToState; }; /// Evaluates `S` and updates `Env` accordingly. 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 @@ -36,6 +36,16 @@ 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())) + return nullptr; + const auto &State = BlockToState[BlockIt->getSecond()->getBlockID()]; + assert(State); + return &State->Env; +} + static BoolValue &evaluateBooleanEquality(const Expr &LHS, const Expr &RHS, Environment &Env) { if (auto *LHSValue = 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,29 +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()); - if (!CFCtx.isBlockReachable(*BlockIt->getSecond())) - return nullptr; - 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) { @@ -269,7 +246,7 @@ TypeErasedDataflowAnalysisState PredState = *MaybePredState; if (Analysis.builtinOptions()) { if (const Stmt *PredTerminatorStmt = Pred->getTerminatorStmt()) { - const StmtToEnvMapImpl StmtToEnv(AC.CFCtx, AC.BlockStates); + const StmtToEnvMap StmtToEnv(AC.CFCtx, AC.BlockStates); auto [Cond, CondValue] = TerminatorVisitor(StmtToEnv, PredState.Env, blockIndexInPredecessor(*Pred, Block)) @@ -304,7 +281,7 @@ AnalysisContext &AC) { const Stmt *S = Elt.getStmt(); assert(S != nullptr); - transfer(StmtToEnvMapImpl(AC.CFCtx, AC.BlockStates), *S, InputState.Env); + transfer(StmtToEnvMap(AC.CFCtx, AC.BlockStates), *S, InputState.Env); } /// Built-in transfer function for `CFGInitializer`.