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 { |
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 | |
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>(Val: 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, PVD: P); |
41 | } |
42 | } else if (const auto *CD = dyn_cast<CXXConstructorDecl>(Val: 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>(Val: 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, PVD: P); |
57 | } |
58 | } |
59 | } |
60 | |
61 | public: |
62 | ParamRegionTestConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {} |
63 | |
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: |
74 | std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, |
75 | StringRef File) override { |
76 | return std::make_unique<ParamRegionTestConsumer>(args&: Compiler); |
77 | } |
78 | }; |
79 | |
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 | |