#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/Support/ErrorHandling.h"
-#include <cassert>
#include <memory>
#include <utility>
return Model.compareEquivalent(Type, *Val1, *Val2);
}
-/// Initializes a global storage value.
-static void initGlobalVar(const VarDecl &D, Environment &Env) {
- if (!D.hasGlobalStorage() ||
- Env.getStorageLocation(D, SkipPast::None) != nullptr)
- return;
-
- auto &Loc = Env.createStorageLocation(D);
- Env.setStorageLocation(D, Loc);
- if (auto *Val = Env.createValue(D.getType()))
- Env.setValue(Loc, *Val);
-}
-
-/// Initializes a global storage value.
-static void initGlobalVar(const Decl &D, Environment &Env) {
- if (auto *V = dyn_cast<VarDecl>(&D))
- initGlobalVar(*V, Env);
-}
-
-/// Initializes global storage values that are declared or referenced from
-/// sub-statements of `S`.
-// FIXME: Add support for resetting globals after function calls to enable
-// the implementation of sound analyses.
-static void initGlobalVars(const Stmt &S, Environment &Env) {
- for (auto *Child : S.children()) {
- if (Child != nullptr)
- initGlobalVars(*Child, Env);
- }
-
- if (auto *DS = dyn_cast<DeclStmt>(&S)) {
- if (DS->isSingleDecl()) {
- const auto &D = *cast<VarDecl>(DS->getSingleDecl());
- initGlobalVar(D, Env);
- } else {
- for (auto *D : DS->getDeclGroup())
- initGlobalVar(*D, Env);
- }
- } else if (auto *E = dyn_cast<DeclRefExpr>(&S)) {
- initGlobalVar(*E->getDecl(), Env);
- } else if (auto *E = dyn_cast<MemberExpr>(&S)) {
- initGlobalVar(*E->getMemberDecl(), Env);
- }
-}
-
Environment::Environment(DataflowAnalysisContext &DACtx,
const DeclContext &DeclCtx)
: Environment(DACtx) {
if (const auto *FuncDecl = dyn_cast<FunctionDecl>(&DeclCtx)) {
- assert(FuncDecl->getBody() != nullptr);
- initGlobalVars(*FuncDecl->getBody(), *this);
for (const auto *ParamDecl : FuncDecl->parameters()) {
assert(ParamDecl != nullptr);
auto &ParamLoc = createStorageLocation(*ParamDecl);
// Group decls are converted into single decls in the CFG so the cast below
// is safe.
const auto &D = *cast<VarDecl>(S->getSingleDecl());
-
- // Static local vars are already initialized in `Environment`.
- if (D.hasGlobalStorage())
- return;
-
auto &Loc = Env.createStorageLocation(D);
Env.setStorageLocation(D, Loc);
if (Member->isFunctionOrFunctionTemplate())
return;
- if (auto *D = dyn_cast<VarDecl>(Member)) {
- if (D->hasGlobalStorage()) {
- auto *VarDeclLoc = Env.getStorageLocation(*D, SkipPast::None);
- if (VarDeclLoc == nullptr)
- return;
-
- if (VarDeclLoc->getType()->isReferenceType()) {
- Env.setStorageLocation(*S, *VarDeclLoc);
- } else {
- auto &Loc = Env.createStorageLocation(*S);
- Env.setStorageLocation(*S, Loc);
- Env.setValue(Loc, Env.takeOwnership(
- std::make_unique<ReferenceValue>(*VarDeclLoc)));
- }
- return;
- }
- }
-
// The receiver can be either a value or a pointer to a value. Skip past the
// indirection to handle both cases.
auto *BaseLoc = cast_or_null<AggregateStorageLocation>(
});
}
-TEST_F(TransferTest, StaticIntSingleVarDecl) {
- std::string Code = R"(
- void target() {
- static int Foo;
- // [[p]]
- }
- )";
- runDataflow(Code,
- [](llvm::ArrayRef<
- std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
- Results,
- ASTContext &ASTCtx) {
- ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
- const Environment &Env = Results[0].second.Env;
-
- const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
- ASSERT_THAT(FooDecl, NotNull());
-
- const StorageLocation *FooLoc =
- Env.getStorageLocation(*FooDecl, SkipPast::None);
- ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
-
- const Value *FooVal = Env.getValue(*FooLoc);
- EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
- });
-}
-
-TEST_F(TransferTest, StaticIntGroupVarDecl) {
- std::string Code = R"(
- void target() {
- static int Foo, Bar;
- (void)0;
- // [[p]]
- }
- )";
- runDataflow(Code,
- [](llvm::ArrayRef<
- std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
- Results,
- ASTContext &ASTCtx) {
- ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
- const Environment &Env = Results[0].second.Env;
-
- const ValueDecl *FooDecl = findValueDecl(ASTCtx, "Foo");
- ASSERT_THAT(FooDecl, NotNull());
-
- const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
- ASSERT_THAT(BarDecl, NotNull());
-
- const StorageLocation *FooLoc =
- Env.getStorageLocation(*FooDecl, SkipPast::None);
- ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(FooLoc));
-
- const StorageLocation *BarLoc =
- Env.getStorageLocation(*BarDecl, SkipPast::None);
- ASSERT_TRUE(isa_and_nonnull<ScalarStorageLocation>(BarLoc));
-
- const Value *FooVal = Env.getValue(*FooLoc);
- EXPECT_TRUE(isa_and_nonnull<IntegerValue>(FooVal));
-
- const Value *BarVal = Env.getValue(*BarLoc);
- EXPECT_TRUE(isa_and_nonnull<IntegerValue>(BarVal));
-
- EXPECT_NE(FooVal, BarVal);
- });
-}
-
-TEST_F(TransferTest, GlobalIntVarDecl) {
- std::string Code = R"(
- static int Foo;
-
- void target() {
- int Bar = Foo;
- int Baz = Foo;
- // [[p]]
- }
- )";
- runDataflow(Code,
- [](llvm::ArrayRef<
- std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
- Results,
- ASTContext &ASTCtx) {
- ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
- const Environment &Env = Results[0].second.Env;
-
- const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
- ASSERT_THAT(BarDecl, NotNull());
-
- const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
- ASSERT_THAT(BazDecl, NotNull());
-
- const Value *BarVal =
- cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
- const Value *BazVal =
- cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None));
- EXPECT_EQ(BarVal, BazVal);
- });
-}
-
-TEST_F(TransferTest, StaticMemberIntVarDecl) {
- std::string Code = R"(
- struct A {
- static int Foo;
- };
-
- void target(A a) {
- int Bar = a.Foo;
- int Baz = a.Foo;
- // [[p]]
- }
- )";
- runDataflow(Code,
- [](llvm::ArrayRef<
- std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
- Results,
- ASTContext &ASTCtx) {
- ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
- const Environment &Env = Results[0].second.Env;
-
- const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
- ASSERT_THAT(BarDecl, NotNull());
-
- const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
- ASSERT_THAT(BazDecl, NotNull());
-
- const Value *BarVal =
- cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
- const Value *BazVal =
- cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None));
- EXPECT_EQ(BarVal, BazVal);
- });
-}
-
-TEST_F(TransferTest, StaticMemberRefVarDecl) {
- std::string Code = R"(
- struct A {
- static int &Foo;
- };
-
- void target(A a) {
- int Bar = a.Foo;
- int Baz = a.Foo;
- // [[p]]
- }
- )";
- runDataflow(Code,
- [](llvm::ArrayRef<
- std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
- Results,
- ASTContext &ASTCtx) {
- ASSERT_THAT(Results, ElementsAre(Pair("p", _)));
- const Environment &Env = Results[0].second.Env;
-
- const ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
- ASSERT_THAT(BarDecl, NotNull());
-
- const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
- ASSERT_THAT(BazDecl, NotNull());
-
- const Value *BarVal =
- cast<IntegerValue>(Env.getValue(*BarDecl, SkipPast::None));
- const Value *BazVal =
- cast<IntegerValue>(Env.getValue(*BazDecl, SkipPast::None));
- EXPECT_EQ(BarVal, BazVal);
- });
-}
-
} // namespace