xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp (revision 8009bbec59d1c5d47ae06c431647ebee6d886ff2)
1 // RUN: %check_clang_tidy %s cppcoreguidelines-owning-memory %t
2 
3 namespace gsl {
4 template <class T>
5 using owner = T;
6 } // namespace gsl
7 
8 template <typename T>
9 class unique_ptr {
10 public:
unique_ptr(gsl::owner<T> resource)11   unique_ptr(gsl::owner<T> resource) : memory(resource) {}
12   unique_ptr(const unique_ptr<T> &) = default;
13 
~unique_ptr()14   ~unique_ptr() { delete memory; }
15 
16 private:
17   gsl::owner<T> memory;
18 };
19 
takes_owner(gsl::owner<int * > owned_int)20 void takes_owner(gsl::owner<int *> owned_int) {
21 }
22 
takes_pointer(int * unowned_int)23 void takes_pointer(int *unowned_int) {
24 }
25 
takes_owner_and_more(int some_int,gsl::owner<int * > owned_int,float f)26 void takes_owner_and_more(int some_int, gsl::owner<int *> owned_int, float f) {
27 }
28 
29 template <typename T>
takes_templated_owner(gsl::owner<T> owned_T)30 void takes_templated_owner(gsl::owner<T> owned_T) {
31 }
32 
returns_owner1()33 gsl::owner<int *> returns_owner1() { return gsl::owner<int *>(new int(42)); } // Ok
returns_owner2()34 gsl::owner<int *> returns_owner2() { return new int(42); }                    // Ok
35 
returns_no_owner1()36 int *returns_no_owner1() { return nullptr; }
returns_no_owner2()37 int *returns_no_owner2() {
38   return new int(42);
39   // CHECK-NOTES: [[@LINE-1]]:3: warning: returning a newly created resource of type 'int *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
40 }
returns_no_owner3()41 int *returns_no_owner3() {
42   int *should_be_owner = new int(42);
43   // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
44   return should_be_owner;
45 }
returns_no_owner4()46 int *returns_no_owner4() {
47   gsl::owner<int *> owner = new int(42);
48   return owner;
49   // CHECK-NOTES: [[@LINE-1]]:3: warning: returning a newly created resource of type 'int *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
50 }
51 
returns_no_owner5()52 unique_ptr<int *> returns_no_owner5() {
53   return unique_ptr<int *>(new int(42)); // Ok
54 }
55 
56 /// FIXME: CSA finds it, but the report is misleading. Ownersemantics can catch this
57 /// by flow analysis similar to bugprone-use-after-move.
csa_not_finding_leak()58 void csa_not_finding_leak() {
59   gsl::owner<int *> o1 = new int(42); // Ok
60 
61   gsl::owner<int *> o2 = o1; // Ok
62   o2 = new int(45);          // conceptual leak, the memory from o1 is now leaked, since its considered moved in the guidelines
63 
64   delete o2;
65   // actual leak occurs here, its found, but mixed
66   delete o1;
67 }
68 
test_assignment_and_initialization()69 void test_assignment_and_initialization() {
70   int stack_int1 = 15;
71   int stack_int2;
72 
73   gsl::owner<int *> owned_int1 = &stack_int1; // BAD
74   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
75 
76   gsl::owner<int *> owned_int2;
77   owned_int2 = &stack_int2; // BAD since no owner, bad since uninitialized
78   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
79 
80   gsl::owner<int *> owned_int3 = new int(42); // Good
81   owned_int3 = nullptr;                       // Good
82 
83   gsl::owner<int *> owned_int4(nullptr); // Ok
84   owned_int4 = new int(42);              // Good
85 
86   gsl::owner<int *> owned_int5 = owned_int3; // Good
87 
88   gsl::owner<int *> owned_int6{nullptr}; // Ok
89   owned_int6 = owned_int4;               // Good
90 
91   // FIXME:, flow analysis for the case of reassignment. Value must be released before
92   owned_int6 = owned_int3; // BAD, because reassignment without resource release
93 
94   auto owned_int7 = returns_owner1(); // Ok, since type deduction does not eliminate the owner wrapper
95 
96   const auto owned_int8 = returns_owner2(); // Ok, since type deduction does not eliminate the owner wrapper
97 
98   gsl::owner<int *> owned_int9 = returns_owner1(); // Ok
99   int *unowned_int3 = returns_owner1();            // Bad
100   // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
101 
102   gsl::owner<int *> owned_int10;
103   owned_int10 = returns_owner1(); // Ok
104 
105   int *unowned_int4;
106   unowned_int4 = returns_owner1(); // Bad
107   // CHECK-NOTES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
108 
109   gsl::owner<int *> owned_int11 = returns_no_owner1(); // Bad since no owner
110   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
111 
112   gsl::owner<int *> owned_int12;
113   owned_int12 = returns_no_owner1(); // Bad since no owner
114   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
115 
116   int *unowned_int5 = returns_no_owner1(); // Ok
117   int *unowned_int6;
118   unowned_int6 = returns_no_owner1(); // Ok
119 
120   int *unowned_int7 = new int(42); // Bad, since resource not assigned to an owner
121   // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
122 
123   int *unowned_int8;
124   unowned_int8 = new int(42);
125   // CHECK-NOTES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
126 
127   gsl::owner<int *> owned_int13 = nullptr; // Ok
128 }
129 
test_deletion()130 void test_deletion() {
131   gsl::owner<int *> owned_int1 = new int(42);
132   delete owned_int1; // Good
133 
134   gsl::owner<int *> owned_int2 = new int[42];
135   delete[] owned_int2; // Good
136 
137   int *unowned_int1 = new int(42); // BAD, since new creates and owner
138   // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
139   delete unowned_int1; // BAD, since no owner
140   // CHECK-NOTES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
141   // CHECK-NOTES: [[@LINE-4]]:3: note: variable declared here
142 
143   int *unowned_int2 = new int[42]; // BAD, since new creates and owner
144   // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
145   delete[] unowned_int2; // BAD since no owner
146   // CHECK-NOTES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
147   // CHECK-NOTES: [[@LINE-4]]:3: note: variable declared here
148 
149   delete new int(42);   // Technically ok, but stupid
150   delete[] new int[42]; // Technically ok, but stupid
151 }
152 
test_owner_function_calls()153 void test_owner_function_calls() {
154   int stack_int = 42;
155   int *unowned_int1 = &stack_int;
156   takes_owner(&stack_int); // BAD
157   // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
158   takes_owner(unowned_int1); // BAD
159   // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
160 
161   gsl::owner<int *> owned_int1 = new int(42);
162   takes_owner(owned_int1); // Ok
163 
164   takes_owner_and_more(42, &stack_int, 42.0f); // BAD
165   // CHECK-NOTES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *'
166   takes_owner_and_more(42, unowned_int1, 42.0f); // BAD
167   // CHECK-NOTES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *'
168 
169   takes_owner_and_more(42, new int(42), 42.0f); // Ok, since new is consumed by owner
170   takes_owner_and_more(42, owned_int1, 42.0f);  // Ok, since owner as argument
171 
172   takes_templated_owner(owned_int1);   // Ok
173   takes_templated_owner(new int(42));  // Ok
174   takes_templated_owner(unowned_int1); // Bad
175   // CHECK-NOTES: [[@LINE-1]]:25: warning: expected argument of type 'gsl::owner<>'; got 'int *'
176 
177   takes_owner(returns_owner1());    // Ok
178   takes_owner(returns_no_owner1()); // BAD
179   // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
180 }
181 
test_unowned_function_calls()182 void test_unowned_function_calls() {
183   int stack_int = 42;
184   int *unowned_int1 = &stack_int;
185   gsl::owner<int *> owned_int1 = new int(42);
186 
187   takes_pointer(&stack_int);   // Ok
188   takes_pointer(unowned_int1); // Ok
189   takes_pointer(owned_int1);   // Ok
190   takes_pointer(new int(42));  // Bad, since new creates and owner
191   // CHECK-NOTES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
192 
193   takes_pointer(returns_owner1()); // Bad
194   // CHECK-NOTES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
195 
196   takes_pointer(returns_no_owner1()); // Ok
197 }
198 
199 // FIXME: Typedefing owner<> to something else does not work.
200 // This might be necessary for code already having a similar typedef like owner<> and
201 // replacing it with owner<>. This might be the same problem as with templates.
202 // The canonical type will ignore the owner<> alias, since its a typedef as well.
203 //
204 // Check, if owners hidden by typedef are handled the same as 'obvious' owners.
205 #if 0
206 using heap_int = gsl::owner<int *>;
207 typedef gsl::owner<float *> heap_float;
208 
209 // This tests only a subset, assuming that the check will either see through the
210 // typedef or not (it doesn't!).
211 void test_typedefed_values() {
212   // Modern typedef.
213   int StackInt1 = 42;
214   heap_int HeapInt1 = &StackInt1;
215   // CHECK MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
216 
217   //FIXME: Typedef not considered correctly here.
218   // heap_int HeapInt2 = new int(42); // Ok
219   takes_pointer(HeapInt1); // Ok
220   takes_owner(HeapInt1);   // Ok
221 
222   // Traditional typedef.
223   float StackFloat1 = 42.0f;
224   heap_float HeapFloat1 = &StackFloat1;
225   // CHECK MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'float *'
226 
227   //FIXME: Typedef not considered correctly here.
228   // heap_float HeapFloat2 = new float(42.0f);
229   HeapFloat2 = HeapFloat1; // Ok
230 }
231 #endif
232 
233 struct ArbitraryClass {};
234 struct ClassWithOwner {                    // Does not define destructor, necessary with owner
ClassWithOwnerClassWithOwner235   ClassWithOwner() : owner_var(nullptr) {} // Ok
236 
ClassWithOwnerClassWithOwner237   ClassWithOwner(ArbitraryClass &other) : owner_var(&other) {}
238   // CHECK-NOTES: [[@LINE-1]]:43: warning: expected initialization of owner member variable with value of type 'gsl::owner<>'; got 'ArbitraryClass *'
239 
ClassWithOwnerClassWithOwner240   ClassWithOwner(gsl::owner<ArbitraryClass *> other) : owner_var(other) {} // Ok
241 
ClassWithOwnerClassWithOwner242   ClassWithOwner(gsl::owner<ArbitraryClass *> data, int /* unused */) { // Ok
243     owner_var = data;                                                   // Ok
244   }
245 
ClassWithOwnerClassWithOwner246   ClassWithOwner(ArbitraryClass *bad_data, int /* unused */, int /* unused */) {
247     owner_var = bad_data;
248     // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
249   }
250 
ClassWithOwnerClassWithOwner251   ClassWithOwner(ClassWithOwner &&other) : owner_var{other.owner_var} {} // Ok
252 
operator =ClassWithOwner253   ClassWithOwner &operator=(ClassWithOwner &&other) {
254     owner_var = other.owner_var; // Ok
255     return *this;
256   }
257 
258   // Returning means, that the owner is "moved", so the class should not access this
259   // variable anymore after this method gets called.
buggy_but_returns_ownerClassWithOwner260   gsl::owner<ArbitraryClass *> buggy_but_returns_owner() { return owner_var; }
261 
262   gsl::owner<ArbitraryClass *> owner_var;
263   // CHECK-NOTES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'ClassWithOwner' to implement a destructor to release the owned resource
264 };
265 
266 class DefaultedDestructor {         // Bad since default constructor with owner
267   ~DefaultedDestructor() = default; // Bad, since will not destroy the owner
268   gsl::owner<int *> Owner;
269   // CHECK-NOTES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'DefaultedDestructor' to implement a destructor to release the owned resource
270 };
271 
272 struct DeletedDestructor {
273   ~DeletedDestructor() = delete;
274   gsl::owner<int *> Owner;
275   // CHECK-NOTES: [[@LINE-1]]:3: warning: member variable of type 'gsl::owner<>' requires the class 'DeletedDestructor' to implement a destructor to release the owned resource
276 };
277 
test_class_with_owner()278 void test_class_with_owner() {
279   ArbitraryClass A;
280   ClassWithOwner C1;                                                   // Ok
281   ClassWithOwner C2{A};                                                // Bad, since the owner would be initialized with an non-owner, but catched in the class
282   ClassWithOwner C3{gsl::owner<ArbitraryClass *>(new ArbitraryClass)}; // Ok
283 
284   const auto Owner1 = C3.buggy_but_returns_owner(); // Ok, deduces Owner1 to owner<ArbitraryClass *> const
285 
286   auto Owner2 = C2.buggy_but_returns_owner(); // Ok, deduces Owner2 to owner<ArbitraryClass *>
287 
288   Owner2 = &A; // BAD, since type deduction resulted in owner<ArbitraryClass *>
289   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
290 
291   gsl::owner<ArbitraryClass *> Owner3 = C1.buggy_but_returns_owner(); // Ok, still an owner
292   Owner3 = &A;                                                        // Bad, since assignment of non-owner to owner
293   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
294 }
295 
296 template <typename T>
297 struct HeapArray {                                          // Ok, since destructor with owner
HeapArrayHeapArray298   HeapArray() : _data(nullptr), size(0) {}                  // Ok
HeapArrayHeapArray299   HeapArray(int size) : _data(new int[size]), size(size) {} // Ok
HeapArrayHeapArray300   HeapArray(int size, T val) {
301     _data = new int[size]; // Ok
302     size = size;
303     for (auto i = 0u; i < size; ++i)
304       _data[i] = val; // Ok
305   }
HeapArrayHeapArray306   HeapArray(int size, T val, int *problematic) : _data{problematic}, size(size) {} // Bad
307   // CHECK-NOTES: [[@LINE-1]]:50: warning: expected initialization of owner member variable with value of type 'gsl::owner<>'; got 'void'
308   // FIXME: void is incorrect type, probably wrong thing matched
309 
HeapArrayHeapArray310   HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok
311     other._data = nullptr;                                              // Ok
312     // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'std::nullptr_t'
313     // FIXME: This warning is emitted because an ImplicitCastExpr for the NullToPointer conversion isn't created for dependent types.
314     other.size = 0;
315   }
316 
operator =HeapArray317   HeapArray<T> &operator=(HeapArray<T> &&other) {
318     _data = other._data; // Ok, NOLINT warning here about bad types, why?
319     size = other.size;
320     return *this;
321   }
322 
~HeapArrayHeapArray323   ~HeapArray() { delete[] _data; } // Ok
324 
dataHeapArray325   T *data() { return _data; } // Ok NOLINT, because it "looks" like a factory
326 
327   gsl::owner<T *> _data;
328   unsigned int size;
329 };
330 
test_inner_template()331 void test_inner_template() {
332   HeapArray<int> Array1;
333   HeapArray<int> Array2(100);
334   HeapArray<int> Array3(100, 0);
335   HeapArray<int> Array4(100, 0, nullptr);
336 
337   Array1 = static_cast<HeapArray<int> &&>(Array2);
338   HeapArray<int> Array5(static_cast<HeapArray<int> &&>(Array3));
339 
340   int *NonOwningPtr = Array1.data();           // Ok
341   gsl::owner<int *> OwningPtr = Array1.data(); // Bad, since it does not return the owner
342   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
343 }
344 
345 // FIXME: Typededuction removes the owner - wrapper, therefore gsl::owner can not be used
346 // with Template classes like this. Is there a walkaround?
347 template <typename T>
348 struct TemplateValue {
349   TemplateValue() = default;
TemplateValueTemplateValue350   TemplateValue(T t) : val{t} {}
351 
setValTemplateValue352   void setVal(const T &t) { val = t; }
getValTemplateValue353   const T getVal() const { return val; }
354 
355   T val;
356 };
357 
358 // FIXME: Same typededcution problems
359 template <typename T>
template_function(T t)360 void template_function(T t) {
361   gsl::owner<int *> owner_t = t; // Probably bad, since type deduction still wrong
362   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'T'
363   // CHECK-NOTES: [[@LINE-2]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
364 }
365 
366 // FIXME: Same typededcution problems
test_templates()367 void test_templates() {
368   int stack_int = 42;
369   int *stack_ptr1 = &stack_int;
370 
371   TemplateValue<gsl::owner<int *>> Owner0; // Ok, T should be owner, but is int*
372 
373   TemplateValue<gsl::owner<int *>> Owner1(new int(42)); // Ok, T should be owner, but is int*
374   Owner1.setVal(&stack_int);                            // Bad since non-owner assignment
375   Owner1.setVal(stack_ptr1);                            // Bad since non-owner assignment
376   //Owner1.setVal(new int(42)); // Ok, but since type deduction is wrong, this one is considered harmful
377 
378   int *stack_ptr2 = Owner1.getVal(); // Bad, initializing non-owner with owner
379 
380   TemplateValue<int *> NonOwner1(new int(42));      // Bad, T is int *, hence dynamic memory to non-owner
381   gsl::owner<int *> IntOwner1 = NonOwner1.getVal(); // Bad, since owner initialized with non-owner
382   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
383 
384   template_function(IntOwner1);  // Ok, but not actually ok, since type deduction removes owner
385   template_function(stack_ptr1); // Bad, but type deduction gets it wrong
386 }
387 
388 namespace PR63994 {
389   struct A {
~APR63994::A390     virtual ~A() {}
391   };
392 
393   struct B : public A {};
394 
foo(int x)395   A* foo(int x) {
396     return new B;
397     // CHECK-NOTES: [[@LINE-1]]:5: warning: returning a newly created resource of type 'A *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
398   }
399 }
400 
401 namespace PR59389 {
402   struct S {
403     S();
404     S(int);
405 
406     int value = 1;
407   };
408 
testLambdaInFunctionNegative()409   void testLambdaInFunctionNegative() {
410     const auto MakeS = []() -> ::gsl::owner<S*> {
411       return ::gsl::owner<S*>{new S{}};
412     };
413   }
414 
testLambdaInFunctionPositive()415   void testLambdaInFunctionPositive() {
416     const auto MakeS = []() -> S* {
417       return ::gsl::owner<S*>{new S{}};
418       // CHECK-NOTES: [[@LINE-1]]:7: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'
419     };
420   }
421 
testFunctionInFunctionNegative()422   void testFunctionInFunctionNegative() {
423     struct C {
424       ::gsl::owner<S*> test() {
425         return ::gsl::owner<S*>{new S{}};
426       }
427     };
428   }
429 
testFunctionInFunctionPositive()430   void testFunctionInFunctionPositive() {
431     struct C {
432       S* test() {
433         return ::gsl::owner<S*>{new S{}};
434         // CHECK-NOTES: [[@LINE-1]]:9: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
435       }
436     };
437   }
438 
testReverseLambdaNegative()439   ::gsl::owner<S*> testReverseLambdaNegative() {
440     const auto MakeI = [] -> int { return 5; };
441     return ::gsl::owner<S*>{new S(MakeI())};
442   }
443 
testReverseLambdaPositive()444   S* testReverseLambdaPositive() {
445     const auto MakeI = [] -> int { return 5; };
446     return ::gsl::owner<S*>{new S(MakeI())};
447     // CHECK-NOTES: [[@LINE-1]]:5: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
448   }
449 
testReverseFunctionNegative()450   ::gsl::owner<S*> testReverseFunctionNegative() {
451     struct C {
452       int test() { return 5; }
453     };
454     return ::gsl::owner<S*>{new S(C().test())};
455   }
456 
testReverseFunctionPositive()457   S* testReverseFunctionPositive() {
458     struct C {
459       int test() { return 5; }
460     };
461     return ::gsl::owner<S*>{new S(C().test())};
462     // CHECK-NOTES: [[@LINE-1]]:5: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a function whose return type is not 'gsl::owner<>'
463   }
464 
testLambdaInLambdaNegative()465   void testLambdaInLambdaNegative() {
466     const auto MakeS = []() -> ::gsl::owner<S*> {
467       const auto MakeI = []() -> int { return 5; };
468       return ::gsl::owner<S*>{new S(MakeI())};
469     };
470   }
471 
testLambdaInLambdaPositive()472   void testLambdaInLambdaPositive() {
473     const auto MakeS = []() -> S* {
474       const auto MakeI = []() -> int { return 5; };
475       return ::gsl::owner<S*>{new S(MakeI())};
476       // CHECK-NOTES: [[@LINE-1]]:7: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'
477     };
478   }
479 
testLambdaInLambdaWithDoubleReturns()480   void testLambdaInLambdaWithDoubleReturns() {
481     const auto MakeS = []() -> S* {
482       const auto MakeS2 = []() -> S* {
483         return ::gsl::owner<S*>{new S(1)};
484         // CHECK-NOTES: [[@LINE-1]]:9: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>' [cppcoreguidelines-owning-memory]
485       };
486       return ::gsl::owner<S*>{new S(2)};
487       // CHECK-NOTES: [[@LINE-1]]:7: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'
488     };
489   }
490 
testReverseLambdaInLambdaNegative()491   void testReverseLambdaInLambdaNegative() {
492     const auto MakeI = []() -> int {
493       const auto MakeS = []() -> ::gsl::owner<S*> { return new S(); };
494       return 5;
495     };
496   }
497 
testReverseLambdaInLambdaPositive()498   void testReverseLambdaInLambdaPositive() {
499     const auto MakeI = []() -> int {
500       const auto MakeS = []() -> S* { return new S(); };
501       // CHECK-NOTES: [[@LINE-1]]:39: warning: returning a newly created resource of type 'S *' or 'gsl::owner<>' from a lambda whose return type is not 'gsl::owner<>'
502       return 5;
503     };
504   }
505 }
506