1 //===- unittests/StaticAnalyzer/StoreTest.cpp -----------------------------===//
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
7 //===----------------------------------------------------------------------===//
11 #include "clang/Tooling/Tooling.h"
12 #include "gtest/gtest.h"
18 class StoreTestConsumer
: public ExprEngineConsumer
{
20 StoreTestConsumer(CompilerInstance
&C
) : ExprEngineConsumer(C
) {}
22 bool HandleTopLevelDecl(DeclGroupRef DG
) override
{
23 for (const auto *D
: DG
)
29 virtual void performTest(const Decl
*D
) = 0;
32 template <class ConsumerTy
> class TestAction
: public ASTFrontendAction
{
34 std::unique_ptr
<ASTConsumer
> CreateASTConsumer(CompilerInstance
&Compiler
,
35 StringRef File
) override
{
36 return std::make_unique
<ConsumerTy
>(Compiler
);
40 // Test that we can put a value into an int-type variable and load it
41 // back from that variable. Test what happens if default bindings are used.
42 class VariableBindConsumer
: public StoreTestConsumer
{
43 void performTest(const Decl
*D
) override
{
44 StoreManager
&SManager
= Eng
.getStoreManager();
45 SValBuilder
&Builder
= Eng
.getSValBuilder();
46 MemRegionManager
&MRManager
= SManager
.getRegionManager();
47 const ASTContext
&ASTCtxt
= Eng
.getContext();
49 const auto *VDX0
= findDeclByName
<VarDecl
>(D
, "x0");
50 const auto *VDY0
= findDeclByName
<VarDecl
>(D
, "y0");
51 const auto *VDZ0
= findDeclByName
<VarDecl
>(D
, "z0");
52 const auto *VDX1
= findDeclByName
<VarDecl
>(D
, "x1");
53 const auto *VDY1
= findDeclByName
<VarDecl
>(D
, "y1");
55 ASSERT_TRUE(VDX0
&& VDY0
&& VDZ0
&& VDX1
&& VDY1
);
57 const StackFrameContext
*SFC
=
58 Eng
.getAnalysisDeclContextManager().getStackFrame(D
);
60 Loc LX0
= loc::MemRegionVal(MRManager
.getVarRegion(VDX0
, SFC
));
61 Loc LY0
= loc::MemRegionVal(MRManager
.getVarRegion(VDY0
, SFC
));
62 Loc LZ0
= loc::MemRegionVal(MRManager
.getVarRegion(VDZ0
, SFC
));
63 Loc LX1
= loc::MemRegionVal(MRManager
.getVarRegion(VDX1
, SFC
));
64 Loc LY1
= loc::MemRegionVal(MRManager
.getVarRegion(VDY1
, SFC
));
66 Store StInit
= SManager
.getInitialStore(SFC
).getStore();
67 SVal Zero
= Builder
.makeZeroVal(ASTCtxt
.IntTy
);
68 SVal One
= Builder
.makeIntVal(1, ASTCtxt
.IntTy
);
69 SVal NarrowZero
= Builder
.makeZeroVal(ASTCtxt
.CharTy
);
72 Store StX0
= SManager
.Bind(StInit
, LX0
, Zero
).getStore();
73 EXPECT_EQ(Zero
, SManager
.getBinding(StX0
, LX0
, ASTCtxt
.IntTy
));
75 // BindDefaultInitial(Zero)
77 SManager
.BindDefaultInitial(StInit
, LY0
.getAsRegion(), Zero
).getStore();
78 EXPECT_EQ(Zero
, SManager
.getBinding(StY0
, LY0
, ASTCtxt
.IntTy
));
79 EXPECT_EQ(Zero
, *SManager
.getDefaultBinding(StY0
, LY0
.getAsRegion()));
82 Store StZ0
= SManager
.BindDefaultZero(StInit
, LZ0
.getAsRegion()).getStore();
83 // BindDefaultZero wipes the region with '0 S8b', not with out Zero.
84 // Direct load, however, does give us back the object of the type
85 // that we specify for loading.
86 EXPECT_EQ(Zero
, SManager
.getBinding(StZ0
, LZ0
, ASTCtxt
.IntTy
));
87 EXPECT_EQ(NarrowZero
, *SManager
.getDefaultBinding(StZ0
, LZ0
.getAsRegion()));
90 Store StX1
= SManager
.Bind(StInit
, LX1
, One
).getStore();
91 EXPECT_EQ(One
, SManager
.getBinding(StX1
, LX1
, ASTCtxt
.IntTy
));
93 // BindDefaultInitial(One)
95 SManager
.BindDefaultInitial(StInit
, LY1
.getAsRegion(), One
).getStore();
96 EXPECT_EQ(One
, SManager
.getBinding(StY1
, LY1
, ASTCtxt
.IntTy
));
97 EXPECT_EQ(One
, *SManager
.getDefaultBinding(StY1
, LY1
.getAsRegion()));
101 using StoreTestConsumer::StoreTestConsumer
;
104 TEST(Store
, VariableBind
) {
105 EXPECT_TRUE(tooling::runToolOnCode(
106 std::make_unique
<TestAction
<VariableBindConsumer
>>(),
107 "void foo() { int x0, y0, z0, x1, y1; }"));
110 class LiteralCompoundConsumer
: public StoreTestConsumer
{
111 void performTest(const Decl
*D
) override
{
112 StoreManager
&SManager
= Eng
.getStoreManager();
113 SValBuilder
&Builder
= Eng
.getSValBuilder();
114 MemRegionManager
&MRManager
= SManager
.getRegionManager();
115 ASTContext
&ASTCtxt
= Eng
.getContext();
117 using namespace ast_matchers
;
119 const auto *CL
= findNode
<CompoundLiteralExpr
>(D
, compoundLiteralExpr());
121 const StackFrameContext
*SFC
=
122 Eng
.getAnalysisDeclContextManager().getStackFrame(D
);
124 QualType Int
= ASTCtxt
.IntTy
;
126 // Get region for 'test'
127 const SubRegion
*CLRegion
= MRManager
.getCompoundLiteralRegion(CL
, SFC
);
129 // Get value for 'test[0]'
130 NonLoc Zero
= Builder
.makeIntVal(0, false);
131 loc::MemRegionVal
ZeroElement(
132 MRManager
.getElementRegion(ASTCtxt
.IntTy
, Zero
, CLRegion
, ASTCtxt
));
134 Store StInit
= SManager
.getInitialStore(SFC
).getStore();
135 // Let's bind constant 1 to 'test[0]'
136 SVal One
= Builder
.makeIntVal(1, Int
);
137 Store StX
= SManager
.Bind(StInit
, ZeroElement
, One
).getStore();
139 // And make sure that we can read this binding back as it was
140 EXPECT_EQ(One
, SManager
.getBinding(StX
, ZeroElement
, Int
));
144 using StoreTestConsumer::StoreTestConsumer
;
147 TEST(Store
, LiteralCompound
) {
148 EXPECT_TRUE(tooling::runToolOnCode(
149 std::make_unique
<TestAction
<LiteralCompoundConsumer
>>(),
150 "void foo() { int *test = (int[]){ 1, 2, 3 }; }", "input.c"));