| //===- unittests/StaticAnalyzer/ParamRegionTest.cpp -----------------------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "Reusables.h" |
| |
| #include "clang/Tooling/Tooling.h" |
| #include "gtest/gtest.h" |
| |
| namespace clang { |
| namespace ento { |
| namespace { |
| |
| class ParamRegionTestConsumer : public ExprEngineConsumer { |
| void checkForSameParamRegions(MemRegionManager &MRMgr, |
| const StackFrameContext *SFC, |
| const ParmVarDecl *PVD) { |
| ASSERT_TRUE(llvm::all_of(PVD->redecls(), [&](const clang::VarDecl *D2) { |
| return MRMgr.getVarRegion(PVD, SFC) == |
| MRMgr.getVarRegion(cast<ParmVarDecl>(D2), SFC); |
| })); |
| } |
| |
| void performTest(const Decl *D) { |
| StoreManager &StMgr = Eng.getStoreManager(); |
| MemRegionManager &MRMgr = StMgr.getRegionManager(); |
| const StackFrameContext *SFC = |
| Eng.getAnalysisDeclContextManager().getStackFrame(D); |
| |
| if (const auto *FD = dyn_cast<FunctionDecl>(D)) { |
| for (const auto *P : FD->parameters()) { |
| if (SFC->inTopFrame()) |
| assert(isa<NonParamVarRegion>(MRMgr.getVarRegion(P, SFC))); |
| else |
| assert(isa<ParamVarRegion>(MRMgr.getVarRegion(P, SFC))); |
| checkForSameParamRegions(MRMgr, SFC, P); |
| } |
| } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) { |
| for (const auto *P : CD->parameters()) { |
| if (SFC->inTopFrame()) |
| assert(isa<NonParamVarRegion>(MRMgr.getVarRegion(P, SFC))); |
| else |
| assert(isa<ParamVarRegion>(MRMgr.getVarRegion(P, SFC))); |
| checkForSameParamRegions(MRMgr, SFC, P); |
| } |
| } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { |
| for (const auto *P : MD->parameters()) { |
| if (SFC->inTopFrame()) |
| assert(isa<NonParamVarRegion>(MRMgr.getVarRegion(P, SFC))); |
| else |
| assert(isa<ParamVarRegion>(MRMgr.getVarRegion(P, SFC))); |
| checkForSameParamRegions(MRMgr, SFC, P); |
| } |
| } |
| } |
| |
| public: |
| ParamRegionTestConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {} |
| |
| bool HandleTopLevelDecl(DeclGroupRef DG) override { |
| for (const auto *D : DG) { |
| performTest(D); |
| } |
| return true; |
| } |
| }; |
| |
| class ParamRegionTestAction : public ASTFrontendAction { |
| public: |
| std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, |
| StringRef File) override { |
| return std::make_unique<ParamRegionTestConsumer>(Compiler); |
| } |
| }; |
| |
| TEST(ParamRegion, ParamRegionTest) { |
| EXPECT_TRUE( |
| tooling::runToolOnCode(std::make_unique<ParamRegionTestAction>(), |
| R"(void foo(int n); |
| void baz(int p); |
| |
| void foo(int n) { |
| auto lambda = [n](int m) { |
| return n + m; |
| }; |
| |
| int k = lambda(2); |
| } |
| |
| void bar(int l) { |
| foo(l); |
| } |
| |
| struct S { |
| int n; |
| S(int nn): n(nn) {} |
| }; |
| |
| void baz(int p) { |
| S s(p); |
| } |
| |
| void bar(int l); |
| void baz(int p);)")); |
| EXPECT_TRUE( |
| tooling::runToolOnCode(std::make_unique<ParamRegionTestAction>(), |
| R"(@interface O |
| + alloc; |
| - initWithInt:(int)q; |
| @end |
| |
| void qix(int r) { |
| O *o = [[O alloc] initWithInt:r]; |
| })", |
| "input.m")); |
| } |
| |
| } // namespace |
| } // namespace ento |
| } // namespace clang |