xref: /llvm-project/clang/unittests/StaticAnalyzer/StoreTest.cpp (revision bd06c417e6c717cbe33b566d7bbaf27fb47e763a)
19b02a9b4SArtem Dergachev //===- unittests/StaticAnalyzer/StoreTest.cpp -----------------------------===//
29b02a9b4SArtem Dergachev //
39b02a9b4SArtem Dergachev // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
49b02a9b4SArtem Dergachev // See https://llvm.org/LICENSE.txt for license information.
59b02a9b4SArtem Dergachev // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
69b02a9b4SArtem Dergachev //
79b02a9b4SArtem Dergachev //===----------------------------------------------------------------------===//
89b02a9b4SArtem Dergachev 
99b02a9b4SArtem Dergachev #include "Reusables.h"
109b02a9b4SArtem Dergachev 
119b02a9b4SArtem Dergachev #include "clang/Tooling/Tooling.h"
129b02a9b4SArtem Dergachev #include "gtest/gtest.h"
139b02a9b4SArtem Dergachev 
149b02a9b4SArtem Dergachev namespace clang {
159b02a9b4SArtem Dergachev namespace ento {
169b02a9b4SArtem Dergachev namespace {
179b02a9b4SArtem Dergachev 
18*bd06c417SValeriy Savchenko class StoreTestConsumer : public ExprEngineConsumer {
199b02a9b4SArtem Dergachev public:
StoreTestConsumer(CompilerInstance & C)20*bd06c417SValeriy Savchenko   StoreTestConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
219b02a9b4SArtem Dergachev 
HandleTopLevelDecl(DeclGroupRef DG)229b02a9b4SArtem Dergachev   bool HandleTopLevelDecl(DeclGroupRef DG) override {
239b02a9b4SArtem Dergachev     for (const auto *D : DG)
249b02a9b4SArtem Dergachev       performTest(D);
259b02a9b4SArtem Dergachev     return true;
269b02a9b4SArtem Dergachev   }
27*bd06c417SValeriy Savchenko 
28*bd06c417SValeriy Savchenko private:
29*bd06c417SValeriy Savchenko   virtual void performTest(const Decl *D) = 0;
309b02a9b4SArtem Dergachev };
319b02a9b4SArtem Dergachev 
32*bd06c417SValeriy Savchenko template <class ConsumerTy> class TestAction : public ASTFrontendAction {
339b02a9b4SArtem Dergachev public:
CreateASTConsumer(CompilerInstance & Compiler,StringRef File)349b02a9b4SArtem Dergachev   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
359b02a9b4SArtem Dergachev                                                  StringRef File) override {
36*bd06c417SValeriy Savchenko     return std::make_unique<ConsumerTy>(Compiler);
379b02a9b4SArtem Dergachev   }
389b02a9b4SArtem Dergachev };
399b02a9b4SArtem Dergachev 
40*bd06c417SValeriy Savchenko // Test that we can put a value into an int-type variable and load it
41*bd06c417SValeriy Savchenko // back from that variable. Test what happens if default bindings are used.
42*bd06c417SValeriy Savchenko class VariableBindConsumer : public StoreTestConsumer {
performTest(const Decl * D)43*bd06c417SValeriy Savchenko   void performTest(const Decl *D) override {
44*bd06c417SValeriy Savchenko     StoreManager &SManager = Eng.getStoreManager();
45*bd06c417SValeriy Savchenko     SValBuilder &Builder = Eng.getSValBuilder();
46*bd06c417SValeriy Savchenko     MemRegionManager &MRManager = SManager.getRegionManager();
47*bd06c417SValeriy Savchenko     const ASTContext &ASTCtxt = Eng.getContext();
48*bd06c417SValeriy Savchenko 
49*bd06c417SValeriy Savchenko     const auto *VDX0 = findDeclByName<VarDecl>(D, "x0");
50*bd06c417SValeriy Savchenko     const auto *VDY0 = findDeclByName<VarDecl>(D, "y0");
51*bd06c417SValeriy Savchenko     const auto *VDZ0 = findDeclByName<VarDecl>(D, "z0");
52*bd06c417SValeriy Savchenko     const auto *VDX1 = findDeclByName<VarDecl>(D, "x1");
53*bd06c417SValeriy Savchenko     const auto *VDY1 = findDeclByName<VarDecl>(D, "y1");
54*bd06c417SValeriy Savchenko 
55*bd06c417SValeriy Savchenko     ASSERT_TRUE(VDX0 && VDY0 && VDZ0 && VDX1 && VDY1);
56*bd06c417SValeriy Savchenko 
57*bd06c417SValeriy Savchenko     const StackFrameContext *SFC =
58*bd06c417SValeriy Savchenko         Eng.getAnalysisDeclContextManager().getStackFrame(D);
59*bd06c417SValeriy Savchenko 
60*bd06c417SValeriy Savchenko     Loc LX0 = loc::MemRegionVal(MRManager.getVarRegion(VDX0, SFC));
61*bd06c417SValeriy Savchenko     Loc LY0 = loc::MemRegionVal(MRManager.getVarRegion(VDY0, SFC));
62*bd06c417SValeriy Savchenko     Loc LZ0 = loc::MemRegionVal(MRManager.getVarRegion(VDZ0, SFC));
63*bd06c417SValeriy Savchenko     Loc LX1 = loc::MemRegionVal(MRManager.getVarRegion(VDX1, SFC));
64*bd06c417SValeriy Savchenko     Loc LY1 = loc::MemRegionVal(MRManager.getVarRegion(VDY1, SFC));
65*bd06c417SValeriy Savchenko 
66*bd06c417SValeriy Savchenko     Store StInit = SManager.getInitialStore(SFC).getStore();
67*bd06c417SValeriy Savchenko     SVal Zero = Builder.makeZeroVal(ASTCtxt.IntTy);
68*bd06c417SValeriy Savchenko     SVal One = Builder.makeIntVal(1, ASTCtxt.IntTy);
69*bd06c417SValeriy Savchenko     SVal NarrowZero = Builder.makeZeroVal(ASTCtxt.CharTy);
70*bd06c417SValeriy Savchenko 
71*bd06c417SValeriy Savchenko     // Bind(Zero)
72*bd06c417SValeriy Savchenko     Store StX0 = SManager.Bind(StInit, LX0, Zero).getStore();
73*bd06c417SValeriy Savchenko     EXPECT_EQ(Zero, SManager.getBinding(StX0, LX0, ASTCtxt.IntTy));
74*bd06c417SValeriy Savchenko 
75*bd06c417SValeriy Savchenko     // BindDefaultInitial(Zero)
76*bd06c417SValeriy Savchenko     Store StY0 =
77*bd06c417SValeriy Savchenko         SManager.BindDefaultInitial(StInit, LY0.getAsRegion(), Zero).getStore();
78*bd06c417SValeriy Savchenko     EXPECT_EQ(Zero, SManager.getBinding(StY0, LY0, ASTCtxt.IntTy));
79*bd06c417SValeriy Savchenko     EXPECT_EQ(Zero, *SManager.getDefaultBinding(StY0, LY0.getAsRegion()));
80*bd06c417SValeriy Savchenko 
81*bd06c417SValeriy Savchenko     // BindDefaultZero()
82*bd06c417SValeriy Savchenko     Store StZ0 = SManager.BindDefaultZero(StInit, LZ0.getAsRegion()).getStore();
83*bd06c417SValeriy Savchenko     // BindDefaultZero wipes the region with '0 S8b', not with out Zero.
84*bd06c417SValeriy Savchenko     // Direct load, however, does give us back the object of the type
85*bd06c417SValeriy Savchenko     // that we specify for loading.
86*bd06c417SValeriy Savchenko     EXPECT_EQ(Zero, SManager.getBinding(StZ0, LZ0, ASTCtxt.IntTy));
87*bd06c417SValeriy Savchenko     EXPECT_EQ(NarrowZero, *SManager.getDefaultBinding(StZ0, LZ0.getAsRegion()));
88*bd06c417SValeriy Savchenko 
89*bd06c417SValeriy Savchenko     // Bind(One)
90*bd06c417SValeriy Savchenko     Store StX1 = SManager.Bind(StInit, LX1, One).getStore();
91*bd06c417SValeriy Savchenko     EXPECT_EQ(One, SManager.getBinding(StX1, LX1, ASTCtxt.IntTy));
92*bd06c417SValeriy Savchenko 
93*bd06c417SValeriy Savchenko     // BindDefaultInitial(One)
94*bd06c417SValeriy Savchenko     Store StY1 =
95*bd06c417SValeriy Savchenko         SManager.BindDefaultInitial(StInit, LY1.getAsRegion(), One).getStore();
96*bd06c417SValeriy Savchenko     EXPECT_EQ(One, SManager.getBinding(StY1, LY1, ASTCtxt.IntTy));
97*bd06c417SValeriy Savchenko     EXPECT_EQ(One, *SManager.getDefaultBinding(StY1, LY1.getAsRegion()));
98*bd06c417SValeriy Savchenko   }
99*bd06c417SValeriy Savchenko 
100*bd06c417SValeriy Savchenko public:
101*bd06c417SValeriy Savchenko   using StoreTestConsumer::StoreTestConsumer;
102*bd06c417SValeriy Savchenko };
103*bd06c417SValeriy Savchenko 
TEST(Store,VariableBind)1049b02a9b4SArtem Dergachev TEST(Store, VariableBind) {
105*bd06c417SValeriy Savchenko   EXPECT_TRUE(tooling::runToolOnCode(
106*bd06c417SValeriy Savchenko       std::make_unique<TestAction<VariableBindConsumer>>(),
107b22804b3SDmitri Gribenko       "void foo() { int x0, y0, z0, x1, y1; }"));
1089b02a9b4SArtem Dergachev }
1099b02a9b4SArtem Dergachev 
110*bd06c417SValeriy Savchenko class LiteralCompoundConsumer : public StoreTestConsumer {
performTest(const Decl * D)111*bd06c417SValeriy Savchenko   void performTest(const Decl *D) override {
112*bd06c417SValeriy Savchenko     StoreManager &SManager = Eng.getStoreManager();
113*bd06c417SValeriy Savchenko     SValBuilder &Builder = Eng.getSValBuilder();
114*bd06c417SValeriy Savchenko     MemRegionManager &MRManager = SManager.getRegionManager();
115*bd06c417SValeriy Savchenko     ASTContext &ASTCtxt = Eng.getContext();
116*bd06c417SValeriy Savchenko 
117*bd06c417SValeriy Savchenko     using namespace ast_matchers;
118*bd06c417SValeriy Savchenko 
119*bd06c417SValeriy Savchenko     const auto *CL = findNode<CompoundLiteralExpr>(D, compoundLiteralExpr());
120*bd06c417SValeriy Savchenko 
121*bd06c417SValeriy Savchenko     const StackFrameContext *SFC =
122*bd06c417SValeriy Savchenko         Eng.getAnalysisDeclContextManager().getStackFrame(D);
123*bd06c417SValeriy Savchenko 
124*bd06c417SValeriy Savchenko     QualType Int = ASTCtxt.IntTy;
125*bd06c417SValeriy Savchenko 
126*bd06c417SValeriy Savchenko     // Get region for 'test'
127*bd06c417SValeriy Savchenko     const SubRegion *CLRegion = MRManager.getCompoundLiteralRegion(CL, SFC);
128*bd06c417SValeriy Savchenko 
129*bd06c417SValeriy Savchenko     // Get value for 'test[0]'
130*bd06c417SValeriy Savchenko     NonLoc Zero = Builder.makeIntVal(0, false);
131*bd06c417SValeriy Savchenko     loc::MemRegionVal ZeroElement(
132*bd06c417SValeriy Savchenko         MRManager.getElementRegion(ASTCtxt.IntTy, Zero, CLRegion, ASTCtxt));
133*bd06c417SValeriy Savchenko 
134*bd06c417SValeriy Savchenko     Store StInit = SManager.getInitialStore(SFC).getStore();
135*bd06c417SValeriy Savchenko     // Let's bind constant 1 to 'test[0]'
136*bd06c417SValeriy Savchenko     SVal One = Builder.makeIntVal(1, Int);
137*bd06c417SValeriy Savchenko     Store StX = SManager.Bind(StInit, ZeroElement, One).getStore();
138*bd06c417SValeriy Savchenko 
139*bd06c417SValeriy Savchenko     // And make sure that we can read this binding back as it was
140*bd06c417SValeriy Savchenko     EXPECT_EQ(One, SManager.getBinding(StX, ZeroElement, Int));
141*bd06c417SValeriy Savchenko   }
142*bd06c417SValeriy Savchenko 
143*bd06c417SValeriy Savchenko public:
144*bd06c417SValeriy Savchenko   using StoreTestConsumer::StoreTestConsumer;
145*bd06c417SValeriy Savchenko };
146*bd06c417SValeriy Savchenko 
TEST(Store,LiteralCompound)147*bd06c417SValeriy Savchenko TEST(Store, LiteralCompound) {
148*bd06c417SValeriy Savchenko   EXPECT_TRUE(tooling::runToolOnCode(
149*bd06c417SValeriy Savchenko       std::make_unique<TestAction<LiteralCompoundConsumer>>(),
150*bd06c417SValeriy Savchenko       "void foo() { int *test = (int[]){ 1, 2, 3 }; }", "input.c"));
151*bd06c417SValeriy Savchenko }
152*bd06c417SValeriy Savchenko 
1539b02a9b4SArtem Dergachev } // namespace
1549b02a9b4SArtem Dergachev } // namespace ento
1559b02a9b4SArtem Dergachev } // namespace clang
156