-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang][dataflow] Eliminate RecordValue::getChild()
.
#65586
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[clang][dataflow] Eliminate RecordValue::getChild()
.
#65586
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Actual changes are tests only, LGTM (though I'm not a reviewer)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
We want to eliminate the `RecordStorageLocation` from `RecordValue` and, ultimately, eliminate `RecordValue` entirely (see the discussion linked in the `RecordValue` class comment). This is one step in that direction. To eliminate `RecordValue::getChild()`, we also eliminate the last remaining caller, namely the `getFieldValue(const RecordValue *, ...)` overload. Calls to this overload have been rewritten to use the `getFieldValue(const RecordStorageLocation *, ...)` overload. Note that this also makes the code slightly simpler in many cases.
cd8f6b6
to
2b2bedd
Compare
Rebasing so I can run the CI again at head (and it will hopefully pass). |
@llvm/pr-subscribers-clang-analysis ChangesWe want to eliminate the To eliminate -- 4 Files Affected:
diff --git a/clang/include/clang/Analysis/FlowSensitive/Value.h b/clang/include/clang/Analysis/FlowSensitive/Value.h index 6e911af7264ced9..e6c68e5b4e93e1e 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Value.h +++ b/clang/include/clang/Analysis/FlowSensitive/Value.h @@ -225,12 +225,6 @@ class RecordValue final : public Value { /// Returns the storage location that this `RecordValue` is associated with. RecordStorageLocation &getLoc() const { return Loc; } - /// Convenience function that returns the child storage location for `Field`. - /// See also the documentation for `RecordStorageLocation::getChild()`. - StorageLocation *getChild(const ValueDecl &Field) const { - return Loc.getChild(Field); - } - private: RecordStorageLocation &Loc; }; diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index 6e37011a052c5e4..ad40c0b082d302e 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -91,8 +91,8 @@ TEST_F(EnvironmentTest, CreateValueRecursiveType) { // Verify that the struct and the field (`R`) with first appearance of the // type is created successfully. Environment Env(DAContext, *Fun); - RecordValue *SVal = cast(Env.createValue(Ty)); - PointerValue *PV = cast_or_null(getFieldValue(SVal, *R, Env)); + auto &SLoc = cast(Env.createObject(Ty)); + PointerValue *PV = cast_or_null(getFieldValue(&SLoc, *R, Env)); EXPECT_THAT(PV, NotNull()); } @@ -240,8 +240,8 @@ TEST_F(EnvironmentTest, IncludeFieldsFromDefaultInitializers) { // Verify that the `X` field of `S` is populated when analyzing the // constructor, even though it is not referenced directly in the constructor. Environment Env(DAContext, *Constructor); - auto *Val = cast(Env.createValue(QTy)); - EXPECT_THAT(getFieldValue(Val, *XDecl, Env), NotNull()); + auto &Loc = cast(Env.createObject(QTy)); + EXPECT_THAT(getFieldValue(&Loc, *XDecl, Env), NotNull()); } TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) { @@ -285,8 +285,7 @@ TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) { Environment Env(DAContext, *Fun); const auto *GlobalLoc = cast(Env.getStorageLocation(*GlobalDecl)); - const auto *GlobalVal = cast(Env.getValue(*GlobalLoc)); - auto *BarVal = getFieldValue(GlobalVal, *BarDecl, Env); + auto *BarVal = getFieldValue(GlobalLoc, *BarDecl, Env); EXPECT_TRUE(isa(BarVal)); } diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h index c61e9f26beff40b..0cf66c218f43fdc 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h @@ -463,18 +463,6 @@ inline Value *getFieldValue(const RecordStorageLocation *Loc, return Env.getValue(*FieldLoc); } -/// Returns the value of a `Field` on a `Struct. -/// Returns null if `Struct` is null. -inline Value *getFieldValue(const RecordValue *Struct, const ValueDecl &Field, - const Environment &Env) { - if (Struct == nullptr) - return nullptr; - StorageLocation *FieldLoc = Struct->getChild(Field); - if (FieldLoc == nullptr) - return nullptr; - return Env.getValue(*FieldLoc); -} - /// Creates and owns constraints which are boolean values. class ConstraintContext { unsigned NextAtom = 0; diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index cced3925c4721c5..05ee5df0e95a433 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -647,26 +647,26 @@ TEST(TransferTest, SelfReferentialPointerVarDecl) { const auto &FooLoc = *cast(Env.getStorageLocation(*FooDecl)); const auto &FooVal = *cast(Env.getValue(FooLoc)); - const auto &FooPointeeVal = - *cast(Env.getValue(FooVal.getPointeeLoc())); + const auto &FooPointeeLoc = + cast(FooVal.getPointeeLoc()); const auto &BarVal = - *cast(getFieldValue(&FooPointeeVal, *BarDecl, Env)); - const auto &BarPointeeVal = - *cast(Env.getValue(BarVal.getPointeeLoc())); + *cast(getFieldValue(&FooPointeeLoc, *BarDecl, Env)); + const auto &BarPointeeLoc = + cast(BarVal.getPointeeLoc()); - EXPECT_THAT(getFieldValue(&BarPointeeVal, *FooRefDecl, Env), NotNull()); + EXPECT_THAT(getFieldValue(&BarPointeeLoc, *FooRefDecl, Env), NotNull()); const auto &FooPtrVal = *cast( - getFieldValue(&BarPointeeVal, *FooPtrDecl, Env)); + getFieldValue(&BarPointeeLoc, *FooPtrDecl, Env)); const auto &FooPtrPointeeLoc = cast(FooPtrVal.getPointeeLoc()); EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); - EXPECT_THAT(getFieldValue(&BarPointeeVal, *BazRefDecl, Env), NotNull()); + EXPECT_THAT(getFieldValue(&BarPointeeLoc, *BazRefDecl, Env), NotNull()); const auto &BazPtrVal = *cast( - getFieldValue(&BarPointeeVal, *BazPtrDecl, Env)); + getFieldValue(&BarPointeeLoc, *BazPtrDecl, Env)); const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc(); EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); }); @@ -2478,9 +2478,10 @@ TEST(TransferTest, BindTemporary) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - const auto &FooVal = *cast(Env.getValue(*FooDecl)); + const auto &FooLoc = + *cast(Env.getStorageLocation(*FooDecl)); const auto *BarVal = cast(Env.getValue(*BarDecl)); - EXPECT_EQ(BarVal, getFieldValue(&FooVal, *BazDecl, Env)); + EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env)); }); } @@ -2970,16 +2971,14 @@ TEST(TransferTest, AggregateInitialization) { const auto *BarArgVal = cast(Env.getValue(*BarArgDecl)); const auto *QuxArgVal = cast(Env.getValue(*QuxArgDecl)); - const auto *QuuxVal = cast(Env.getValue(*QuuxDecl)); - ASSERT_THAT(QuuxVal, NotNull()); - - const auto *BazVal = - cast(getFieldValue(QuuxVal, *BazDecl, Env)); - ASSERT_THAT(BazVal, NotNull()); + const auto &QuuxLoc = + *cast(Env.getStorageLocation(*QuuxDecl)); + const auto &BazLoc = + *cast(QuuxLoc.getChild(*BazDecl)); - EXPECT_EQ(getFieldValue(QuuxVal, *BarDecl, Env), BarArgVal); - EXPECT_EQ(getFieldValue(BazVal, *FooDecl, Env), FooArgVal); - EXPECT_EQ(getFieldValue(QuuxVal, *QuxDecl, Env), QuxArgVal); + EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal); + EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal); + EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal); // Check that fields initialized in an initializer list are always // modeled in other instances of the same type. @@ -3653,8 +3652,9 @@ TEST(TransferTest, AssignMemberBeforeCopy) { const auto *BarVal = cast(Env.getValue(*BarDecl)); - const auto *A2Val = cast(Env.getValue(*A2Decl)); - EXPECT_EQ(getFieldValue(A2Val, *FooDecl, Env), BarVal); + const auto &A2Loc = + *cast(Env.getStorageLocation(*A2Decl)); + EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal); }); } |
@llvm/pr-subscribers-clang ChangesWe want to eliminate the To eliminate -- 4 Files Affected:
diff --git a/clang/include/clang/Analysis/FlowSensitive/Value.h b/clang/include/clang/Analysis/FlowSensitive/Value.h index 6e911af7264ced9..e6c68e5b4e93e1e 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Value.h +++ b/clang/include/clang/Analysis/FlowSensitive/Value.h @@ -225,12 +225,6 @@ class RecordValue final : public Value { /// Returns the storage location that this `RecordValue` is associated with. RecordStorageLocation &getLoc() const { return Loc; } - /// Convenience function that returns the child storage location for `Field`. - /// See also the documentation for `RecordStorageLocation::getChild()`. - StorageLocation *getChild(const ValueDecl &Field) const { - return Loc.getChild(Field); - } - private: RecordStorageLocation &Loc; }; diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index 6e37011a052c5e4..ad40c0b082d302e 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -91,8 +91,8 @@ TEST_F(EnvironmentTest, CreateValueRecursiveType) { // Verify that the struct and the field (`R`) with first appearance of the // type is created successfully. Environment Env(DAContext, *Fun); - RecordValue *SVal = cast(Env.createValue(Ty)); - PointerValue *PV = cast_or_null(getFieldValue(SVal, *R, Env)); + auto &SLoc = cast(Env.createObject(Ty)); + PointerValue *PV = cast_or_null(getFieldValue(&SLoc, *R, Env)); EXPECT_THAT(PV, NotNull()); } @@ -240,8 +240,8 @@ TEST_F(EnvironmentTest, IncludeFieldsFromDefaultInitializers) { // Verify that the `X` field of `S` is populated when analyzing the // constructor, even though it is not referenced directly in the constructor. Environment Env(DAContext, *Constructor); - auto *Val = cast(Env.createValue(QTy)); - EXPECT_THAT(getFieldValue(Val, *XDecl, Env), NotNull()); + auto &Loc = cast(Env.createObject(QTy)); + EXPECT_THAT(getFieldValue(&Loc, *XDecl, Env), NotNull()); } TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) { @@ -285,8 +285,7 @@ TEST_F(EnvironmentTest, InitGlobalVarsFieldFun) { Environment Env(DAContext, *Fun); const auto *GlobalLoc = cast(Env.getStorageLocation(*GlobalDecl)); - const auto *GlobalVal = cast(Env.getValue(*GlobalLoc)); - auto *BarVal = getFieldValue(GlobalVal, *BarDecl, Env); + auto *BarVal = getFieldValue(GlobalLoc, *BarDecl, Env); EXPECT_TRUE(isa(BarVal)); } diff --git a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h index c61e9f26beff40b..0cf66c218f43fdc 100644 --- a/clang/unittests/Analysis/FlowSensitive/TestingSupport.h +++ b/clang/unittests/Analysis/FlowSensitive/TestingSupport.h @@ -463,18 +463,6 @@ inline Value *getFieldValue(const RecordStorageLocation *Loc, return Env.getValue(*FieldLoc); } -/// Returns the value of a `Field` on a `Struct. -/// Returns null if `Struct` is null. -inline Value *getFieldValue(const RecordValue *Struct, const ValueDecl &Field, - const Environment &Env) { - if (Struct == nullptr) - return nullptr; - StorageLocation *FieldLoc = Struct->getChild(Field); - if (FieldLoc == nullptr) - return nullptr; - return Env.getValue(*FieldLoc); -} - /// Creates and owns constraints which are boolean values. class ConstraintContext { unsigned NextAtom = 0; diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index cced3925c4721c5..05ee5df0e95a433 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -647,26 +647,26 @@ TEST(TransferTest, SelfReferentialPointerVarDecl) { const auto &FooLoc = *cast(Env.getStorageLocation(*FooDecl)); const auto &FooVal = *cast(Env.getValue(FooLoc)); - const auto &FooPointeeVal = - *cast(Env.getValue(FooVal.getPointeeLoc())); + const auto &FooPointeeLoc = + cast(FooVal.getPointeeLoc()); const auto &BarVal = - *cast(getFieldValue(&FooPointeeVal, *BarDecl, Env)); - const auto &BarPointeeVal = - *cast(Env.getValue(BarVal.getPointeeLoc())); + *cast(getFieldValue(&FooPointeeLoc, *BarDecl, Env)); + const auto &BarPointeeLoc = + cast(BarVal.getPointeeLoc()); - EXPECT_THAT(getFieldValue(&BarPointeeVal, *FooRefDecl, Env), NotNull()); + EXPECT_THAT(getFieldValue(&BarPointeeLoc, *FooRefDecl, Env), NotNull()); const auto &FooPtrVal = *cast( - getFieldValue(&BarPointeeVal, *FooPtrDecl, Env)); + getFieldValue(&BarPointeeLoc, *FooPtrDecl, Env)); const auto &FooPtrPointeeLoc = cast(FooPtrVal.getPointeeLoc()); EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); - EXPECT_THAT(getFieldValue(&BarPointeeVal, *BazRefDecl, Env), NotNull()); + EXPECT_THAT(getFieldValue(&BarPointeeLoc, *BazRefDecl, Env), NotNull()); const auto &BazPtrVal = *cast( - getFieldValue(&BarPointeeVal, *BazPtrDecl, Env)); + getFieldValue(&BarPointeeLoc, *BazPtrDecl, Env)); const StorageLocation &BazPtrPointeeLoc = BazPtrVal.getPointeeLoc(); EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); }); @@ -2478,9 +2478,10 @@ TEST(TransferTest, BindTemporary) { const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); - const auto &FooVal = *cast(Env.getValue(*FooDecl)); + const auto &FooLoc = + *cast(Env.getStorageLocation(*FooDecl)); const auto *BarVal = cast(Env.getValue(*BarDecl)); - EXPECT_EQ(BarVal, getFieldValue(&FooVal, *BazDecl, Env)); + EXPECT_EQ(BarVal, getFieldValue(&FooLoc, *BazDecl, Env)); }); } @@ -2970,16 +2971,14 @@ TEST(TransferTest, AggregateInitialization) { const auto *BarArgVal = cast(Env.getValue(*BarArgDecl)); const auto *QuxArgVal = cast(Env.getValue(*QuxArgDecl)); - const auto *QuuxVal = cast(Env.getValue(*QuuxDecl)); - ASSERT_THAT(QuuxVal, NotNull()); - - const auto *BazVal = - cast(getFieldValue(QuuxVal, *BazDecl, Env)); - ASSERT_THAT(BazVal, NotNull()); + const auto &QuuxLoc = + *cast(Env.getStorageLocation(*QuuxDecl)); + const auto &BazLoc = + *cast(QuuxLoc.getChild(*BazDecl)); - EXPECT_EQ(getFieldValue(QuuxVal, *BarDecl, Env), BarArgVal); - EXPECT_EQ(getFieldValue(BazVal, *FooDecl, Env), FooArgVal); - EXPECT_EQ(getFieldValue(QuuxVal, *QuxDecl, Env), QuxArgVal); + EXPECT_EQ(getFieldValue(&QuuxLoc, *BarDecl, Env), BarArgVal); + EXPECT_EQ(getFieldValue(&BazLoc, *FooDecl, Env), FooArgVal); + EXPECT_EQ(getFieldValue(&QuuxLoc, *QuxDecl, Env), QuxArgVal); // Check that fields initialized in an initializer list are always // modeled in other instances of the same type. @@ -3653,8 +3652,9 @@ TEST(TransferTest, AssignMemberBeforeCopy) { const auto *BarVal = cast(Env.getValue(*BarDecl)); - const auto *A2Val = cast(Env.getValue(*A2Decl)); - EXPECT_EQ(getFieldValue(A2Val, *FooDecl, Env), BarVal); + const auto &A2Loc = + *cast(Env.getStorageLocation(*A2Decl)); + EXPECT_EQ(getFieldValue(&A2Loc, *FooDecl, Env), BarVal); }); } |
We want to eliminate the `RecordStorageLocation` from `RecordValue` and, ultimately, eliminate `RecordValue` entirely (see the discussion linked in the `RecordValue` class comment). This is one step in that direction. To eliminate `RecordValue::getChild()`, we also eliminate the last remaining caller, namely the `getFieldValue(const RecordValue *, ...)` overload. Calls to this overload have been rewritten to use the `getFieldValue(const RecordStorageLocation *, ...)` overload. Note that this also makes the code slightly simpler in many cases.
We want to eliminate the
RecordStorageLocation
fromRecordValue
and,ultimately, eliminate
RecordValue
entirely (see the discussion linked in theRecordValue
class comment). This is one step in that direction.To eliminate
RecordValue::getChild()
, we also eliminate the last remainingcaller, namely the
getFieldValue(const RecordValue *, ...)
overload. Callsto this overload have been rewritten to use the
getFieldValue(const RecordStorageLocation *, ...)
overload. Note that thisalso makes the code slightly simpler in many cases.