[clang][dataflow] Add transfer function for addrof

This is part of the implementation of the dataflow analysis framework.
See "[RFC] A dataflow analysis framework for Clang AST" on cfe-dev.

Reviewed-by: xazax.hun

Differential Revision: https://reviews.llvm.org/D117496
This commit is contained in:
Stanislav Gatev 2022-01-17 16:23:24 +00:00
parent 541322540e
commit 59e031ff90
2 changed files with 90 additions and 5 deletions

View File

@ -174,19 +174,45 @@ public:
}
void VisitUnaryOperator(const UnaryOperator *S) {
if (S->getOpcode() == UO_Deref) {
assert(S->getSubExpr() != nullptr);
// The CFG does not contain `ParenExpr` as top-level statements in basic
// blocks, however sub-expressions can still be of that type.
assert(S->getSubExpr() != nullptr);
const Expr *SubExpr = S->getSubExpr()->IgnoreParens();
assert(SubExpr != nullptr);
switch (S->getOpcode()) {
case UO_Deref: {
const auto *SubExprVal = cast_or_null<PointerValue>(
Env.getValue(*S->getSubExpr(), SkipPast::Reference));
Env.getValue(*SubExpr, SkipPast::Reference));
if (SubExprVal == nullptr)
return;
break;
auto &Loc = Env.createStorageLocation(*S);
Env.setStorageLocation(*S, Loc);
Env.setValue(Loc, Env.takeOwnership(std::make_unique<ReferenceValue>(
SubExprVal->getPointeeLoc())));
break;
}
case UO_AddrOf: {
// Do not form a pointer to a reference. If `SubExpr` is assigned a
// `ReferenceValue` then form a value that points to the location of its
// pointee.
StorageLocation *PointeeLoc =
Env.getStorageLocation(*SubExpr, SkipPast::Reference);
if (PointeeLoc == nullptr)
break;
auto &PointerLoc = Env.createStorageLocation(*S);
auto &PointerVal =
Env.takeOwnership(std::make_unique<PointerValue>(*PointeeLoc));
Env.setStorageLocation(*S, PointerLoc);
Env.setValue(PointerLoc, PointerVal);
break;
}
default:
// FIXME: Add support for UO_LNot.
break;
}
// FIXME: Add support for UO_AddrOf, UO_LNot.
}
void VisitCXXThisExpr(const CXXThisExpr *S) {

View File

@ -1699,4 +1699,63 @@ TEST_F(TransferTest, StaticCast) {
});
}
TEST_F(TransferTest, AddrOfValue) {
std::string Code = R"(
void target() {
int Foo;
int *Bar = &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 ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
ASSERT_THAT(BarDecl, NotNull());
const auto *FooLoc = cast<ScalarStorageLocation>(
Env.getStorageLocation(*FooDecl, SkipPast::None));
const auto *BarVal =
cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
EXPECT_EQ(&BarVal->getPointeeLoc(), FooLoc);
});
}
TEST_F(TransferTest, AddrOfReference) {
std::string Code = R"(
void target(int *Foo) {
int *Bar = &(*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 ValueDecl *BarDecl = findValueDecl(ASTCtx, "Bar");
ASSERT_THAT(BarDecl, NotNull());
const auto *FooVal =
cast<PointerValue>(Env.getValue(*FooDecl, SkipPast::None));
const auto *BarVal =
cast<PointerValue>(Env.getValue(*BarDecl, SkipPast::None));
EXPECT_EQ(&BarVal->getPointeeLoc(), &FooVal->getPointeeLoc());
});
}
} // namespace