ymandel created this revision. ymandel added a reviewer: sgatev. Herald added subscribers: tschuett, steakhal. ymandel requested review of this revision. Herald added a project: clang.
These built-in functions build the (sophisticated) model of the code's memory. This model isn't used by all analyses, so we provide for disabling it to avoid incurring the costs associated with its construction. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D118178 Files: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp clang/unittests/Analysis/FlowSensitive/TransferTest.cpp clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp
Index: clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp =================================================================== --- clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp +++ clang/unittests/Analysis/FlowSensitive/TypeErasedDataflowAnalysisTest.cpp @@ -42,6 +42,8 @@ template <typename AnalysisT> class AnalysisCallback : public ast_matchers::MatchFinder::MatchCallback { public: + AnalysisCallback(AnalysisT (*MakeAnalysis)(ASTContext &)) + : MakeAnalysis(MakeAnalysis) {} void run(const ast_matchers::MatchFinder::MatchResult &Result) override { assert(BlockStates.empty()); @@ -54,12 +56,13 @@ auto CFCtx = llvm::cantFail( ControlFlowContext::build(nullptr, Body, Result.Context)); - AnalysisT Analysis(*Result.Context); + AnalysisT Analysis = MakeAnalysis(*Result.Context); DataflowAnalysisContext DACtx; Environment Env(DACtx); BlockStates = runDataflowAnalysis(CFCtx, Analysis, Env); } + AnalysisT (*MakeAnalysis)(ASTContext &); std::vector< llvm::Optional<DataflowAnalysisState<typename AnalysisT::Lattice>>> BlockStates; @@ -67,11 +70,11 @@ template <typename AnalysisT> std::vector<llvm::Optional<DataflowAnalysisState<typename AnalysisT::Lattice>>> -runAnalysis(llvm::StringRef Code) { +runAnalysis(llvm::StringRef Code, AnalysisT (*MakeAnalysis)(ASTContext &)) { std::unique_ptr<ASTUnit> AST = tooling::buildASTFromCodeWithArgs(Code, {"-std=c++11"}); - AnalysisCallback<AnalysisT> Callback; + AnalysisCallback<AnalysisT> Callback(MakeAnalysis); ast_matchers::MatchFinder Finder; Finder.addMatcher( ast_matchers::functionDecl(ast_matchers::hasName("target")).bind("func"), @@ -82,9 +85,8 @@ } TEST(DataflowAnalysisTest, NoopAnalysis) { - auto BlockStates = runAnalysis<NoopAnalysis>(R"( - void target() {} - )"); + auto BlockStates = runAnalysis<NoopAnalysis>( + "void target() {}", [](ASTContext &C) { return NoopAnalysis(C, false); }); EXPECT_EQ(BlockStates.size(), 2u); EXPECT_TRUE(BlockStates[0].hasValue()); EXPECT_TRUE(BlockStates[1].hasValue()); @@ -109,8 +111,9 @@ : public DataflowAnalysis<NonConvergingAnalysis, NonConvergingLattice> { public: explicit NonConvergingAnalysis(ASTContext &Context) - : DataflowAnalysis<NonConvergingAnalysis, NonConvergingLattice>(Context) { - } + : DataflowAnalysis<NonConvergingAnalysis, NonConvergingLattice>( + Context, + /*ApplyBuiltinTransfer=*/false) {} static NonConvergingLattice initialElement() { return {0}; } @@ -120,11 +123,13 @@ }; TEST(DataflowAnalysisTest, NonConvergingAnalysis) { - auto BlockStates = runAnalysis<NonConvergingAnalysis>(R"( + auto BlockStates = runAnalysis<NonConvergingAnalysis>( + R"( void target() { while(true) {} } - )"); + )", + [](ASTContext &C) { return NonConvergingAnalysis(C); }); EXPECT_EQ(BlockStates.size(), 4u); EXPECT_TRUE(BlockStates[0].hasValue()); EXPECT_TRUE(BlockStates[1].hasValue()); Index: clang/unittests/Analysis/FlowSensitive/TransferTest.cpp =================================================================== --- clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -40,11 +40,14 @@ protected: template <typename Matcher> void runDataflow(llvm::StringRef Code, Matcher Match, - LangStandard::Kind Std = LangStandard::lang_cxx17) { + LangStandard::Kind Std = LangStandard::lang_cxx17, + bool ApplyBuiltinTransfer = true) { ASSERT_THAT_ERROR( test::checkDataflow<NoopAnalysis>( Code, "target", - [](ASTContext &C, Environment &) { return NoopAnalysis(C); }, + [ApplyBuiltinTransfer](ASTContext &C, Environment &) { + return NoopAnalysis(C, ApplyBuiltinTransfer); + }, [&Match]( llvm::ArrayRef< std::pair<std::string, DataflowAnalysisState<NoopLattice>>> @@ -73,6 +76,31 @@ return Result; } +TEST_F(TransferTest, IntVarDeclNotTrackedWhenTransferDisabled) { + std::string Code = R"( + void target() { + int Foo; + // [[p]] + } + )"; + runDataflow( + Code, + [](llvm::ArrayRef< + std::pair<std::string, DataflowAnalysisState<NoopLattice>>> + Results, + ASTContext &ASTCtx) { + ASSERT_THAT(Results, ElementsAre(Pair("p", _))); + const Environment &Env = Results[0].second.Env; + + const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo"); + ASSERT_THAT(FooDecl, NotNull()); + + EXPECT_EQ(Env.getStorageLocation(*FooDecl, SkipPast::None), nullptr); + }, + LangStandard::lang_cxx17, + /*ApplyBuiltinTransfer=*/false); +} + TEST_F(TransferTest, IntVarDecl) { std::string Code = R"( void target() { Index: clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp =================================================================== --- clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp +++ clang/unittests/Analysis/FlowSensitive/TestingSupportTest.cpp @@ -79,12 +79,12 @@ ASTContext &)> Expectations) { ASSERT_THAT_ERROR( - test::checkDataflow<NoopAnalysis>(Code, Target, - [](ASTContext &Context, Environment &) { - return NoopAnalysis(Context); - }, - std::move(Expectations), - {"-fsyntax-only", "-std=c++17"}), + test::checkDataflow<NoopAnalysis>( + Code, Target, + [](ASTContext &Context, Environment &) { + return NoopAnalysis(Context, /*ApplyBuiltinTransfer=*/false); + }, + std::move(Expectations), {"-fsyntax-only", "-std=c++17"}), llvm::Succeeded()); } Index: clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h =================================================================== --- clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h +++ clang/unittests/Analysis/FlowSensitive/NoopAnalysis.h @@ -39,8 +39,11 @@ class NoopAnalysis : public DataflowAnalysis<NoopAnalysis, NoopLattice> { public: - NoopAnalysis(ASTContext &Context) - : DataflowAnalysis<NoopAnalysis, NoopLattice>(Context) {} + // `ApplyBuiltinTransfer` controls whether to run the built-in transfer + // functions that model memory during the analysis. + NoopAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer) + : DataflowAnalysis<NoopAnalysis, NoopLattice>(Context, + ApplyBuiltinTransfer) {} static NoopLattice initialElement() { return {}; } Index: clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp =================================================================== --- clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp +++ clang/lib/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.cpp @@ -119,7 +119,8 @@ const Stmt *S = CfgStmt.getStmt(); assert(S != nullptr); - transfer(*S, State.Env); + if (Analysis.applyBuiltinTransfer()) + transfer(*S, State.Env); Analysis.transferTypeErased(S, State.Lattice, State.Env); if (HandleTransferredStmt != nullptr) @@ -178,7 +179,8 @@ HandleTransferredStmt); break; case CFGElement::Initializer: - transferCFGInitializer(*Element.getAs<CFGInitializer>(), State); + if (Analysis.applyBuiltinTransfer()) + transferCFGInitializer(*Element.getAs<CFGInitializer>(), State); break; default: // FIXME: Evaluate other kinds of `CFGElement`. Index: clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h =================================================================== --- clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h +++ clang/include/clang/Analysis/FlowSensitive/TypeErasedDataflowAnalysis.h @@ -41,7 +41,14 @@ /// Type-erased base class for dataflow analyses built on a single lattice type. class TypeErasedDataflowAnalysis { + // Determines whether to apply the built-in transfer functions. + bool ApplyBuiltinTransfer; + public: + TypeErasedDataflowAnalysis() : ApplyBuiltinTransfer(true) {} + TypeErasedDataflowAnalysis(bool ApplyBuiltinTransfer) + : ApplyBuiltinTransfer(ApplyBuiltinTransfer) {} + virtual ~TypeErasedDataflowAnalysis() {} /// Returns the `ASTContext` that is used by the analysis. @@ -66,6 +73,10 @@ /// type-erased lattice element. virtual void transferTypeErased(const Stmt *, TypeErasedLattice &, Environment &) = 0; + + // Determines whether to apply the built-in transfer functions, which model + // the heap and stack in the `Environment`. + bool applyBuiltinTransfer() { return ApplyBuiltinTransfer; } }; /// Type-erased model of the program at a given program point. Index: clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h =================================================================== --- clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h +++ clang/include/clang/Analysis/FlowSensitive/DataflowAnalysis.h @@ -57,6 +57,8 @@ using Lattice = LatticeT; explicit DataflowAnalysis(ASTContext &Context) : Context(Context) {} + explicit DataflowAnalysis(ASTContext &Context, bool ApplyBuiltinTransfer) + : TypeErasedDataflowAnalysis(ApplyBuiltinTransfer), Context(Context) {} ASTContext &getASTContext() final { return Context; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits