106 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			106 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- unittests/StaticAnalyzer/StoreTest.cpp -----------------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "Reusables.h"
 | |
| 
 | |
| #include "clang/Tooling/Tooling.h"
 | |
| #include "gtest/gtest.h"
 | |
| 
 | |
| namespace clang {
 | |
| namespace ento {
 | |
| namespace {
 | |
| 
 | |
| // 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();
 | |
| 
 | |
|     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);
 | |
| 
 | |
|     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));
 | |
| 
 | |
|     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);
 | |
| 
 | |
|     // Bind(Zero)
 | |
|     Store StX0 =
 | |
|         StMgr.Bind(StInit, LX0, Zero).getStore();
 | |
|     ASSERT_EQ(Zero, StMgr.getBinding(StX0, LX0, ACtx.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()));
 | |
| 
 | |
|     // BindDefaultZero()
 | |
|     Store StZ0 =
 | |
|         StMgr.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()));
 | |
| 
 | |
|     // Bind(One)
 | |
|     Store StX1 =
 | |
|         StMgr.Bind(StInit, LX1, One).getStore();
 | |
|     ASSERT_EQ(One, StMgr.getBinding(StX1, LX1, ACtx.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()));
 | |
|   }
 | |
| 
 | |
| public:
 | |
|   VariableBindConsumer(CompilerInstance &C) : ExprEngineConsumer(C) {}
 | |
| 
 | |
|   bool HandleTopLevelDecl(DeclGroupRef DG) override {
 | |
|     for (const auto *D : DG)
 | |
|       performTest(D);
 | |
|     return true;
 | |
|   }
 | |
| };
 | |
| 
 | |
| class VariableBindAction : public ASTFrontendAction {
 | |
| public:
 | |
|   std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &Compiler,
 | |
|                                                  StringRef File) override {
 | |
|     return std::make_unique<VariableBindConsumer>(Compiler);
 | |
|   }
 | |
| };
 | |
| 
 | |
| TEST(Store, VariableBind) {
 | |
|   EXPECT_TRUE(tooling::runToolOnCode(std::make_unique<VariableBindAction>(),
 | |
|                                      "void foo() { int x0, y0, z0, x1, y1; }"));
 | |
| }
 | |
| 
 | |
| } // namespace
 | |
| } // namespace ento
 | |
| } // namespace clang
 |