@@ -1009,6 +1009,174 @@ TEST_F(TransferTest, StructMember) {
1009
1009
});
1010
1010
}
1011
1011
1012
+ TEST_F (TransferTest, DerivedBaseMemberClass) {
1013
+ std::string Code = R"(
1014
+ class A {
1015
+ int ADefault;
1016
+ protected:
1017
+ int AProtected;
1018
+ private:
1019
+ int APrivate;
1020
+ public:
1021
+ int APublic;
1022
+ };
1023
+
1024
+ class B : public A {
1025
+ int BDefault;
1026
+ protected:
1027
+ int BProtected;
1028
+ private:
1029
+ int BPrivate;
1030
+ };
1031
+
1032
+ void target() {
1033
+ B Foo;
1034
+ // [[p]]
1035
+ }
1036
+ )" ;
1037
+ runDataflow (
1038
+ Code, [](llvm::ArrayRef<
1039
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1040
+ Results,
1041
+ ASTContext &ASTCtx) {
1042
+ ASSERT_THAT (Results, ElementsAre (Pair (" p" , _)));
1043
+ const Environment &Env = Results[0 ].second .Env ;
1044
+
1045
+ const ValueDecl *FooDecl = findValueDecl (ASTCtx, " Foo" );
1046
+ ASSERT_THAT (FooDecl, NotNull ());
1047
+ ASSERT_TRUE (FooDecl->getType ()->isRecordType ());
1048
+
1049
+ // Derived-class fields.
1050
+ const FieldDecl *BDefaultDecl = nullptr ;
1051
+ const FieldDecl *BProtectedDecl = nullptr ;
1052
+ const FieldDecl *BPrivateDecl = nullptr ;
1053
+ for (const FieldDecl *Field :
1054
+ FooDecl->getType ()->getAsRecordDecl ()->fields ()) {
1055
+ if (Field->getNameAsString () == " BDefault" ) {
1056
+ BDefaultDecl = Field;
1057
+ } else if (Field->getNameAsString () == " BProtected" ) {
1058
+ BProtectedDecl = Field;
1059
+ } else if (Field->getNameAsString () == " BPrivate" ) {
1060
+ BPrivateDecl = Field;
1061
+ } else {
1062
+ FAIL () << " Unexpected field: " << Field->getNameAsString ();
1063
+ }
1064
+ }
1065
+ ASSERT_THAT (BDefaultDecl, NotNull ());
1066
+ ASSERT_THAT (BProtectedDecl, NotNull ());
1067
+ ASSERT_THAT (BPrivateDecl, NotNull ());
1068
+
1069
+ // Base-class fields.
1070
+ const FieldDecl *ADefaultDecl = nullptr ;
1071
+ const FieldDecl *APrivateDecl = nullptr ;
1072
+ const FieldDecl *AProtectedDecl = nullptr ;
1073
+ const FieldDecl *APublicDecl = nullptr ;
1074
+ for (const clang::CXXBaseSpecifier &Base :
1075
+ FooDecl->getType ()->getAsCXXRecordDecl ()->bases ()) {
1076
+ QualType BaseType = Base.getType ();
1077
+ ASSERT_TRUE (BaseType->isRecordType ());
1078
+ for (const FieldDecl *Field : BaseType->getAsRecordDecl ()->fields ()) {
1079
+ if (Field->getNameAsString () == " ADefault" ) {
1080
+ ADefaultDecl = Field;
1081
+ } else if (Field->getNameAsString () == " AProtected" ) {
1082
+ AProtectedDecl = Field;
1083
+ } else if (Field->getNameAsString () == " APrivate" ) {
1084
+ APrivateDecl = Field;
1085
+ } else if (Field->getNameAsString () == " APublic" ) {
1086
+ APublicDecl = Field;
1087
+ } else {
1088
+ FAIL () << " Unexpected field: " << Field->getNameAsString ();
1089
+ }
1090
+ }
1091
+ }
1092
+ ASSERT_THAT (ADefaultDecl, NotNull ());
1093
+ ASSERT_THAT (AProtectedDecl, NotNull ());
1094
+ ASSERT_THAT (APrivateDecl, NotNull ());
1095
+ ASSERT_THAT (APublicDecl, NotNull ());
1096
+
1097
+ const auto &FooLoc = *cast<AggregateStorageLocation>(
1098
+ Env.getStorageLocation (*FooDecl, SkipPast::None));
1099
+ const auto &FooVal = *cast<StructValue>(Env.getValue (FooLoc));
1100
+
1101
+ // Note: we can't test presence of children in `FooLoc`, because
1102
+ // `getChild` requires its argument be present (or fails an assert). So,
1103
+ // we limit to testing presence in `FooVal` and coherence between the
1104
+ // two.
1105
+
1106
+ // Base-class fields.
1107
+ EXPECT_THAT (FooVal.getChild (*ADefaultDecl), IsNull ());
1108
+ EXPECT_THAT (FooVal.getChild (*APrivateDecl), IsNull ());
1109
+
1110
+ EXPECT_THAT (FooVal.getChild (*AProtectedDecl), NotNull ());
1111
+ EXPECT_EQ (Env.getValue (FooLoc.getChild (*APublicDecl)),
1112
+ FooVal.getChild (*APublicDecl));
1113
+ EXPECT_THAT (FooVal.getChild (*APublicDecl), NotNull ());
1114
+ EXPECT_EQ (Env.getValue (FooLoc.getChild (*AProtectedDecl)),
1115
+ FooVal.getChild (*AProtectedDecl));
1116
+
1117
+ // Derived-class fields.
1118
+ EXPECT_THAT (FooVal.getChild (*BDefaultDecl), NotNull ());
1119
+ EXPECT_EQ (Env.getValue (FooLoc.getChild (*BDefaultDecl)),
1120
+ FooVal.getChild (*BDefaultDecl));
1121
+ EXPECT_THAT (FooVal.getChild (*BProtectedDecl), NotNull ());
1122
+ EXPECT_EQ (Env.getValue (FooLoc.getChild (*BProtectedDecl)),
1123
+ FooVal.getChild (*BProtectedDecl));
1124
+ EXPECT_THAT (FooVal.getChild (*BPrivateDecl), NotNull ());
1125
+ EXPECT_EQ (Env.getValue (FooLoc.getChild (*BPrivateDecl)),
1126
+ FooVal.getChild (*BPrivateDecl));
1127
+ });
1128
+ }
1129
+
1130
+ TEST_F (TransferTest, DerivedBaseMemberStructDefault) {
1131
+ std::string Code = R"(
1132
+ struct A {
1133
+ int Bar;
1134
+ };
1135
+ struct B : public A {
1136
+ };
1137
+
1138
+ void target() {
1139
+ B Foo;
1140
+ // [[p]]
1141
+ }
1142
+ )" ;
1143
+ runDataflow (
1144
+ Code, [](llvm::ArrayRef<
1145
+ std::pair<std::string, DataflowAnalysisState<NoopLattice>>>
1146
+ Results,
1147
+ ASTContext &ASTCtx) {
1148
+ ASSERT_THAT (Results, ElementsAre (Pair (" p" , _)));
1149
+ const Environment &Env = Results[0 ].second .Env ;
1150
+
1151
+ const ValueDecl *FooDecl = findValueDecl (ASTCtx, " Foo" );
1152
+ ASSERT_THAT (FooDecl, NotNull ());
1153
+
1154
+ ASSERT_TRUE (FooDecl->getType ()->isRecordType ());
1155
+ const FieldDecl *BarDecl = nullptr ;
1156
+ for (const clang::CXXBaseSpecifier &Base :
1157
+ FooDecl->getType ()->getAsCXXRecordDecl ()->bases ()) {
1158
+ QualType BaseType = Base.getType ();
1159
+ ASSERT_TRUE (BaseType->isStructureType ());
1160
+
1161
+ for (const FieldDecl *Field : BaseType->getAsRecordDecl ()->fields ()) {
1162
+ if (Field->getNameAsString () == " Bar" ) {
1163
+ BarDecl = Field;
1164
+ } else {
1165
+ FAIL () << " Unexpected field: " << Field->getNameAsString ();
1166
+ }
1167
+ }
1168
+ }
1169
+ ASSERT_THAT (BarDecl, NotNull ());
1170
+
1171
+ const auto &FooLoc = *cast<AggregateStorageLocation>(
1172
+ Env.getStorageLocation (*FooDecl, SkipPast::None));
1173
+ const auto &FooVal = *cast<StructValue>(Env.getValue (FooLoc));
1174
+ EXPECT_THAT (FooVal.getChild (*BarDecl), NotNull ());
1175
+ EXPECT_EQ (Env.getValue (FooLoc.getChild (*BarDecl)),
1176
+ FooVal.getChild (*BarDecl));
1177
+ });
1178
+ }
1179
+
1012
1180
TEST_F (TransferTest, ClassMember) {
1013
1181
std::string Code = R"(
1014
1182
class A {
0 commit comments