3232namespace clang ::dataflow {
3333namespace {
3434
35+ using ast_matchers::BoundNodes;
3536using ast_matchers::callee;
3637using ast_matchers::cxxMemberCallExpr;
3738using ast_matchers::functionDecl;
@@ -46,6 +47,8 @@ using dataflow::RecordStorageLocation;
4647using dataflow::Value;
4748using dataflow::WatchedLiteralsSolver;
4849
50+ using testing::SizeIs;
51+
4952NamedDecl *lookup (StringRef Name, const DeclContext &DC) {
5053 auto Result = DC.lookup (&DC.getParentASTContext ().Idents .get (Name));
5154 EXPECT_TRUE (Result.isSingleResult ()) << Name;
@@ -99,7 +102,8 @@ struct CommonTestInputs {
99102 const CallExpr *CallRef;
100103};
101104
102- TEST_F (CachedConstAccessorsLatticeTest, SameValBeforeClearOrDiffAfterClear) {
105+ TEST_F (CachedConstAccessorsLatticeTest,
106+ SamePrimitiveValBeforeClearOrDiffAfterClear) {
103107 CommonTestInputs Inputs;
104108 auto *CE = Inputs.CallVal ;
105109 RecordStorageLocation Loc (Inputs.SType , RecordStorageLocation::FieldToLoc (),
@@ -144,6 +148,51 @@ TEST_F(CachedConstAccessorsLatticeTest, SameLocBeforeClearOrDiffAfterClear) {
144148 EXPECT_NE (Loc3, Loc2);
145149}
146150
151+ TEST_F (CachedConstAccessorsLatticeTest,
152+ SameStructValBeforeClearOrDiffAfterClear) {
153+ TestAST AST (R"cpp(
154+ struct S {
155+ S structValProperty() const;
156+ };
157+ void target() {
158+ S s;
159+ s.structValProperty();
160+ }
161+ )cpp" );
162+ auto *SDecl =
163+ cast<CXXRecordDecl>(lookup (" S" , *AST.context ().getTranslationUnitDecl ()));
164+ QualType SType = AST.context ().getRecordType (SDecl);
165+ const CallExpr *CE = selectFirst<CallExpr>(
166+ " call" , match (cxxMemberCallExpr (
167+ callee (functionDecl (hasName (" structValProperty" ))))
168+ .bind (" call" ),
169+ AST.context ()));
170+ ASSERT_NE (CE, nullptr );
171+
172+ RecordStorageLocation Loc (SType, RecordStorageLocation::FieldToLoc (), {});
173+
174+ LatticeT Lattice;
175+ // Accessors that return a record by value are modeled by a record storage
176+ // location (instead of a Value).
177+ auto NopInit = [](StorageLocation &) {};
178+ StorageLocation *Loc1 = Lattice.getOrCreateConstMethodReturnStorageLocation (
179+ Loc, CE, Env, NopInit);
180+ auto NotCalled = [](StorageLocation &) {
181+ ASSERT_TRUE (false ) << " Not reached" ;
182+ };
183+ StorageLocation *Loc2 = Lattice.getOrCreateConstMethodReturnStorageLocation (
184+ Loc, CE, Env, NotCalled);
185+
186+ EXPECT_EQ (Loc1, Loc2);
187+
188+ Lattice.clearConstMethodReturnStorageLocations (Loc);
189+ StorageLocation *Loc3 = Lattice.getOrCreateConstMethodReturnStorageLocation (
190+ Loc, CE, Env, NopInit);
191+
192+ EXPECT_NE (Loc3, Loc1);
193+ EXPECT_NE (Loc3, Loc1);
194+ }
195+
147196TEST_F (CachedConstAccessorsLatticeTest, ClearDifferentLocs) {
148197 CommonTestInputs Inputs;
149198 auto *CE = Inputs.CallRef ;
@@ -168,6 +217,49 @@ TEST_F(CachedConstAccessorsLatticeTest, ClearDifferentLocs) {
168217 EXPECT_EQ (RetLoc1, RetLoc2);
169218}
170219
220+ TEST_F (CachedConstAccessorsLatticeTest, DifferentValsFromDifferentLocs) {
221+ TestAST AST (R"cpp(
222+ struct S {
223+ int *valProperty() const;
224+ };
225+ void target() {
226+ S s1;
227+ s1.valProperty();
228+ S s2;
229+ s2.valProperty();
230+ }
231+ )cpp" );
232+ auto *SDecl =
233+ cast<CXXRecordDecl>(lookup (" S" , *AST.context ().getTranslationUnitDecl ()));
234+ QualType SType = AST.context ().getRecordType (SDecl);
235+ SmallVector<BoundNodes, 1 > valPropertyCalls =
236+ match (cxxMemberCallExpr (callee (functionDecl (hasName (" valProperty" ))))
237+ .bind (" call" ),
238+ AST.context ());
239+ ASSERT_THAT (valPropertyCalls, SizeIs (2 ));
240+
241+ const CallExpr *CE1 = selectFirst<CallExpr>(
242+ " call" , valPropertyCalls);
243+ ASSERT_NE (CE1, nullptr );
244+
245+ valPropertyCalls.erase (valPropertyCalls.begin ());
246+ const CallExpr *CE2 = selectFirst<CallExpr>(
247+ " call" , valPropertyCalls);
248+ ASSERT_NE (CE2, nullptr );
249+ ASSERT_NE (CE1, CE2);
250+
251+ RecordStorageLocation LocS1 (SType, RecordStorageLocation::FieldToLoc (), {});
252+ RecordStorageLocation LocS2 (SType, RecordStorageLocation::FieldToLoc (), {});
253+
254+ LatticeT Lattice;
255+ Value *Val1 =
256+ Lattice.getOrCreateConstMethodReturnValue (LocS1, CE1, Env);
257+ Value *Val2 =
258+ Lattice.getOrCreateConstMethodReturnValue (LocS2, CE2, Env);
259+
260+ EXPECT_NE (Val1, Val2);
261+ }
262+
171263TEST_F (CachedConstAccessorsLatticeTest, JoinSameNoop) {
172264 CommonTestInputs Inputs;
173265 auto *CE = Inputs.CallVal ;
0 commit comments