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