1111#include " clang/ASTMatchers/ASTMatchers.h"
1212#include " clang/Testing/TestAST.h"
1313#include " llvm/ADT/StringMap.h"
14+ #include " llvm/Testing/Support/Error.h"
1415#include " gmock/gmock.h"
1516#include " gtest/gtest.h"
1617#include < optional>
@@ -20,6 +21,7 @@ namespace clang::lifetimes::internal {
2021namespace {
2122
2223using namespace ast_matchers ;
24+ using ::testing::SizeIs;
2325using ::testing::UnorderedElementsAreArray;
2426
2527// A helper class to run the full lifetime analysis on a piece of code
@@ -96,21 +98,18 @@ class LifetimeTestHelper {
9698 return OID;
9799 }
98100
99- std::optional <LoanID> getLoanForVar (llvm::StringRef VarName) {
101+ std::vector <LoanID> getLoansForVar (llvm::StringRef VarName) {
100102 auto *VD = findDecl<VarDecl>(VarName);
101- if (!VD)
102- return std::nullopt ;
103+ if (!VD) {
104+ ADD_FAILURE () << " No VarDecl found for '" << VarName << " '" ;
105+ return {};
106+ }
103107 std::vector<LoanID> LID = Analysis.getLoanIDForVar (VD);
104108 if (LID.empty ()) {
105109 ADD_FAILURE () << " Loan for '" << VarName << " ' not found." ;
106- return std::nullopt ;
107- }
108- // TODO: Support retrieving more than one loans to a var.
109- if (LID.size () > 1 ) {
110- ADD_FAILURE () << " More than 1 loans found for '" << VarName;
111- return std::nullopt ;
110+ return {};
112111 }
113- return LID[ 0 ] ;
112+ return LID;
114113 }
115114
116115 std::optional<LoanSet> getLoansAtPoint (OriginID OID,
@@ -121,13 +120,12 @@ class LifetimeTestHelper {
121120 return Analysis.getLoansAtPoint (OID, PP);
122121 }
123122
124- std::optional<llvm::DenseSet <LoanID>>
123+ std::optional<std::vector <LoanID>>
125124 getExpiredLoansAtPoint (llvm::StringRef Annotation) {
126125 ProgramPoint PP = Runner.getProgramPoint (Annotation);
127126 if (!PP)
128127 return std::nullopt ;
129- auto Expired = Analysis.getExpiredLoansAtPoint (PP);
130- return llvm::DenseSet<LoanID>{Expired.begin (), Expired.end ()};
128+ return Analysis.getExpiredLoansAtPoint (PP);
131129 }
132130
133131private:
@@ -197,12 +195,13 @@ MATCHER_P2(HasLoansToImpl, LoanVars, Annotation, "") {
197195
198196 std::vector<LoanID> ExpectedLoans;
199197 for (const auto &LoanVar : LoanVars) {
200- std::optional <LoanID> ExpectedLIDOpt = Info.Helper .getLoanForVar (LoanVar);
201- if (!ExpectedLIDOpt ) {
198+ std::vector <LoanID> ExpectedLIDs = Info.Helper .getLoansForVar (LoanVar);
199+ if (ExpectedLIDs. empty () ) {
202200 *result_listener << " could not find loan for var '" << LoanVar << " '" ;
203201 return false ;
204202 }
205- ExpectedLoans.push_back (*ExpectedLIDOpt);
203+ ExpectedLoans.insert (ExpectedLoans.end (), ExpectedLIDs.begin (),
204+ ExpectedLIDs.end ());
206205 }
207206
208207 return ExplainMatchResult (UnorderedElementsAreArray (ExpectedLoans),
@@ -221,17 +220,17 @@ MATCHER_P(AreExpiredAt, Annotation, "") {
221220 << Annotation << " '" ;
222221 return false ;
223222 }
224- std::vector<LoanID> ActualExpiredLoans (ActualExpiredSetOpt->begin (),
225- ActualExpiredSetOpt->end ());
223+ std::vector<LoanID> ActualExpiredLoans = *ActualExpiredSetOpt;
226224 std::vector<LoanID> ExpectedExpiredLoans;
227225 for (const auto &VarName : Info.LoanVars ) {
228- auto LoanIDOpt = Helper.getLoanForVar (VarName);
229- if (!LoanIDOpt ) {
226+ auto LoanIDs = Helper.getLoansForVar (VarName);
227+ if (LoanIDs. empty () ) {
230228 *result_listener << " could not find a loan for variable '" << VarName
231229 << " '" ;
232230 return false ;
233231 }
234- ExpectedExpiredLoans.push_back (*LoanIDOpt);
232+ ExpectedExpiredLoans.insert (ExpectedExpiredLoans.end (), LoanIDs.begin (),
233+ LoanIDs.end ());
235234 }
236235 return ExplainMatchResult (UnorderedElementsAreArray (ExpectedExpiredLoans),
237236 ActualExpiredLoans, result_listener);
@@ -730,5 +729,17 @@ TEST_F(LifetimeAnalysisTest, ReassignedPointerThenOriginalExpires) {
730729 EXPECT_THAT (LoansTo ({" s1" , " s2" }), AreExpiredAt (" p_after_s1_expires" ));
731730}
732731
732+ TEST_F (LifetimeAnalysisTest, NoDuplicateLoansForImplicitCastToConst) {
733+ SetupTest (R"(
734+ void target() {
735+ MyObj a;
736+ const MyObj* p = &a;
737+ const MyObj* q = &a;
738+ POINT(at_end);
739+ }
740+ )" );
741+ EXPECT_THAT (Helper->getLoansForVar (" a" ), SizeIs (2 ));
742+ }
743+
733744} // anonymous namespace
734745} // namespace clang::lifetimes::internal
0 commit comments