[clang] 64ba462 - [clang][dataflow] Add a transfer function for InitListExpr
Stanislav Gatev via cfe-commits
cfe-commits at lists.llvm.org
Tue Jan 25 08:30:24 PST 2022
Author: Stanislav Gatev
Date: 2022-01-25T16:28:15Z
New Revision: 64ba462b6e398bdb33464963f7d6274320f84370
URL: https://github.com/llvm/llvm-project/commit/64ba462b6e398bdb33464963f7d6274320f84370
DIFF: https://github.com/llvm/llvm-project/commit/64ba462b6e398bdb33464963f7d6274320f84370.diff
LOG: [clang][dataflow] Add a transfer function for InitListExpr
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/D118119
Added:
Modified:
clang/include/clang/Analysis/FlowSensitive/Value.h
clang/lib/Analysis/FlowSensitive/Transfer.cpp
clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Analysis/FlowSensitive/Value.h b/clang/include/clang/Analysis/FlowSensitive/Value.h
index d1de2b64fd95a..47e4d31c832bb 100644
--- a/clang/include/clang/Analysis/FlowSensitive/Value.h
+++ b/clang/include/clang/Analysis/FlowSensitive/Value.h
@@ -100,15 +100,18 @@ class StructValue final : public Value {
return Val->getKind() == Kind::Struct;
}
- /// Returns the child value for `D`.
+ /// Returns the child value that is assigned for `D`.
Value &getChild(const ValueDecl &D) const {
auto It = Children.find(&D);
assert(It != Children.end());
return *It->second;
}
+ /// Assigns `Val` as the child value for `D`.
+ void setChild(const ValueDecl &D, Value &Val) { Children[&D] = &Val; }
+
private:
- const llvm::DenseMap<const ValueDecl *, Value *> Children;
+ llvm::DenseMap<const ValueDecl *, Value *> Children;
};
} // namespace dataflow
diff --git a/clang/lib/Analysis/FlowSensitive/Transfer.cpp b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
index 32a05333923f5..7c5e063278d78 100644
--- a/clang/lib/Analysis/FlowSensitive/Transfer.cpp
+++ b/clang/lib/Analysis/FlowSensitive/Transfer.cpp
@@ -22,9 +22,11 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Analysis/FlowSensitive/DataflowEnvironment.h"
#include "clang/Basic/OperatorKinds.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
#include <cassert>
#include <memory>
+#include <tuple>
namespace clang {
namespace dataflow {
@@ -414,6 +416,33 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
Env.setValue(Loc, *Val);
}
+ void VisitInitListExpr(const InitListExpr *S) {
+ QualType Type = S->getType();
+
+ auto &Loc = Env.createStorageLocation(*S);
+ Env.setStorageLocation(*S, Loc);
+
+ auto *Val = Env.createValue(Type);
+ if (Val == nullptr)
+ return;
+
+ Env.setValue(Loc, *Val);
+
+ if (Type->isStructureOrClassType()) {
+ for (auto IT : llvm::zip(Type->getAsRecordDecl()->fields(), S->inits())) {
+ const FieldDecl *Field = std::get<0>(IT);
+ assert(Field != nullptr);
+
+ const Expr *Init = std::get<1>(IT);
+ assert(Init != nullptr);
+
+ if (Value *InitVal = Env.getValue(*Init, SkipPast::None))
+ cast<StructValue>(Val)->setChild(*Field, *InitVal);
+ }
+ }
+ // FIXME: Implement array initialization.
+ }
+
// FIXME: Add support for:
// - CXXBoolLiteralExpr
diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
index c1eaf281ddc49..cd3e58207680a 100644
--- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
+++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp
@@ -1865,4 +1865,91 @@ TEST_F(TransferTest, VarDeclInDoWhile) {
});
}
+TEST_F(TransferTest, AggregateInitialization) {
+ std::string BracesCode = R"(
+ struct A {
+ int Foo;
+ };
+
+ struct B {
+ int Bar;
+ A Baz;
+ int Qux;
+ };
+
+ void target(int BarArg, int FooArg, int QuxArg) {
+ B Quux{BarArg, {FooArg}, QuxArg};
+ /*[[p]]*/
+ }
+ )";
+ std::string BraceEllisionCode = R"(
+ struct A {
+ int Foo;
+ };
+
+ struct B {
+ int Bar;
+ A Baz;
+ int Qux;
+ };
+
+ void target(int BarArg, int FooArg, int QuxArg) {
+ B Quux = {BarArg, FooArg, QuxArg};
+ /*[[p]]*/
+ }
+ )";
+ for (const std::string &Code : {BracesCode, BraceEllisionCode}) {
+ 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 ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz");
+ ASSERT_THAT(BazDecl, NotNull());
+
+ const ValueDecl *QuxDecl = findValueDecl(ASTCtx, "Qux");
+ ASSERT_THAT(QuxDecl, NotNull());
+
+ const ValueDecl *FooArgDecl = findValueDecl(ASTCtx, "FooArg");
+ ASSERT_THAT(FooArgDecl, NotNull());
+
+ const ValueDecl *BarArgDecl = findValueDecl(ASTCtx, "BarArg");
+ ASSERT_THAT(BarArgDecl, NotNull());
+
+ const ValueDecl *QuxArgDecl = findValueDecl(ASTCtx, "QuxArg");
+ ASSERT_THAT(QuxArgDecl, NotNull());
+
+ const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux");
+ ASSERT_THAT(QuuxDecl, NotNull());
+
+ const auto *FooArgVal =
+ cast<IntegerValue>(Env.getValue(*FooArgDecl, SkipPast::None));
+ const auto *BarArgVal =
+ cast<IntegerValue>(Env.getValue(*BarArgDecl, SkipPast::None));
+ const auto *QuxArgVal =
+ cast<IntegerValue>(Env.getValue(*QuxArgDecl, SkipPast::None));
+
+ const auto *QuuxVal =
+ cast<StructValue>(Env.getValue(*QuuxDecl, SkipPast::None));
+ ASSERT_THAT(QuuxVal, NotNull());
+
+ const auto *BazVal = cast<StructValue>(&QuuxVal->getChild(*BazDecl));
+ ASSERT_THAT(BazVal, NotNull());
+
+ EXPECT_EQ(&QuuxVal->getChild(*BarDecl), BarArgVal);
+ EXPECT_EQ(&BazVal->getChild(*FooDecl), FooArgVal);
+ EXPECT_EQ(&QuuxVal->getChild(*QuxDecl), QuxArgVal);
+ });
+ }
+}
+
} // namespace
More information about the cfe-commits
mailing list