1 | //===- unittests/StaticAnalyzer/SymbolReaperTest.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 SuperRegionLivenessConsumer : public ExprEngineConsumer { |
19 | void performTest(const Decl *D) { |
20 | const auto *FD = findDeclByName<FieldDecl>(Where: D, Name: "x" ); |
21 | const auto *VD = findDeclByName<VarDecl>(Where: D, Name: "s" ); |
22 | assert(FD && VD); |
23 | |
24 | // The variable must belong to a stack frame, |
25 | // otherwise SymbolReaper would think it's a global. |
26 | const StackFrameContext *SFC = |
27 | Eng.getAnalysisDeclContextManager().getStackFrame(D); |
28 | |
29 | // Create regions for 's' and 's.x'. |
30 | const VarRegion *VR = Eng.getRegionManager().getVarRegion(VD, SFC); |
31 | const FieldRegion *FR = Eng.getRegionManager().getFieldRegion(FD, VR); |
32 | |
33 | // Pass a null location context to the SymbolReaper so that |
34 | // it was thinking that the variable is dead. |
35 | SymbolReaper SymReaper((StackFrameContext *)nullptr, (Stmt *)nullptr, |
36 | Eng.getSymbolManager(), Eng.getStoreManager()); |
37 | |
38 | SymReaper.markLive(region: FR); |
39 | EXPECT_TRUE(SymReaper.isLiveRegion(VR)); |
40 | } |
41 | |
42 | public: |
43 | SuperRegionLivenessConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {} |
44 | ~SuperRegionLivenessConsumer() override {} |
45 | |
46 | bool HandleTopLevelDecl(DeclGroupRef DG) override { |
47 | for (const auto *D : DG) |
48 | performTest(D); |
49 | return true; |
50 | } |
51 | }; |
52 | |
53 | class SuperRegionLivenessAction : public ASTFrontendAction { |
54 | public: |
55 | SuperRegionLivenessAction() {} |
56 | std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler, |
57 | StringRef File) override { |
58 | return std::make_unique<SuperRegionLivenessConsumer>(args&: Compiler); |
59 | } |
60 | }; |
61 | |
62 | // Test that marking s.x as live would also make s live. |
63 | TEST(SymbolReaper, SuperRegionLiveness) { |
64 | EXPECT_TRUE( |
65 | tooling::runToolOnCode(std::make_unique<SuperRegionLivenessAction>(), |
66 | "void foo() { struct S { int x; } s; }" )); |
67 | } |
68 | |
69 | } // namespace |
70 | } // namespace ento |
71 | } // namespace clang |
72 | |