blob: 1b467dbfd2244754d246a62e8cc99e2f36d06096 [file] [log] [blame]
Googlerb0019ca2021-11-26 14:20:10 +00001// Part of the Crubit project, under the Apache License v2.0 with LLVM
2// Exceptions. See /LICENSE for license information.
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#include "lifetime_annotations/lifetime_annotations.h"
6
7#include <string>
8#include <utility>
9
Luca Versaric21d92f2022-05-25 00:56:30 -070010#include "gmock/gmock.h"
11#include "gtest/gtest.h"
12#include "absl/status/status.h"
13#include "common/status_test_matchers.h"
Marcel Hlopko97a68a12022-03-09 11:38:51 +000014#include "lifetime_annotations/test/named_func_lifetimes.h"
15#include "lifetime_annotations/test/run_on_code.h"
Martin Brænne2af40a02022-06-27 01:28:16 -070016#include "lifetime_annotations/type_lifetimes.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070017#include "clang/ASTMatchers/ASTMatchFinder.h"
18#include "clang/ASTMatchers/ASTMatchers.h"
19#include "llvm/Support/FormatVariadic.h"
Googlerb0019ca2021-11-26 14:20:10 +000020
Martin Brænne9fb786f2022-06-23 01:18:19 -070021// This file contains tests both for the "legacy" lifetime annotations
22// (`[[clang::annotate("lifetimes", ...)]]` placed on a function declaration)
23// and the newer annotations (`[[clang::annotate_type("lifetime", ...")]]`
24// placed on a type). This is because we expect we may continue to use the
25// "legacy" style of annotations in sidecar files.
26//
27// Some tests only test one style of annotation where testing the other style
28// does not make sense for the particular test.
29
Martin Brænne1a207c52022-04-19 00:05:38 -070030namespace clang {
31namespace tidy {
32namespace lifetimes {
Googlerb0019ca2021-11-26 14:20:10 +000033namespace {
34
Luca Versaric21d92f2022-05-25 00:56:30 -070035using crubit::IsOkAndHolds;
36using crubit::StatusIs;
Googlerb0019ca2021-11-26 14:20:10 +000037using testing::StartsWith;
Googlerb0019ca2021-11-26 14:20:10 +000038
Lukasz Anforowicz63f10da2022-01-26 16:59:36 +000039bool IsOverloaded(const clang::FunctionDecl* func) {
40 return !func->getDeclContext()->lookup(func->getDeclName()).isSingleResult();
41}
42
Googlerb0019ca2021-11-26 14:20:10 +000043std::string QualifiedName(const clang::FunctionDecl* func) {
44 std::string str;
45 llvm::raw_string_ostream ostream(str);
46 func->printQualifiedName(ostream);
Lukasz Anforowicz63f10da2022-01-26 16:59:36 +000047 if (IsOverloaded(func)) {
Martin Brænne2af40a02022-06-27 01:28:16 -070048 ostream << "[" << StripAttributes(func->getType()).getAsString() << "]";
Lukasz Anforowicz63f10da2022-01-26 16:59:36 +000049 }
Googlerb0019ca2021-11-26 14:20:10 +000050 ostream.flush();
51 return str;
52}
53
Martin Brænne9fb786f2022-06-23 01:18:19 -070054// Prepends definitions for lifetime annotation macros to the code.
55std::string WithLifetimeMacros(absl::string_view code) {
56 std::string result = R"(
Martin Brænne8bc2de32022-06-24 07:01:52 -070057 // TODO(mboehme): We would prefer `$(...)` to be a variadic macro that
58 // stringizes each of its macro arguments individually. This is possible but
59 // requires some contortions: https://stackoverflow.com/a/5958315
Martin Brænne9fb786f2022-06-23 01:18:19 -070060 #define $(l) [[clang::annotate_type("lifetime", #l)]]
Martin Brænne8bc2de32022-06-24 07:01:52 -070061 #define $2(l1, l2) [[clang::annotate_type("lifetime", #l1, #l2)]]
62 #define $3(l1, l2, l3) [[clang::annotate_type("lifetime", #l1, #l2, #l3)]]
Martin Brænne9fb786f2022-06-23 01:18:19 -070063 )";
64 for (char l = 'a'; l <= 'z'; ++l) {
65 absl::StrAppendFormat(&result, "#define $%c $(%c)\n", l, l);
66 }
Martin Brænneddf2e822022-06-27 00:43:56 -070067 absl::StrAppend(&result, "#define $static $(static)\n");
Martin Brænne9fb786f2022-06-23 01:18:19 -070068 absl::StrAppend(&result, code);
69 return result;
70}
71
Googlerb0019ca2021-11-26 14:20:10 +000072class LifetimeAnnotationsTest : public testing::Test {
73 protected:
74 absl::StatusOr<NamedFuncLifetimes> GetNamedLifetimeAnnotations(
75 absl::string_view code,
76 const clang::tooling::FileContentMappings& file_contents =
77 clang::tooling::FileContentMappings()) {
78 absl::StatusOr<NamedFuncLifetimes> result;
Googler656e5b22022-03-01 09:40:47 +000079 bool success = runOnCodeWithLifetimeHandlers(
Googler1cd66872021-12-10 11:40:03 +000080 llvm::StringRef(code.data(), code.size()),
Googlerb0019ca2021-11-26 14:20:10 +000081 [&result](clang::ASTContext& ast_context,
82 const LifetimeAnnotationContext& lifetime_context) {
83 using clang::ast_matchers::findAll;
84 using clang::ast_matchers::functionDecl;
85 using clang::ast_matchers::match;
86
87 NamedFuncLifetimes named_func_lifetimes;
88 for (const auto& node :
89 match(findAll(functionDecl().bind("func")), ast_context)) {
90 if (const auto* func =
91 node.getNodeAs<clang::FunctionDecl>("func")) {
Martin Brænnebd003e92022-06-27 23:22:27 -070092 // Skip various categories of function:
93 // - Template instantiation don't contain any annotations that
94 // aren't present in the template itself, but they may contain
95 // reference-like types (which will obviously be unannotated),
96 // which will generate nuisance "lifetime elision not enabled"
97 // errors.
98 // - Implicitly defaulted functions obviously cannot contain
99 // lifetime annotations. They will need to be handled through
100 // `AnalyzeDefaultedFunction()` in analyze.cc.
101 if (func->isTemplateInstantiation() ||
102 (func->isDefaulted() && !func->isExplicitlyDefaulted())) {
103 continue;
104 }
105
Googlerbea5dd12021-11-30 11:47:04 +0000106 LifetimeSymbolTable symbol_table;
Googlerb0019ca2021-11-26 14:20:10 +0000107 llvm::Expected<FunctionLifetimes> func_lifetimes =
Googlerbea5dd12021-11-30 11:47:04 +0000108 GetLifetimeAnnotations(func, lifetime_context, &symbol_table);
Googlerb0019ca2021-11-26 14:20:10 +0000109
Martin Brænne2af40a02022-06-27 01:28:16 -0700110 std::string new_entry;
111 if (func_lifetimes) {
112 new_entry = NameLifetimes(*func_lifetimes, symbol_table);
113 } else {
114 new_entry = absl::StrCat(
115 "ERROR: ", llvm::toString(func_lifetimes.takeError()));
Googlerb0019ca2021-11-26 14:20:10 +0000116 }
Martin Brænne2af40a02022-06-27 01:28:16 -0700117
Lukasz Anforowicz63f10da2022-01-26 16:59:36 +0000118 std::string func_name = QualifiedName(func);
Lukasz Anforowicz63f10da2022-01-26 16:59:36 +0000119 std::optional<llvm::StringRef> old_entry =
120 named_func_lifetimes.Get(func_name);
121 if (old_entry.has_value()) {
122 if (new_entry != old_entry.value()) {
123 result = absl::UnknownError(
124 llvm::formatv(
125 "Unexpectedly different lifetimes for function '{0}'."
126 "Old: '{1}'. New: '{2}'.",
127 func_name, old_entry.value(), new_entry)
128 .str());
129 return;
130 }
131 } else {
132 named_func_lifetimes.Add(std::move(func_name),
133 std::move(new_entry));
134 }
Googlerb0019ca2021-11-26 14:20:10 +0000135 }
136 }
137
138 result = std::move(named_func_lifetimes);
139 },
140 {}, file_contents);
141
Googler656e5b22022-03-01 09:40:47 +0000142 if (!success) {
143 return absl::UnknownError(
144 "Error extracting lifetimes. (Compilation error?)");
145 }
146
Googlerb0019ca2021-11-26 14:20:10 +0000147 return result;
148 }
149};
150
151TEST_F(LifetimeAnnotationsTest, NoLifetimes) {
152 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
153 int f(int);
154 )"),
155 IsOkAndHolds(LifetimesAre({{"f", "()"}})));
156}
157
Googler656e5b22022-03-01 09:40:47 +0000158TEST_F(LifetimeAnnotationsTest, Failure_CompileError) {
159 EXPECT_THAT(
160 GetNamedLifetimeAnnotations(R"(
161 undefined f(undefined);
162 )"),
163 StatusIs(absl::StatusCode::kUnknown,
164 StartsWith("Error extracting lifetimes. (Compilation error?)")));
165}
166
Googlerb0019ca2021-11-26 14:20:10 +0000167TEST_F(LifetimeAnnotationsTest, Failure_NoAnnotationsNoLifetimeElision) {
168 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
169 int** f(int*);
170 )"),
Martin Brænne2af40a02022-06-27 01:28:16 -0700171 IsOkAndHolds(LifetimesAre(
172 {{"f", "ERROR: Lifetime elision not enabled for 'f'"}})));
Googlerb0019ca2021-11-26 14:20:10 +0000173}
174
Googler6804a012022-01-05 07:04:36 +0000175TEST_F(LifetimeAnnotationsTest, Failure_NoOutputAnnotationNoLifetimeElision) {
176 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
177 int* f();
178 )"),
Martin Brænne2af40a02022-06-27 01:28:16 -0700179 // We specifically want to see this error message rather than
180 // "Cannot elide output lifetimes".
181 IsOkAndHolds(LifetimesAre(
182 {{"f", "ERROR: Lifetime elision not enabled for 'f'"}})));
Googler6804a012022-01-05 07:04:36 +0000183}
184
Googlerb0019ca2021-11-26 14:20:10 +0000185TEST_F(LifetimeAnnotationsTest, Failure_NoAnnotationsElisionPragmaInWrongFile) {
186 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
Googler33f768d2021-11-29 10:33:49 +0000187 #pragma clang lifetime_elision
Googlerb0019ca2021-11-26 14:20:10 +0000188 #include "header.h"
189 )",
190 {std::make_pair("header.h", R"(
191 int** f(int*);
192 )")}),
Martin Brænne2af40a02022-06-27 01:28:16 -0700193 IsOkAndHolds(LifetimesAre(
194 {{"f", "ERROR: Lifetime elision not enabled for 'f'"}})));
Googlerb0019ca2021-11-26 14:20:10 +0000195}
196
197TEST_F(LifetimeAnnotationsTest, LifetimeElision_OneInputLifetime) {
198 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
Googler33f768d2021-11-29 10:33:49 +0000199 #pragma clang lifetime_elision
Googlerb0019ca2021-11-26 14:20:10 +0000200 int** f(int*);
201 )"),
202 IsOkAndHolds(LifetimesAre({{"f", "a -> (a, a)"}})));
203}
204
205TEST_F(LifetimeAnnotationsTest, LifetimeElision_NoOutputLifetimes) {
206 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
Googler33f768d2021-11-29 10:33:49 +0000207 #pragma clang lifetime_elision
Googlerb0019ca2021-11-26 14:20:10 +0000208 void f(int**, int *);
209 )"),
210 IsOkAndHolds(LifetimesAre({{"f", "(a, b), c"}})));
211}
212
213TEST_F(LifetimeAnnotationsTest, LifetimeElision_Templates) {
214 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
Googler33f768d2021-11-29 10:33:49 +0000215 #pragma clang lifetime_elision
Googlerb0019ca2021-11-26 14:20:10 +0000216 template <class T> class vector {};
217 int* f(vector<int *>);
218 vector<int*> g(int *);
219 )"),
220 IsOkAndHolds(LifetimesAre({{"f", "a -> a"}, {"g", "a -> a"}})));
221}
222
Googlere4d4ec42022-03-28 06:52:23 -0700223TEST_F(LifetimeAnnotationsTest, LifetimeElision_NestedTemplates) {
Luca Versari6ee6b342022-04-05 05:40:52 -0700224 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
Googlerbdc55802022-03-24 11:21:37 +0000225 #pragma clang lifetime_elision
226 template <class T>
227 struct Outer {
228 template <class U>
229 struct Inner {
230 };
231 };
232 void f(Outer<int *>::Inner<int *> &);
233 Outer<int *>::Inner<int *> g(int *);
234 )"),
Luca Versari6ee6b342022-04-05 05:40:52 -0700235 IsOkAndHolds(LifetimesAre(
236 {{"f", "(<a>::<b>, c)"}, {"g", "a -> <a>::<a>"}})));
Googlerbdc55802022-03-24 11:21:37 +0000237}
238
Googlerfbb37d22022-03-02 15:13:53 +0000239TEST_F(LifetimeAnnotationsTest, LifetimeElision_LifetimeParameterizedType) {
240 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
241 #pragma clang lifetime_elision
242 struct [[clang::annotate("lifetime_params", "s")]] string_view{};
243 string_view f(string_view);
244 )"),
245 IsOkAndHolds(LifetimesAre({{"f", "a -> a"}})));
246}
247
Googlerb0019ca2021-11-26 14:20:10 +0000248TEST_F(LifetimeAnnotationsTest, LifetimeElision_Method) {
249 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
Googler33f768d2021-11-29 10:33:49 +0000250 #pragma clang lifetime_elision
Googlerb0019ca2021-11-26 14:20:10 +0000251 struct S {
252 int** method(int *, int *);
253 };
254 )"),
Googler6804a012022-01-05 07:04:36 +0000255 IsOkAndHolds(LifetimesAre({{"S::method", "a: b, c -> (a, a)"}})));
Googlerb0019ca2021-11-26 14:20:10 +0000256}
257
Devin Jeanpierre108e9c02022-06-02 07:10:09 -0700258TEST_F(LifetimeAnnotationsTest, LifetimeElision_Destructor) {
259 EXPECT_THAT(GetNamedLifetimeAnnotations(R"cc(
260 // Note: this works even without #pragma clang lifetime_elision
261 struct S {
262 ~S();
263 };
264 )cc"),
265 IsOkAndHolds(LifetimesAre({{"S::~S", "a:"}})));
266}
267
Lukasz Anforowicz63f10da2022-01-26 16:59:36 +0000268TEST_F(LifetimeAnnotationsTest, LifetimeElision_ExplicitlyDefaultedCtor) {
269 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
270 #pragma clang lifetime_elision
271 struct S {
272 S() = default;
273 };)"),
274 IsOkAndHolds(LifetimesAre({{"S::S", "a:"}})));
275}
276
Googler8a8e82e2022-02-28 14:53:56 +0000277TEST_F(LifetimeAnnotationsTest, LifetimeElision_ArrayParamLifetimes) {
278 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
279 #pragma clang lifetime_elision
280 void f(int pair[2]);
281 )"),
282 IsOkAndHolds(LifetimesAre({{"f", "a"}})));
283}
284
285TEST_F(LifetimeAnnotationsTest, LifetimeElision_ArrayParamAsTypedefLifetimes) {
286 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
287 #pragma clang lifetime_elision
Googler656e5b22022-03-01 09:40:47 +0000288 typedef int Arr[2];
Googler8a8e82e2022-02-28 14:53:56 +0000289 void f(Arr);
290 )"),
291 IsOkAndHolds(LifetimesAre({{"f", "a"}})));
292}
293
294TEST_F(LifetimeAnnotationsTest, LifetimeElision_FunctionPointerLifetimes) {
295 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
296 #pragma clang lifetime_elision
297 void f(void (*)());
298 )"),
299 IsOkAndHolds(LifetimesAre({{"f", "a"}})));
300}
301
302TEST_F(LifetimeAnnotationsTest,
303 LifetimeElision_FunctionPointerAsTypedefLifetimes) {
304 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
305 #pragma clang lifetime_elision
306 typedef void (*FunctionPointer)();
307 void f(FunctionPointer hook);
308 )"),
309 IsOkAndHolds(LifetimesAre({{"f", "a"}})));
310}
311
312TEST_F(LifetimeAnnotationsTest, LifetimeElision_FunctionReferenceLifetimes) {
313 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
314 #pragma clang lifetime_elision
315 typedef void (&FunctionReference)();
316 void f(FunctionReference hook);
317 )"),
318 IsOkAndHolds(LifetimesAre({{"f", "a"}})));
319}
320
321TEST_F(LifetimeAnnotationsTest,
322 LifetimeElision_FunctionReferenceAsTypedefLifetimes) {
323 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
324 #pragma clang lifetime_elision
325 void f(void (&)());
326 )"),
327 IsOkAndHolds(LifetimesAre({{"f", "a"}})));
328}
329
Googler2e1f0c12022-03-01 09:26:30 +0000330TEST_F(LifetimeAnnotationsTest,
331 LifetimeElision_PointerToMemberDoesNotGetLifetime) {
332 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
333 #pragma clang lifetime_elision
334 struct S {};
335 void f(int S::*ptr_to_member);
336 )"),
337 IsOkAndHolds(LifetimesAre({{"f", "()"}})));
338}
339
Googler8a8e82e2022-02-28 14:53:56 +0000340TEST_F(LifetimeAnnotationsTest, LifetimeElision_FailureTooFewInputLifetimes) {
341 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
342 #pragma clang lifetime_elision
343 int* f();
344 )"),
Martin Brænne2af40a02022-06-27 01:28:16 -0700345 IsOkAndHolds(LifetimesAre(
346 {{"f",
347 "ERROR: Cannot elide output lifetimes for 'f' because it "
348 "is a non-member function that does not have exactly one "
349 "input lifetime"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000350}
351
352TEST_F(LifetimeAnnotationsTest, LifetimeElision_FailureTooManyInputLifetimes) {
353 EXPECT_THAT(GetNamedLifetimeAnnotations(R"(
354 #pragma clang lifetime_elision
355 int* f(int**);
356 )"),
Martin Brænne2af40a02022-06-27 01:28:16 -0700357 IsOkAndHolds(LifetimesAre(
358 {{"f",
359 "ERROR: Cannot elide output lifetimes for 'f' because it "
360 "is a non-member function that does not have exactly one "
361 "input lifetime"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000362}
363
364TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_NoLifetimes) {
365 EXPECT_THAT(GetNamedLifetimeAnnotations(R"_(
366 [[clang::annotate("lifetimes", "()")]]
367 void f(int);
368 )_"),
369 IsOkAndHolds(LifetimesAre({{"f", "()"}})));
370}
371
Martin Brænne9fb786f2022-06-23 01:18:19 -0700372TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_BadAttributeArgument) {
373 EXPECT_THAT(
374 GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
375 void f(int* [[clang::annotate_type("lifetime", 1)]]);
376 )")),
Martin Brænne2af40a02022-06-27 01:28:16 -0700377 IsOkAndHolds(LifetimesAre(
378 {{"f", "ERROR: cannot evaluate argument as a string literal"}})));
Martin Brænne9fb786f2022-06-23 01:18:19 -0700379}
380
Googler8a8e82e2022-02-28 14:53:56 +0000381TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_Simple) {
Martin Brænne9fb786f2022-06-23 01:18:19 -0700382 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Googler8a8e82e2022-02-28 14:53:56 +0000383 [[clang::annotate("lifetimes", "a -> a")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700384 int* f1(int*);
385 int* $a f2(int* $a);
386 )")),
387 IsOkAndHolds(LifetimesAre({{"f1", "a -> a"}, {"f2", "a -> a"}})));
388}
389
390TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_SimpleRef) {
391 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
392 [[clang::annotate("lifetimes", "a -> a")]]
393 int& f1(int&);
394 int& $a f2(int& $a);
395 )")),
396 IsOkAndHolds(LifetimesAre({{"f1", "a -> a"}, {"f2", "a -> a"}})));
397}
398
399TEST_F(LifetimeAnnotationsTest,
400 LifetimeAnnotation_Invalid_MultipleLifetimesOnPointer) {
401 EXPECT_THAT(
402 GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Martin Brænne8bc2de32022-06-24 07:01:52 -0700403 void f(int* $2(a, b));
Martin Brænne9fb786f2022-06-23 01:18:19 -0700404 )")),
Martin Brænne2af40a02022-06-27 01:28:16 -0700405 IsOkAndHolds(LifetimesAre(
406 {{"f", "ERROR: Expected a single lifetime but 2 were given"}})));
Martin Brænne9fb786f2022-06-23 01:18:19 -0700407}
408
409TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_Static) {
410 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
411 [[clang::annotate("lifetimes", "static -> static")]]
412 int* f1(int*);
413 int* $static f2(int* $static);
414 )")),
415 IsOkAndHolds(LifetimesAre(
416 {{"f1", "static -> static"}, {"f2", "static -> static"}})));
417}
418
419TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_PartialElision) {
420 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
421 #pragma clang lifetime_elision
422 int* $a f(int* $a, int*, int* $a);
423 )")),
424 IsOkAndHolds(LifetimesAre({{"f", "a, b, a -> a"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000425}
426
427TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_MultiplePtr) {
Martin Brænne9fb786f2022-06-23 01:18:19 -0700428 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Googler8a8e82e2022-02-28 14:53:56 +0000429 [[clang::annotate("lifetimes", "(a, b) -> a")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700430 int* f1(int**);
431 int* $a f2(int* $a * $b);
432 )")),
433 IsOkAndHolds(LifetimesAre(
434 {{"f1", "(a, b) -> a"}, {"f2", "(a, b) -> a"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000435}
436
437TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_MultipleArguments) {
Martin Brænne9fb786f2022-06-23 01:18:19 -0700438 EXPECT_THAT(
439 GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Googler8a8e82e2022-02-28 14:53:56 +0000440 [[clang::annotate("lifetimes", "a, b -> a")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700441 int* f1(int*, int*);
442 int* $a f2(int* $a, int* $b);
443 )")),
444 IsOkAndHolds(LifetimesAre({{"f1", "a, b -> a"}, {"f2", "a, b -> a"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000445}
446
447TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_NoReturn) {
Martin Brænne9fb786f2022-06-23 01:18:19 -0700448 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Googler8a8e82e2022-02-28 14:53:56 +0000449 [[clang::annotate("lifetimes", "a, b")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700450 void f1(int*, int*);
451 void f2(int* $a, int* $b);
452 )")),
453 IsOkAndHolds(LifetimesAre({{"f1", "a, b"}, {"f2", "a, b"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000454}
455
Martin Brænne9fb786f2022-06-23 01:18:19 -0700456TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_ParamWithoutLifetime) {
457 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Googler8a8e82e2022-02-28 14:53:56 +0000458 [[clang::annotate("lifetimes", "a, (), a -> a")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700459 int* f1(int*, int, int*);
460 int* $a f2(int* $a, int, int* $a);
461 )")),
462 IsOkAndHolds(LifetimesAre(
463 {{"f1", "a, (), a -> a"}, {"f2", "a, (), a -> a"}})));
464}
465
466TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_LifetimeParameterizedType) {
467 // Use a custom delimiter so that the `")` in the `clang::annotate` attribute
468 // below doesn't prematurely terminate the string.
469 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"code(
470 struct [[clang::annotate("lifetime_params", "a", "b")]] S_param {};
471
472 [[clang::annotate("lifetimes", "([a, b]) -> ([a, b])")]]
473 S_param f1(S_param s);
474
Martin Brænne8bc2de32022-06-24 07:01:52 -0700475 S_param $2(a, b) f2(S_param $2(a, b) s);
Martin Brænne9fb786f2022-06-23 01:18:19 -0700476 )code")),
477 IsOkAndHolds(LifetimesAre({{"f1", "([a, b]) -> ([a, b])"},
478 {"f2", "([a, b]) -> ([a, b])"}})));
479}
480
Martin Brænne8bc2de32022-06-24 07:01:52 -0700481TEST_F(
482 LifetimeAnnotationsTest,
483 LifetimeAnnotation_LifetimeParameterizedType_Invalid_WrongNumberOfLifetimes) {
Martin Brænne2af40a02022-06-27 01:28:16 -0700484 EXPECT_THAT(
485 GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Martin Brænne9fb786f2022-06-23 01:18:19 -0700486 struct [[clang::annotate("lifetime_params", "a", "b")]] S_param {};
487
Martin Brænne8bc2de32022-06-24 07:01:52 -0700488 void f(S_param $3(a, b, c) s);
Martin Brænne9fb786f2022-06-23 01:18:19 -0700489 )")),
Martin Brænne2af40a02022-06-27 01:28:16 -0700490 IsOkAndHolds(LifetimesAre({{"f",
491 "ERROR: Type has 2 lifetime parameters but 3 "
492 "lifetime arguments were given"}})));
Martin Brænne9fb786f2022-06-23 01:18:19 -0700493}
494
Martin Brænne8bc2de32022-06-24 07:01:52 -0700495TEST_F(
496 LifetimeAnnotationsTest,
497 LifetimeAnnotation_LifetimeParameterizedType_Invalid_MultipleAnnotateAttributes) {
Martin Brænne2af40a02022-06-27 01:28:16 -0700498 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Martin Brænne8bc2de32022-06-24 07:01:52 -0700499 struct [[clang::annotate("lifetime_params", "a", "b")]] S_param {};
500
501 void f(S_param $a $b s);
502 )")),
Martin Brænne2af40a02022-06-27 01:28:16 -0700503 IsOkAndHolds(LifetimesAre(
504 {{"f",
505 "ERROR: Only one `[[annotate_type(\"lifetime\", ...)]]` "
506 "attribute may be placed on a type"}})));
Martin Brænne8bc2de32022-06-24 07:01:52 -0700507}
508
Martin Brænne9fb786f2022-06-23 01:18:19 -0700509TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_Template) {
510 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
511 template <class T> class vector {};
512
513 [[clang::annotate("lifetimes", "(a, b) -> a")]]
514 int* f1(const vector<int *> &);
515 int* $a f2(const vector<int * $a> & $b);
516 )")),
517 IsOkAndHolds(LifetimesAre(
518 {{"f1", "(a, b) -> a"}, {"f2", "(a, b) -> a"}})));
519}
520
521TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_VariadicTemplate) {
522 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"code(
523 template <class... T> class variadic{};
524
525 [[clang::annotate("lifetimes", "(<a, b>, c)")]]
526 void f1(const variadic<int *, int *> &);
527 void f2(const variadic<int * $a, int * $b> & $c);
528 )code")),
529 IsOkAndHolds(LifetimesAre(
530 {{"f1", "(<a, b>, c)"}, {"f2", "(<a, b>, c)"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000531}
532
Martin Brænne33f4f502022-06-27 01:15:15 -0700533TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_VariadicTemplateWithCtor) {
Martin Brænne33f4f502022-06-27 01:15:15 -0700534 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"code(
535 template <typename... Args> struct S { S() $a {} };
536 template <typename T, typename... Args>
537 struct S<T, Args...> {
538 S(T t, Args... args) $a {}
539 };
540
Martin Brænnebd003e92022-06-27 23:22:27 -0700541 void target(int* $a a, int* $b b) {
Martin Brænne33f4f502022-06-27 01:15:15 -0700542 S<int*, int*> s = {a, b};
543 }
544 )code")),
Martin Brænnebd003e92022-06-27 23:22:27 -0700545 IsOkAndHolds(LifetimesAre({{"S::S<Args...>", "a:"},
546 {"S<type-parameter-0-0, "
547 "type-parameter-0-1...>::"
548 "S<type-parameter-0-0, "
549 "type-parameter-0-1...>",
550 "a: (), ()"},
551 {"target", "a, b"}})));
Martin Brænne33f4f502022-06-27 01:15:15 -0700552}
553
Googler8a8e82e2022-02-28 14:53:56 +0000554TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_Method) {
Martin Brænne9fb786f2022-06-23 01:18:19 -0700555 EXPECT_THAT(
556 GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Googler8a8e82e2022-02-28 14:53:56 +0000557 struct S {
558 [[clang::annotate("lifetimes", "a: -> a")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700559 int* f1();
560 int* $a f2() $a;
Googler8a8e82e2022-02-28 14:53:56 +0000561 };
Martin Brænne9fb786f2022-06-23 01:18:19 -0700562 )")),
563 IsOkAndHolds(LifetimesAre({{"S::f1", "a: -> a"}, {"S::f2", "a: -> a"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000564}
565
566TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_MethodWithParam) {
Martin Brænne9fb786f2022-06-23 01:18:19 -0700567 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Googler8a8e82e2022-02-28 14:53:56 +0000568 struct S {
569 [[clang::annotate("lifetimes", "a: b -> a")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700570 int* f1(int*);
571 int* $a f2(int* $b) $a;
Googler8a8e82e2022-02-28 14:53:56 +0000572 };
Martin Brænne9fb786f2022-06-23 01:18:19 -0700573 )")),
574 IsOkAndHolds(LifetimesAre(
575 {{"S::f1", "a: b -> a"}, {"S::f2", "a: b -> a"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000576}
577
Luca Versari95ce68f2022-03-24 14:44:19 +0000578TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_MethodWithLifetimeParams) {
Martin Brænne9fb786f2022-06-23 01:18:19 -0700579 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Luca Versari95ce68f2022-03-24 14:44:19 +0000580 struct [[clang::annotate("lifetime_params", "x", "y")]] S {
Luca Versari6ee6b342022-04-05 05:40:52 -0700581 [[clang::annotate("lifetimes", "([x, y], a): -> x")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700582 int* f1();
583 // It's implied that the lifetime parameters of `this` are $x and $y
584 // because this is a member function on struct with those lifetime
585 // parameters.
586 // TODO(mboehme): This doesn't work yet. We need some special handling
587 // to know that in this context, the type `S` doesn't need lifetimes
588 // put on it.
589 // TODO(mboehme): How do we resolve this difference relative to the
590 // "legacy" lifetime annotations? Does this mean that they should also
591 // not include the lifetimes x and y?
592 // int* $x f2() $a;
Luca Versari95ce68f2022-03-24 14:44:19 +0000593 };
Martin Brænne9fb786f2022-06-23 01:18:19 -0700594 )")),
595 IsOkAndHolds(LifetimesAre({{"S::f1", "([x, y], a): -> x"}})));
Luca Versari95ce68f2022-03-24 14:44:19 +0000596}
597
Googler8a8e82e2022-02-28 14:53:56 +0000598TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_Invalid_MissingThis) {
Martin Brænne2af40a02022-06-27 01:28:16 -0700599 EXPECT_THAT(
600 GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Googler8a8e82e2022-02-28 14:53:56 +0000601 struct S {
602 [[clang::annotate("lifetimes", "-> a")]]
603 int* f();
604 };
Martin Brænne9fb786f2022-06-23 01:18:19 -0700605 )")),
Martin Brænne2af40a02022-06-27 01:28:16 -0700606 IsOkAndHolds(LifetimesAre(
607 {{"S::f",
608 "ERROR: Invalid lifetime annotation: too few lifetimes"}})));
Martin Brænne9fb786f2022-06-23 01:18:19 -0700609 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
610 struct S {
611 int* $a f();
612 };
613 )")),
Martin Brænne2af40a02022-06-27 01:28:16 -0700614 IsOkAndHolds(LifetimesAre(
615 {{"S::f", "ERROR: Lifetime elision not enabled for 'f'"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000616}
617
618TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_Invalid_ThisOnFreeFunction) {
Martin Brænne2af40a02022-06-27 01:28:16 -0700619 EXPECT_THAT(
620 GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Googler8a8e82e2022-02-28 14:53:56 +0000621 [[clang::annotate("lifetimes", "a: a -> a")]]
622 int* f(int*);
Martin Brænne9fb786f2022-06-23 01:18:19 -0700623 )")),
Martin Brænne2af40a02022-06-27 01:28:16 -0700624 IsOkAndHolds(LifetimesAre(
625 {{"f", "ERROR: Invalid lifetime annotation: too many lifetimes"}})));
626 EXPECT_THAT(
627 GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Martin Brænne9fb786f2022-06-23 01:18:19 -0700628 int* $a f(int* $a) $a;
629 )")),
Martin Brænne2af40a02022-06-27 01:28:16 -0700630 IsOkAndHolds(LifetimesAre({{"f",
631 "ERROR: Encountered a `this` lifetime on a "
632 "function with no `this` parameter"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000633}
634
635TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_Invalid_WrongNumber) {
Martin Brænne2af40a02022-06-27 01:28:16 -0700636 EXPECT_THAT(
637 GetNamedLifetimeAnnotations(R"(
Googler8a8e82e2022-02-28 14:53:56 +0000638 [[clang::annotate("lifetimes", "a -> a")]]
639 int* f(int**);
640 )"),
Martin Brænne2af40a02022-06-27 01:28:16 -0700641 IsOkAndHolds(LifetimesAre(
642 {{"f", "ERROR: Invalid lifetime annotation: too few lifetimes"}})));
Googler8a8e82e2022-02-28 14:53:56 +0000643}
644
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700645TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_Callback) {
646 EXPECT_THAT(
Martin Brænne9fb786f2022-06-23 01:18:19 -0700647 GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700648 [[clang::annotate("lifetimes", "b, ((a -> a), static) -> b")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700649 int* f1(int*, int* (*)(int*));
650 int* $b f2(int* $b, int* $a (* $static)(int* $a));
651 )")),
652 IsOkAndHolds(LifetimesAre({{"f1", "b, ((a -> a), static) -> b"},
653 {"f2", "b, ((a -> a), static) -> b"}})));
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700654}
655
656TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_CallbackMultipleParams) {
657 EXPECT_THAT(
Martin Brænne9fb786f2022-06-23 01:18:19 -0700658 GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700659 [[clang::annotate("lifetimes", "c, ((a, b -> a), static) -> c")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700660 int* f1(int*, int* (*)(int*, int*));
661 int* $c f2(int* $c, int* $a (* $static)(int* $a, int* $b));
662 )")),
663 IsOkAndHolds(LifetimesAre({{"f1", "c, ((a, b -> a), static) -> c"},
664 {"f2", "c, ((a, b -> a), static) -> c"}})));
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700665}
666
667TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_CallbackTmplFunc) {
Martin Brænne9fb786f2022-06-23 01:18:19 -0700668 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700669 template <typename Func>
670 struct function;
671 [[clang::annotate("lifetimes", "a, ((b -> b)) -> a")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700672 int* f1(int*, function<int*(int*)>);
673 int* $a f2(int* $a, function<int* $b(int* $b)>);
674 )")),
675 IsOkAndHolds(LifetimesAre({{"f1", "a, ((b -> b)) -> a"},
676 {"f2", "a, ((b -> b)) -> a"}})));
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700677}
678
679TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_MultipleCallbacks) {
Martin Brænne9fb786f2022-06-23 01:18:19 -0700680 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"(
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700681 [[clang::annotate("lifetimes", "a, ((b -> b), static), ((c -> c), static) -> a")]]
Martin Brænne9fb786f2022-06-23 01:18:19 -0700682 int* f1(int*, int* (*)(int*), int* (*)(int*));
683 int* $a f2(int* $a, int* $b (* $static)(int* $b), int* $c (* $static)(int* $c));
684 )")),
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700685 IsOkAndHolds(LifetimesAre(
Martin Brænne9fb786f2022-06-23 01:18:19 -0700686 {{"f1", "a, ((b -> b), static), ((c -> c), static) -> a"},
687 {"f2", "a, ((b -> b), static), ((c -> c), static) -> a"}})));
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700688}
689
690TEST_F(LifetimeAnnotationsTest, LifetimeAnnotation_ReturnFunctionPtr) {
Martin Brænne9fb786f2022-06-23 01:18:19 -0700691 EXPECT_THAT(GetNamedLifetimeAnnotations(WithLifetimeMacros(R"_(
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700692 typedef int* (*FP)(int*);
693 [[clang::annotate("lifetimes", "a -> ((b -> b), static)")]]
694 FP f(int*);
Martin Brænne9fb786f2022-06-23 01:18:19 -0700695 // TODO(mboehme): Need to support lifetime parameters on type aliases to
696 // be able to express this in the new syntax.
697 )_")),
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700698 IsOkAndHolds(LifetimesAre({{"f", "a -> ((b -> b), static)"}})));
699}
700
Googlerb0019ca2021-11-26 14:20:10 +0000701} // namespace
Martin Brænne1a207c52022-04-19 00:05:38 -0700702} // namespace lifetimes
703} // namespace tidy
704} // namespace clang