namespace ento {
namespace {
+class StoreTestConsumer : public ExprEngineConsumer {
+public:
+ StoreTestConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DG) override {
+ for (const auto *D : DG)
+ performTest(D);
+ return true;
+ }
+
+private:
+ virtual void performTest(const Decl *D) = 0;
+};
+
+template <class ConsumerTy> class TestAction : public ASTFrontendAction {
+public:
+ std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef File) override {
+ return std::make_unique<ConsumerTy>(Compiler);
+ }
+};
+
// Test that we can put a value into an int-type variable and load it
// back from that variable. Test what happens if default bindings are used.
-class VariableBindConsumer : public ExprEngineConsumer {
- void performTest(const Decl *D) {
- StoreManager &StMgr = Eng.getStoreManager();
- SValBuilder &SVB = Eng.getSValBuilder();
- MemRegionManager &MRMgr = StMgr.getRegionManager();
- const ASTContext &ACtx = Eng.getContext();
+class VariableBindConsumer : public StoreTestConsumer {
+ void performTest(const Decl *D) override {
+ StoreManager &SManager = Eng.getStoreManager();
+ SValBuilder &Builder = Eng.getSValBuilder();
+ MemRegionManager &MRManager = SManager.getRegionManager();
+ const ASTContext &ASTCtxt = Eng.getContext();
const auto *VDX0 = findDeclByName<VarDecl>(D, "x0");
const auto *VDY0 = findDeclByName<VarDecl>(D, "y0");
const auto *VDZ0 = findDeclByName<VarDecl>(D, "z0");
const auto *VDX1 = findDeclByName<VarDecl>(D, "x1");
const auto *VDY1 = findDeclByName<VarDecl>(D, "y1");
- assert(VDX0 && VDY0 && VDZ0 && VDX1 && VDY1);
+
+ ASSERT_TRUE(VDX0 && VDY0 && VDZ0 && VDX1 && VDY1);
const StackFrameContext *SFC =
Eng.getAnalysisDeclContextManager().getStackFrame(D);
- Loc LX0 = loc::MemRegionVal(MRMgr.getVarRegion(VDX0, SFC));
- Loc LY0 = loc::MemRegionVal(MRMgr.getVarRegion(VDY0, SFC));
- Loc LZ0 = loc::MemRegionVal(MRMgr.getVarRegion(VDZ0, SFC));
- Loc LX1 = loc::MemRegionVal(MRMgr.getVarRegion(VDX1, SFC));
- Loc LY1 = loc::MemRegionVal(MRMgr.getVarRegion(VDY1, SFC));
+ Loc LX0 = loc::MemRegionVal(MRManager.getVarRegion(VDX0, SFC));
+ Loc LY0 = loc::MemRegionVal(MRManager.getVarRegion(VDY0, SFC));
+ Loc LZ0 = loc::MemRegionVal(MRManager.getVarRegion(VDZ0, SFC));
+ Loc LX1 = loc::MemRegionVal(MRManager.getVarRegion(VDX1, SFC));
+ Loc LY1 = loc::MemRegionVal(MRManager.getVarRegion(VDY1, SFC));
- Store StInit = StMgr.getInitialStore(SFC).getStore();
- SVal Zero = SVB.makeZeroVal(ACtx.IntTy);
- SVal One = SVB.makeIntVal(1, ACtx.IntTy);
- SVal NarrowZero = SVB.makeZeroVal(ACtx.CharTy);
+ Store StInit = SManager.getInitialStore(SFC).getStore();
+ SVal Zero = Builder.makeZeroVal(ASTCtxt.IntTy);
+ SVal One = Builder.makeIntVal(1, ASTCtxt.IntTy);
+ SVal NarrowZero = Builder.makeZeroVal(ASTCtxt.CharTy);
// Bind(Zero)
- Store StX0 =
- StMgr.Bind(StInit, LX0, Zero).getStore();
- ASSERT_EQ(Zero, StMgr.getBinding(StX0, LX0, ACtx.IntTy));
+ Store StX0 = SManager.Bind(StInit, LX0, Zero).getStore();
+ EXPECT_EQ(Zero, SManager.getBinding(StX0, LX0, ASTCtxt.IntTy));
// BindDefaultInitial(Zero)
Store StY0 =
- StMgr.BindDefaultInitial(StInit, LY0.getAsRegion(), Zero).getStore();
- ASSERT_EQ(Zero, StMgr.getBinding(StY0, LY0, ACtx.IntTy));
- ASSERT_EQ(Zero, *StMgr.getDefaultBinding(StY0, LY0.getAsRegion()));
+ SManager.BindDefaultInitial(StInit, LY0.getAsRegion(), Zero).getStore();
+ EXPECT_EQ(Zero, SManager.getBinding(StY0, LY0, ASTCtxt.IntTy));
+ EXPECT_EQ(Zero, *SManager.getDefaultBinding(StY0, LY0.getAsRegion()));
// BindDefaultZero()
- Store StZ0 =
- StMgr.BindDefaultZero(StInit, LZ0.getAsRegion()).getStore();
+ Store StZ0 = SManager.BindDefaultZero(StInit, LZ0.getAsRegion()).getStore();
// BindDefaultZero wipes the region with '0 S8b', not with out Zero.
// Direct load, however, does give us back the object of the type
// that we specify for loading.
- ASSERT_EQ(Zero, StMgr.getBinding(StZ0, LZ0, ACtx.IntTy));
- ASSERT_EQ(NarrowZero, *StMgr.getDefaultBinding(StZ0, LZ0.getAsRegion()));
+ EXPECT_EQ(Zero, SManager.getBinding(StZ0, LZ0, ASTCtxt.IntTy));
+ EXPECT_EQ(NarrowZero, *SManager.getDefaultBinding(StZ0, LZ0.getAsRegion()));
// Bind(One)
- Store StX1 =
- StMgr.Bind(StInit, LX1, One).getStore();
- ASSERT_EQ(One, StMgr.getBinding(StX1, LX1, ACtx.IntTy));
+ Store StX1 = SManager.Bind(StInit, LX1, One).getStore();
+ EXPECT_EQ(One, SManager.getBinding(StX1, LX1, ASTCtxt.IntTy));
// BindDefaultInitial(One)
Store StY1 =
- StMgr.BindDefaultInitial(StInit, LY1.getAsRegion(), One).getStore();
- ASSERT_EQ(One, StMgr.getBinding(StY1, LY1, ACtx.IntTy));
- ASSERT_EQ(One, *StMgr.getDefaultBinding(StY1, LY1.getAsRegion()));
+ SManager.BindDefaultInitial(StInit, LY1.getAsRegion(), One).getStore();
+ EXPECT_EQ(One, SManager.getBinding(StY1, LY1, ASTCtxt.IntTy));
+ EXPECT_EQ(One, *SManager.getDefaultBinding(StY1, LY1.getAsRegion()));
}
public:
- VariableBindConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
+ using StoreTestConsumer::StoreTestConsumer;
+};
- bool HandleTopLevelDecl(DeclGroupRef DG) override {
- for (const auto *D : DG)
- performTest(D);
- return true;
+TEST(Store, VariableBind) {
+ EXPECT_TRUE(tooling::runToolOnCode(
+ std::make_unique<TestAction<VariableBindConsumer>>(),
+ "void foo() { int x0, y0, z0, x1, y1; }"));
+}
+
+class LiteralCompoundConsumer : public StoreTestConsumer {
+ void performTest(const Decl *D) override {
+ StoreManager &SManager = Eng.getStoreManager();
+ SValBuilder &Builder = Eng.getSValBuilder();
+ MemRegionManager &MRManager = SManager.getRegionManager();
+ ASTContext &ASTCtxt = Eng.getContext();
+
+ using namespace ast_matchers;
+
+ const auto *CL = findNode<CompoundLiteralExpr>(D, compoundLiteralExpr());
+
+ const StackFrameContext *SFC =
+ Eng.getAnalysisDeclContextManager().getStackFrame(D);
+
+ QualType Int = ASTCtxt.IntTy;
+
+ // Get region for 'test'
+ const SubRegion *CLRegion = MRManager.getCompoundLiteralRegion(CL, SFC);
+
+ // Get value for 'test[0]'
+ NonLoc Zero = Builder.makeIntVal(0, false);
+ loc::MemRegionVal ZeroElement(
+ MRManager.getElementRegion(ASTCtxt.IntTy, Zero, CLRegion, ASTCtxt));
+
+ Store StInit = SManager.getInitialStore(SFC).getStore();
+ // Let's bind constant 1 to 'test[0]'
+ SVal One = Builder.makeIntVal(1, Int);
+ Store StX = SManager.Bind(StInit, ZeroElement, One).getStore();
+
+ // And make sure that we can read this binding back as it was
+ EXPECT_EQ(One, SManager.getBinding(StX, ZeroElement, Int));
}
-};
-class VariableBindAction : public ASTFrontendAction {
public:
- std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
- StringRef File) override {
- return std::make_unique<VariableBindConsumer>(Compiler);
- }
+ using StoreTestConsumer::StoreTestConsumer;
};
-TEST(Store, VariableBind) {
- EXPECT_TRUE(tooling::runToolOnCode(std::make_unique<VariableBindAction>(),
- "void foo() { int x0, y0, z0, x1, y1; }"));
+TEST(Store, LiteralCompound) {
+ EXPECT_TRUE(tooling::runToolOnCode(
+ std::make_unique<TestAction<LiteralCompoundConsumer>>(),
+ "void foo() { int *test = (int[]){ 1, 2, 3 }; }", "input.c"));
}
} // namespace