Author: Wei Yi Tee Date: 2022-08-26T22:41:20Z New Revision: fb9c1b8938fdc37705aa2e71688c4a061cfb2cd5
URL: https://github.com/llvm/llvm-project/commit/fb9c1b8938fdc37705aa2e71688c4a061cfb2cd5 DIFF: https://github.com/llvm/llvm-project/commit/fb9c1b8938fdc37705aa2e71688c4a061cfb2cd5.diff LOG: Revert "[clang][dataflow] Extend transfer functions for other `CFGElement`s" This reverts commit 4b815eb4fde0202434c6395973578349767b3f15. Added: Modified: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/TestingSupport.h Removed: ################################################################################ diff --git a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h index 4849841d2d8fb..4d1f5248f2115 100644 --- a/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -93,29 +93,10 @@ class DataflowAnalysis : public TypeErasedDataflowAnalysis { return L1 == L2; } - /// Deprecated. Use the `transfer` function overload applied on `CFGElement`. - /// - /// Transfer function for statements in the code being analysed. - virtual void transfer(const Stmt *Stmt, Lattice &L, Environment &Env) {} - - /// Transfer function for elements in the control flow graph built from the - /// code being analysed. - virtual void transfer(const CFGElement *Element, Lattice &L, - Environment &Env) {} - - // FIXME: Use CRTP pattern and remove virtual transfer functions after users - // have been updated to implement transfer. - // (e.g. static_cast<Derived*>(this)->transfer(Element, L, Env)) - void transferTypeErased(const CFGElement *Element, TypeErasedLattice &E, + void transferTypeErased(const Stmt *Stmt, TypeErasedLattice &E, Environment &Env) final { Lattice &L = llvm::any_cast<Lattice &>(E.Value); - transfer(Element, L, Env); - - // FIXME: Remove after users have been updated to implement the `transfer` - // overload applied on `CFGElement`. - if (auto Stmt = Element->getAs<CFGStmt>()) { - transfer(Stmt->getStmt(), L, Env); - } + static_cast<Derived *>(this)->transfer(Stmt, L, Env); } private: @@ -131,41 +112,37 @@ template <typename LatticeT> struct DataflowAnalysisState { Environment Env; }; -// FIXME: Rename to `runDataflowAnalysis` after usages of the overload that -// applies to `CFGStmt` have been replaced. -// /// Performs dataflow analysis and returns a mapping from basic block IDs to /// dataflow analysis states that model the respective basic blocks. The /// returned vector, if any, will have the same size as the number of CFG /// blocks, with indices corresponding to basic block IDs. Returns an error if /// the dataflow analysis cannot be performed successfully. Otherwise, calls -/// `PostVisitCFG` on each CFG element with the final analysis results at that +/// `PostVisitStmt` on each statement with the final analysis results at that /// program point. template <typename AnalysisT> llvm::Expected<std::vector< llvm::Optional<DataflowAnalysisState<typename AnalysisT::Lattice>>>> -runDataflowAnalysisOnCFG( +runDataflowAnalysis( const ControlFlowContext &CFCtx, AnalysisT &Analysis, const Environment &InitEnv, - std::function<void(const CFGElement &, const DataflowAnalysisState< - typename AnalysisT::Lattice> &)> - PostVisitCFG = nullptr) { - std::function<void(const CFGElement &, - const TypeErasedDataflowAnalysisState &)> - PostVisitCFGClosure = nullptr; - if (PostVisitCFG) { - PostVisitCFGClosure = [&PostVisitCFG]( - const CFGElement &Element, - const TypeErasedDataflowAnalysisState &State) { + std::function<void(const CFGStmt &, const DataflowAnalysisState< + typename AnalysisT::Lattice> &)> + PostVisitStmt = nullptr) { + std::function<void(const CFGStmt &, const TypeErasedDataflowAnalysisState &)> + PostVisitStmtClosure = nullptr; + if (PostVisitStmt != nullptr) { + PostVisitStmtClosure = [&PostVisitStmt]( + const CFGStmt &Stmt, + const TypeErasedDataflowAnalysisState &State) { auto *Lattice = llvm::any_cast<typename AnalysisT::Lattice>(&State.Lattice.Value); - PostVisitCFG(Element, DataflowAnalysisState<typename AnalysisT::Lattice>{ - *Lattice, State.Env}); + PostVisitStmt(Stmt, DataflowAnalysisState<typename AnalysisT::Lattice>{ + *Lattice, State.Env}); }; } auto TypeErasedBlockStates = runTypeErasedDataflowAnalysis( - CFCtx, Analysis, InitEnv, PostVisitCFGClosure); + CFCtx, Analysis, InitEnv, PostVisitStmtClosure); if (!TypeErasedBlockStates) return TypeErasedBlockStates.takeError(); @@ -186,41 +163,6 @@ runDataflowAnalysisOnCFG( return BlockStates; } -/// Deprecated. Use `runDataflowAnalysisOnCFG` instead. -/// -/// Performs dataflow analysis and returns a mapping from basic block IDs to -/// dataflow analysis states that model the respective basic blocks. The -/// returned vector, if any, will have the same size as the number of CFG -/// blocks, with indices corresponding to basic block IDs. Returns an error if -/// the dataflow analysis cannot be performed successfully. Otherwise, calls -/// `PostVisitStmt` on each statement with the final analysis results at that -/// program point. -template <typename AnalysisT> -llvm::Expected<std::vector< - llvm::Optional<DataflowAnalysisState<typename AnalysisT::Lattice>>>> -runDataflowAnalysis( - const ControlFlowContext &CFCtx, AnalysisT &Analysis, - const Environment &InitEnv, - std::function<void(const CFGStmt &, const DataflowAnalysisState< - typename AnalysisT::Lattice> &)> - PostVisitStmt = nullptr) { - std::function<void( - const CFGElement &, - const DataflowAnalysisState<typename AnalysisT::Lattice> &)> - PostVisitCFG = nullptr; - if (PostVisitStmt) { - PostVisitCFG = - [&PostVisitStmt]( - const CFGElement &Element, - const DataflowAnalysisState<typename AnalysisT::Lattice> &State) { - if (auto Stmt = Element.getAs<CFGStmt>()) { - PostVisitStmt(*Stmt, State); - } - }; - } - return runDataflowAnalysisOnCFG(CFCtx, Analysis, InitEnv, PostVisitCFG); -} - /// Abstract base class for dataflow "models": reusable analysis components that /// model a particular aspect of program semantics in the `Environment`. For /// example, a model may capture a type and its related functions. diff --git a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h index c7dccc36a6a2f..58acda7e6389d 100644 --- a/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h +++ b/clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -79,9 +79,9 @@ class TypeErasedDataflowAnalysis : public Environment::ValueModel { virtual bool isEqualTypeErased(const TypeErasedLattice &, const TypeErasedLattice &) = 0; - /// Applies the analysis transfer function for a given control flow graph - /// element and type-erased lattice element. - virtual void transferTypeErased(const CFGElement *, TypeErasedLattice &, + /// Applies the analysis transfer function for a given statement and + /// type-erased lattice element. + virtual void transferTypeErased(const Stmt *, TypeErasedLattice &, Environment &) = 0; /// If the built-in transfer functions (which model the heap and stack in the @@ -104,10 +104,10 @@ struct TypeErasedDataflowAnalysisState { : Lattice(std::move(Lattice)), Env(std::move(Env)) {} }; -/// Transfers the state of a basic block by evaluating each of its elements in +/// Transfers the state of a basic block by evaluating each of its statements in /// the context of `Analysis` and the states of its predecessors that are -/// available in `BlockStates`. `PostVisitCFG` (if provided) will be applied to -/// each element in the block, after it is evaluated. +/// available in `BlockStates`. `HandleTransferredStmt` (if provided) will be +/// applied to each statement in the block, after it is evaluated. /// /// Requirements: /// @@ -119,23 +119,23 @@ TypeErasedDataflowAnalysisState transferBlock( llvm::ArrayRef<llvm::Optional<TypeErasedDataflowAnalysisState>> BlockStates, const CFGBlock &Block, const Environment &InitEnv, TypeErasedDataflowAnalysis &Analysis, - std::function<void(const CFGElement &, + std::function<void(const CFGStmt &, const TypeErasedDataflowAnalysisState &)> - PostVisitCFG = nullptr); + HandleTransferredStmt = nullptr); /// Performs dataflow analysis and returns a mapping from basic block IDs to /// dataflow analysis states that model the respective basic blocks. Indices of /// the returned vector correspond to basic block IDs. Returns an error if the /// dataflow analysis cannot be performed successfully. Otherwise, calls -/// `PostVisitCFG` on each CFG element with the final analysis results at that +/// `PostVisitStmt` on each statement with the final analysis results at that /// program point. llvm::Expected<std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>>> runTypeErasedDataflowAnalysis( const ControlFlowContext &CFCtx, TypeErasedDataflowAnalysis &Analysis, const Environment &InitEnv, - std::function<void(const CFGElement &, + std::function<void(const CFGStmt &, const TypeErasedDataflowAnalysisState &)> - PostVisitCFG = nullptr); + PostVisitStmt = nullptr); } // namespace dataflow } // namespace clang diff --git a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp index b85a72a8a7b71..dc2ecef771b69 100644 --- a/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ b/clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -154,37 +154,19 @@ class TerminatorVisitor : public ConstStmtVisitor<TerminatorVisitor> { TransferOptions TransferOpts; }; -/// Holds data structures required for running dataflow analysis. -struct AnalysisContext { - AnalysisContext( - const ControlFlowContext &CFCtx, TypeErasedDataflowAnalysis &Analysis, - const Environment &InitEnv, - llvm::ArrayRef<llvm::Optional<TypeErasedDataflowAnalysisState>> - 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<llvm::Optional<TypeErasedDataflowAnalysisState>> BlockStates; -}; - /// Computes the input state for a given basic block by joining the output /// states of its predecessors. /// /// Requirements: /// /// All predecessors of `Block` except those with loop back edges must have -/// already been transferred. States in `AC.BlockStates` that are set to +/// already been transferred. States in `BlockStates` that are set to /// `llvm::None` represent basic blocks that are not evaluated yet. -static TypeErasedDataflowAnalysisState -computeBlockInputState(const CFGBlock &Block, AnalysisContext &AC) { +static TypeErasedDataflowAnalysisState computeBlockInputState( + const ControlFlowContext &CFCtx, + llvm::ArrayRef<llvm::Optional<TypeErasedDataflowAnalysisState>> BlockStates, + const CFGBlock &Block, const Environment &InitEnv, + TypeErasedDataflowAnalysis &Analysis) { llvm::DenseSet<const CFGBlock *> Preds; Preds.insert(Block.pred_begin(), Block.pred_end()); if (Block.getTerminator().isTemporaryDtorsBranch()) { @@ -211,16 +193,13 @@ computeBlockInputState(const CFGBlock &Block, AnalysisContext &AC) { // // See `NoreturnDestructorTest` for concrete examples. if (Block.succ_begin()->getReachableBlock()->hasNoReturnElement()) { - auto &StmtToBlock = AC.CFCtx.getStmtToBlock(); - auto StmtBlock = StmtToBlock.find(Block.getTerminatorStmt()); - assert(StmtBlock != StmtToBlock.end()); + auto StmtBlock = CFCtx.getStmtToBlock().find(Block.getTerminatorStmt()); + assert(StmtBlock != CFCtx.getStmtToBlock().end()); Preds.erase(StmtBlock->getSecond()); } } llvm::Optional<TypeErasedDataflowAnalysisState> MaybeState; - - auto &Analysis = AC.Analysis; auto BuiltinTransferOpts = Analysis.builtinTransferOptions(); for (const CFGBlock *Pred : Preds) { @@ -231,14 +210,14 @@ computeBlockInputState(const CFGBlock &Block, AnalysisContext &AC) { // Skip if `Pred` was not evaluated yet. This could happen if `Pred` has a // loop back edge to `Block`. const llvm::Optional<TypeErasedDataflowAnalysisState> &MaybePredState = - AC.BlockStates[Pred->getBlockID()]; + BlockStates[Pred->getBlockID()]; if (!MaybePredState) continue; TypeErasedDataflowAnalysisState PredState = MaybePredState.value(); if (BuiltinTransferOpts) { if (const Stmt *PredTerminatorStmt = Pred->getTerminatorStmt()) { - const StmtToEnvMapImpl StmtToEnv(AC.CFCtx, AC.BlockStates); + const StmtToEnvMapImpl StmtToEnv(CFCtx, BlockStates); TerminatorVisitor(StmtToEnv, PredState.Env, blockIndexInPredecessor(*Pred, Block), *BuiltinTransferOpts) @@ -257,125 +236,107 @@ computeBlockInputState(const CFGBlock &Block, AnalysisContext &AC) { // FIXME: Consider passing `Block` to `Analysis.typeErasedInitialElement()` // to enable building analyses like computation of dominators that // initialize the state of each basic block diff erently. - MaybeState.emplace(Analysis.typeErasedInitialElement(), AC.InitEnv); + MaybeState.emplace(Analysis.typeErasedInitialElement(), InitEnv); } return *MaybeState; } -/// Built-in transfer function for `CFGStmt`. -void builtinTransferStatement(const CFGStmt &Elt, - TypeErasedDataflowAnalysisState &InputState, - AnalysisContext &AC) { - const Stmt *S = Elt.getStmt(); +/// Transfers `State` by evaluating `CfgStmt` in the context of `Analysis`. +/// `HandleTransferredStmt` (if provided) will be applied to `CfgStmt`, after it +/// is evaluated. +static void transferCFGStmt( + const ControlFlowContext &CFCtx, + llvm::ArrayRef<llvm::Optional<TypeErasedDataflowAnalysisState>> BlockStates, + const CFGStmt &CfgStmt, TypeErasedDataflowAnalysis &Analysis, + TypeErasedDataflowAnalysisState &State, + std::function<void(const CFGStmt &, + const TypeErasedDataflowAnalysisState &)> + HandleTransferredStmt) { + const Stmt *S = CfgStmt.getStmt(); assert(S != nullptr); - transfer(StmtToEnvMapImpl(AC.CFCtx, AC.BlockStates), *S, InputState.Env, - *AC.Analysis.builtinTransferOptions()); + + auto BuiltinTransferOpts = Analysis.builtinTransferOptions(); + if (BuiltinTransferOpts) + transfer(StmtToEnvMapImpl(CFCtx, BlockStates), *S, State.Env, + *BuiltinTransferOpts); + Analysis.transferTypeErased(S, State.Lattice, State.Env); + + if (HandleTransferredStmt != nullptr) + HandleTransferredStmt(CfgStmt, State); } -/// Built-in transfer function for `CFGInitializer`. -void builtinTransferInitializer(const CFGInitializer &Elt, - TypeErasedDataflowAnalysisState &InputState) { - const CXXCtorInitializer *Init = Elt.getInitializer(); - assert(Init != nullptr); +/// Transfers `State` by evaluating `CfgInit`. +static void transferCFGInitializer(const CFGInitializer &CfgInit, + TypeErasedDataflowAnalysisState &State) { + const auto &ThisLoc = *cast<AggregateStorageLocation>( + State.Env.getThisPointeeStorageLocation()); - auto &Env = InputState.Env; - const auto &ThisLoc = - *cast<AggregateStorageLocation>(Env.getThisPointeeStorageLocation()); + const CXXCtorInitializer *Initializer = CfgInit.getInitializer(); + assert(Initializer != nullptr); - const FieldDecl *Member = Init->getMember(); + const FieldDecl *Member = Initializer->getMember(); if (Member == nullptr) // Not a field initializer. return; - auto *InitStmt = Init->getInit(); + auto *InitStmt = Initializer->getInit(); assert(InitStmt != nullptr); - auto *InitStmtLoc = Env.getStorageLocation(*InitStmt, SkipPast::Reference); + auto *InitStmtLoc = + State.Env.getStorageLocation(*InitStmt, SkipPast::Reference); if (InitStmtLoc == nullptr) return; - auto *InitStmtVal = Env.getValue(*InitStmtLoc); + auto *InitStmtVal = State.Env.getValue(*InitStmtLoc); if (InitStmtVal == nullptr) return; if (Member->getType()->isReferenceType()) { auto &MemberLoc = ThisLoc.getChild(*Member); - Env.setValue(MemberLoc, Env.takeOwnership(std::make_unique<ReferenceValue>( - *InitStmtLoc))); + State.Env.setValue(MemberLoc, + State.Env.takeOwnership( + std::make_unique<ReferenceValue>(*InitStmtLoc))); } else { auto &MemberLoc = ThisLoc.getChild(*Member); - Env.setValue(MemberLoc, *InitStmtVal); - } -} - -void builtinTransfer(const CFGElement &Elt, - TypeErasedDataflowAnalysisState &State, - AnalysisContext &AC) { - switch (Elt.getKind()) { - case CFGElement::Statement: { - builtinTransferStatement(Elt.castAs<CFGStmt>(), State, AC); - break; - } - case CFGElement::Initializer: { - builtinTransferInitializer(Elt.castAs<CFGInitializer>(), State); - break; - } - default: - // FIXME: Evaluate other kinds of `CFGElement`. - break; + State.Env.setValue(MemberLoc, *InitStmtVal); } } -/// Transfers `State` by evaluating each element in the `Block` based on the -/// `AC.Analysis` specified. -/// -/// Built-in transfer functions (if the option for `ApplyBuiltinTransfer` is set -/// by the analysis) will be applied to the element before evaluation by the -/// user-specified analysis. -/// `PostVisitCFG` (if provided) will be applied to the element after evaluation -/// by the user-specified analysis. -TypeErasedDataflowAnalysisState -transferCFGBlock(const CFGBlock &Block, AnalysisContext &AC, - std::function<void(const CFGElement &, - const TypeErasedDataflowAnalysisState &)> - PostVisitCFG = nullptr) { - auto State = computeBlockInputState(Block, AC); - for (const auto &Element : Block) { - // Built-in analysis - if (AC.Analysis.builtinTransferOptions()) { - builtinTransfer(Element, State, AC); - } - - // User-provided analysis - AC.Analysis.transferTypeErased(&Element, State.Lattice, State.Env); - - // Post processing - if (PostVisitCFG) { - PostVisitCFG(Element, State); - } - } - return State; -} - TypeErasedDataflowAnalysisState transferBlock( const ControlFlowContext &CFCtx, llvm::ArrayRef<llvm::Optional<TypeErasedDataflowAnalysisState>> BlockStates, const CFGBlock &Block, const Environment &InitEnv, TypeErasedDataflowAnalysis &Analysis, - std::function<void(const CFGElement &, + std::function<void(const CFGStmt &, const TypeErasedDataflowAnalysisState &)> - PostVisitCFG) { - AnalysisContext AC(CFCtx, Analysis, InitEnv, BlockStates); - return transferCFGBlock(Block, AC, PostVisitCFG); + HandleTransferredStmt) { + TypeErasedDataflowAnalysisState State = + computeBlockInputState(CFCtx, BlockStates, Block, InitEnv, Analysis); + for (const CFGElement &Element : Block) { + switch (Element.getKind()) { + case CFGElement::Statement: + transferCFGStmt(CFCtx, BlockStates, *Element.getAs<CFGStmt>(), Analysis, + State, HandleTransferredStmt); + break; + case CFGElement::Initializer: + if (Analysis.builtinTransferOptions()) + transferCFGInitializer(*Element.getAs<CFGInitializer>(), State); + break; + default: + // FIXME: Evaluate other kinds of `CFGElement`. + break; + } + } + return State; } llvm::Expected<std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>>> runTypeErasedDataflowAnalysis( const ControlFlowContext &CFCtx, TypeErasedDataflowAnalysis &Analysis, const Environment &InitEnv, - std::function<void(const CFGElement &, + std::function<void(const CFGStmt &, const TypeErasedDataflowAnalysisState &)> - PostVisitCFG) { + PostVisitStmt) { PostOrderCFGView POV(&CFCtx.getCFG()); ForwardDataflowWorklist Worklist(CFCtx.getCFG(), &POV); @@ -388,8 +349,6 @@ runTypeErasedDataflowAnalysis( InitEnv}; Worklist.enqueueSuccessors(&Entry); - AnalysisContext AC(CFCtx, Analysis, InitEnv, BlockStates); - // Bugs in lattices and transfer functions can prevent the analysis from // converging. To limit the damage (infinite loops) that these bugs can cause, // limit the number of iterations. @@ -414,7 +373,7 @@ runTypeErasedDataflowAnalysis( const llvm::Optional<TypeErasedDataflowAnalysisState> &OldBlockState = BlockStates[Block->getBlockID()]; TypeErasedDataflowAnalysisState NewBlockState = - transferCFGBlock(*Block, AC); + transferBlock(CFCtx, BlockStates, *Block, InitEnv, Analysis); if (OldBlockState && Analysis.isEqualTypeErased(OldBlockState.value().Lattice, @@ -436,12 +395,14 @@ runTypeErasedDataflowAnalysis( // FIXME: Consider evaluating unreachable basic blocks (those that have a // state set to `llvm::None` at this point) to also analyze dead code. - if (PostVisitCFG) { + if (PostVisitStmt) { for (const CFGBlock *Block : CFCtx.getCFG()) { // Skip blocks that were not evaluated. if (!BlockStates[Block->getBlockID()]) continue; - transferCFGBlock(*Block, AC, PostVisitCFG); + + transferBlock(CFCtx, BlockStates, *Block, InitEnv, Analysis, + PostVisitStmt); } } diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h index cdcf61ee22577..f09d5f9db21ad 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h @@ -71,25 +71,14 @@ struct AnalysisData { std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>> &BlockStates; }; -// FIXME: Rename to `checkDataflow` after usages of the overload that applies to -// `CFGStmt` have been replaced. -// -/// Runs dataflow analysis (specified from `MakeAnalysis`) and the -/// `PostVisitCFG` function (if provided) on the body of the function that -/// matches `TargetFuncMatcher` in code snippet `Code`. `VerifyResults` checks -/// that the results from the analysis are correct. -/// -/// Requirements: -/// -/// `AnalysisT` contains a type `Lattice`. template <typename AnalysisT> -llvm::Error checkDataflowOnCFG( +llvm::Error checkDataflow( llvm::StringRef Code, ast_matchers::internal::Matcher<FunctionDecl> TargetFuncMatcher, std::function<AnalysisT(ASTContext &, Environment &)> MakeAnalysis, - std::function<void(ASTContext &, const CFGElement &, + std::function<void(ASTContext &, const CFGStmt &, const TypeErasedDataflowAnalysisState &)> - PostVisitCFG, + PostVisitStmt, std::function<void(AnalysisData)> VerifyResults, ArrayRef<std::string> Args, const tooling::FileContentMappings &VirtualMappedFiles = {}) { llvm::Annotations AnnotatedCode(Code); @@ -123,14 +112,13 @@ llvm::Error checkDataflowOnCFG( Environment Env(DACtx, *F); auto Analysis = MakeAnalysis(Context, Env); - std::function<void(const CFGElement &, - const TypeErasedDataflowAnalysisState &)> - PostVisitCFGClosure = nullptr; - if (PostVisitCFG) { - PostVisitCFGClosure = [&PostVisitCFG, &Context]( - const CFGElement &Element, - const TypeErasedDataflowAnalysisState &State) { - PostVisitCFG(Context, Element, State); + std::function<void(const CFGStmt &, const TypeErasedDataflowAnalysisState &)> + PostVisitStmtClosure = nullptr; + if (PostVisitStmt != nullptr) { + PostVisitStmtClosure = [&PostVisitStmt, &Context]( + const CFGStmt &Stmt, + const TypeErasedDataflowAnalysisState &State) { + PostVisitStmt(Context, Stmt, State); }; } @@ -142,7 +130,7 @@ llvm::Error checkDataflowOnCFG( llvm::Expected<std::vector<llvm::Optional<TypeErasedDataflowAnalysisState>>> MaybeBlockStates = runTypeErasedDataflowAnalysis(*CFCtx, Analysis, Env, - PostVisitCFGClosure); + PostVisitStmtClosure); if (!MaybeBlockStates) return MaybeBlockStates.takeError(); auto &BlockStates = *MaybeBlockStates; @@ -153,32 +141,6 @@ llvm::Error checkDataflowOnCFG( return llvm::Error::success(); } -template <typename AnalysisT> -llvm::Error checkDataflow( - llvm::StringRef Code, - ast_matchers::internal::Matcher<FunctionDecl> TargetFuncMatcher, - std::function<AnalysisT(ASTContext &, Environment &)> MakeAnalysis, - std::function<void(ASTContext &, const CFGStmt &, - const TypeErasedDataflowAnalysisState &)> - PostVisitStmt, - std::function<void(AnalysisData)> VerifyResults, ArrayRef<std::string> Args, - const tooling::FileContentMappings &VirtualMappedFiles = {}) { - std::function<void(ASTContext & Context, const CFGElement &, - const TypeErasedDataflowAnalysisState &)> - PostVisitCFG = nullptr; - if (PostVisitStmt) { - PostVisitCFG = - [&PostVisitStmt](ASTContext &Context, const CFGElement &Element, - const TypeErasedDataflowAnalysisState &State) { - if (auto Stmt = Element.getAs<CFGStmt>()) { - PostVisitStmt(Context, *Stmt, State); - } - }; - } - return checkDataflowOnCFG(Code, TargetFuncMatcher, MakeAnalysis, PostVisitCFG, - VerifyResults, Args, VirtualMappedFiles); -} - // Runs dataflow on the body of the function that matches `TargetFuncMatcher` in // code snippet `Code`. Requires: `AnalysisT` contains a type `Lattice`. template <typename AnalysisT> @@ -195,9 +157,9 @@ llvm::Error checkDataflow( const tooling::FileContentMappings &VirtualMappedFiles = {}) { using StateT = DataflowAnalysisState<typename AnalysisT::Lattice>; - return checkDataflowOnCFG( + return checkDataflow( Code, std::move(TargetFuncMatcher), std::move(MakeAnalysis), - /*PostVisitCFG=*/nullptr, + /*PostVisitStmt=*/nullptr, [&VerifyResults](AnalysisData AnalysisData) { if (AnalysisData.BlockStates.empty()) { VerifyResults({}, AnalysisData.ASTCtx); @@ -218,13 +180,9 @@ llvm::Error checkDataflow( AnalysisData.CFCtx, AnalysisData.BlockStates, *Block, AnalysisData.Env, AnalysisData.Analysis, [&Results, - &Annotations](const clang::CFGElement &Element, + &Annotations](const clang::CFGStmt &Stmt, const TypeErasedDataflowAnalysisState &State) { - // FIXME: Extend testing annotations to non statement constructs - auto Stmt = Element.getAs<CFGStmt>(); - if (!Stmt) - return; - auto It = Annotations.find(Stmt->getStmt()); + auto It = Annotations.find(Stmt.getStmt()); if (It == Annotations.end()) return; auto *Lattice = llvm::any_cast<typename AnalysisT::Lattice>( _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits