reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
//===- 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