1 //===- unittests/StaticAnalyzer/ParamRegionTest.cpp -----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Reusables.h"
10 
11 #include "clang/Tooling/Tooling.h"
12 #include "gtest/gtest.h"
13 
14 namespace clang {
15 namespace ento {
16 namespace {
17 
18 class ParamRegionTestConsumer : public ExprEngineConsumer {
checkForSameParamRegions(MemRegionManager & MRMgr,const StackFrameContext * SFC,const ParmVarDecl * PVD)19   void checkForSameParamRegions(MemRegionManager &MRMgr,
20                                 const StackFrameContext *SFC,
21                                 const ParmVarDecl *PVD) {
22     ASSERT_TRUE(llvm::all_of(PVD->redecls(), [&](const clang::VarDecl *D2) {
23       return MRMgr.getVarRegion(PVD, SFC) ==
24              MRMgr.getVarRegion(cast<ParmVarDecl>(D2), SFC);
25     }));
26   }
27 
performTest(const Decl * D)28   void performTest(const Decl *D) {
29     StoreManager &StMgr = Eng.getStoreManager();
30     MemRegionManager &MRMgr = StMgr.getRegionManager();
31     const StackFrameContext *SFC =
32         Eng.getAnalysisDeclContextManager().getStackFrame(D);
33 
34     if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
35       for (const auto *P : FD->parameters()) {
36         if (SFC->inTopFrame())
37           assert(isa<NonParamVarRegion>(MRMgr.getVarRegion(P, SFC)));
38         else
39           assert(isa<ParamVarRegion>(MRMgr.getVarRegion(P, SFC)));
40         checkForSameParamRegions(MRMgr, SFC, P);
41       }
42     } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(D)) {
43       for (const auto *P : CD->parameters()) {
44         if (SFC->inTopFrame())
45           assert(isa<NonParamVarRegion>(MRMgr.getVarRegion(P, SFC)));
46         else
47           assert(isa<ParamVarRegion>(MRMgr.getVarRegion(P, SFC)));
48         checkForSameParamRegions(MRMgr, SFC, P);
49       }
50     } else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
51       for (const auto *P : MD->parameters()) {
52         if (SFC->inTopFrame())
53           assert(isa<NonParamVarRegion>(MRMgr.getVarRegion(P, SFC)));
54         else
55           assert(isa<ParamVarRegion>(MRMgr.getVarRegion(P, SFC)));
56         checkForSameParamRegions(MRMgr, SFC, P);
57       }
58     }
59   }
60 
61 public:
ParamRegionTestConsumer(CompilerInstance & C)62   ParamRegionTestConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
63 
HandleTopLevelDecl(DeclGroupRef DG)64   bool HandleTopLevelDecl(DeclGroupRef DG) override {
65     for (const auto *D : DG) {
66       performTest(D);
67     }
68     return true;
69   }
70 };
71 
72 class ParamRegionTestAction : public ASTFrontendAction {
73 public:
CreateASTConsumer(CompilerInstance & Compiler,StringRef File)74   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
75                                                  StringRef File) override {
76     return std::make_unique<ParamRegionTestConsumer>(Compiler);
77   }
78 };
79 
TEST(ParamRegion,ParamRegionTest)80 TEST(ParamRegion, ParamRegionTest) {
81   EXPECT_TRUE(
82       tooling::runToolOnCode(std::make_unique<ParamRegionTestAction>(),
83                              R"(void foo(int n);
84                                 void baz(int p);
85 
86                                 void foo(int n) {
87                                   auto lambda = [n](int m) {
88                                     return n + m;
89                                   };
90 
91                                   int k = lambda(2);
92                                 }
93 
94                                 void bar(int l) {
95                                   foo(l);
96                                 }
97 
98                                 struct S {
99                                   int n;
100                                   S(int nn): n(nn) {}
101                                 };
102 
103                                 void baz(int p) {
104                                   S s(p);
105                                 }
106 
107                                 void bar(int l);
108                                 void baz(int p);)"));
109   EXPECT_TRUE(
110       tooling::runToolOnCode(std::make_unique<ParamRegionTestAction>(),
111                              R"(@interface O
112                                 + alloc;
113                                 - initWithInt:(int)q;
114                                 @end
115 
116                                 void qix(int r) {
117                                   O *o = [[O alloc] initWithInt:r];
118                                 })",
119                              "input.m"));
120 }
121 
122 } // namespace
123 } // namespace ento
124 } // namespace clang
125