11
11
#include " clang/ASTMatchers/ASTMatchers.h"
12
12
#include " clang/Testing/TestAST.h"
13
13
#include " llvm/ADT/StringMap.h"
14
+ #include " llvm/Testing/Support/Error.h"
14
15
#include " gmock/gmock.h"
15
16
#include " gtest/gtest.h"
16
17
#include < optional>
@@ -20,6 +21,7 @@ namespace clang::lifetimes::internal {
20
21
namespace {
21
22
22
23
using namespace ast_matchers ;
24
+ using ::testing::SizeIs;
23
25
using ::testing::UnorderedElementsAreArray;
24
26
25
27
// A helper class to run the full lifetime analysis on a piece of code
@@ -96,21 +98,18 @@ class LifetimeTestHelper {
96
98
return OID;
97
99
}
98
100
99
- std::optional <LoanID> getLoanForVar (llvm::StringRef VarName) {
101
+ std::vector <LoanID> getLoansForVar (llvm::StringRef VarName) {
100
102
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
+ }
103
107
std::vector<LoanID> LID = Analysis.getLoanIDForVar (VD);
104
108
if (LID.empty ()) {
105
109
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 {};
112
111
}
113
- return LID[ 0 ] ;
112
+ return LID;
114
113
}
115
114
116
115
std::optional<LoanSet> getLoansAtPoint (OriginID OID,
@@ -121,13 +120,12 @@ class LifetimeTestHelper {
121
120
return Analysis.getLoansAtPoint (OID, PP);
122
121
}
123
122
124
- std::optional<llvm::DenseSet <LoanID>>
123
+ std::optional<std::vector <LoanID>>
125
124
getExpiredLoansAtPoint (llvm::StringRef Annotation) {
126
125
ProgramPoint PP = Runner.getProgramPoint (Annotation);
127
126
if (!PP)
128
127
return std::nullopt;
129
- auto Expired = Analysis.getExpiredLoansAtPoint (PP);
130
- return llvm::DenseSet<LoanID>{Expired.begin (), Expired.end ()};
128
+ return Analysis.getExpiredLoansAtPoint (PP);
131
129
}
132
130
133
131
private:
@@ -197,12 +195,13 @@ MATCHER_P2(HasLoansToImpl, LoanVars, Annotation, "") {
197
195
198
196
std::vector<LoanID> ExpectedLoans;
199
197
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 () ) {
202
200
*result_listener << " could not find loan for var '" << LoanVar << " '" ;
203
201
return false ;
204
202
}
205
- ExpectedLoans.push_back (*ExpectedLIDOpt);
203
+ ExpectedLoans.insert (ExpectedLoans.end (), ExpectedLIDs.begin (),
204
+ ExpectedLIDs.end ());
206
205
}
207
206
208
207
return ExplainMatchResult (UnorderedElementsAreArray (ExpectedLoans),
@@ -221,17 +220,17 @@ MATCHER_P(AreExpiredAt, Annotation, "") {
221
220
<< Annotation << " '" ;
222
221
return false ;
223
222
}
224
- std::vector<LoanID> ActualExpiredLoans (ActualExpiredSetOpt->begin (),
225
- ActualExpiredSetOpt->end ());
223
+ std::vector<LoanID> ActualExpiredLoans = *ActualExpiredSetOpt;
226
224
std::vector<LoanID> ExpectedExpiredLoans;
227
225
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 () ) {
230
228
*result_listener << " could not find a loan for variable '" << VarName
231
229
<< " '" ;
232
230
return false ;
233
231
}
234
- ExpectedExpiredLoans.push_back (*LoanIDOpt);
232
+ ExpectedExpiredLoans.insert (ExpectedExpiredLoans.end (), LoanIDs.begin (),
233
+ LoanIDs.end ());
235
234
}
236
235
return ExplainMatchResult (UnorderedElementsAreArray (ExpectedExpiredLoans),
237
236
ActualExpiredLoans, result_listener);
@@ -730,5 +729,17 @@ TEST_F(LifetimeAnalysisTest, ReassignedPointerThenOriginalExpires) {
730
729
EXPECT_THAT (LoansTo ({" s1" , " s2" }), AreExpiredAt (" p_after_s1_expires" ));
731
730
}
732
731
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
+
733
744
} // anonymous namespace
734
745
} // namespace clang::lifetimes::internal
0 commit comments