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: |
11 | unique_ptr(gsl::owner<T> resource) : memory(resource) {} |
12 | unique_ptr(const unique_ptr<T> &) = default; |
13 | |
14 | ~unique_ptr() { delete memory; } |
15 | |
16 | private: |
17 | gsl::owner<T> memory; |
18 | }; |
19 | |
20 | void takes_owner(gsl::owner<int *> owned_int) { |
21 | } |
22 | |
23 | void takes_pointer(int *unowned_int) { |
24 | } |
25 | |
26 | void takes_owner_and_more(int some_int, gsl::owner<int *> owned_int, float f) { |
27 | } |
28 | |
29 | template <typename T> |
30 | void takes_templated_owner(gsl::owner<T> owned_T) { |
31 | } |
32 | |
33 | gsl::owner<int *> returns_owner1() { return gsl::owner<int *>(new int(42)); } // Ok |
34 | gsl::owner<int *> returns_owner2() { return new int(42); } // Ok |
35 | |
36 | int *returns_no_owner1() { return nullptr; } |
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 | } |
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 | } |
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 | |
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. |
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 | |
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 | |
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 | |
153 | void test_owner_function_calls() { |
154 | int stack_int = 42; |
155 | int *unowned_int1 = &stack_int; |
156 | takes_owner(owned_int: &stack_int); // BAD |
157 | // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *' |
158 | takes_owner(owned_int: 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_int: owned_int1); // Ok |
163 | |
164 | takes_owner_and_more(some_int: 42, owned_int: &stack_int, f: 42.0f); // BAD |
165 | // CHECK-NOTES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *' |
166 | takes_owner_and_more(some_int: 42, owned_int: unowned_int1, f: 42.0f); // BAD |
167 | // CHECK-NOTES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *' |
168 | |
169 | takes_owner_and_more(some_int: 42, owned_int: new int(42), f: 42.0f); // Ok, since new is consumed by owner |
170 | takes_owner_and_more(some_int: 42, owned_int: owned_int1, f: 42.0f); // Ok, since owner as argument |
171 | |
172 | takes_templated_owner(owned_T: owned_int1); // Ok |
173 | takes_templated_owner(owned_T: new int(42)); // Ok |
174 | takes_templated_owner(owned_T: unowned_int1); // Bad |
175 | // CHECK-NOTES: [[@LINE-1]]:25: warning: expected argument of type 'gsl::owner<>'; got 'int *' |
176 | |
177 | takes_owner(owned_int: returns_owner1()); // Ok |
178 | takes_owner(owned_int: returns_no_owner1()); // BAD |
179 | // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *' |
180 | } |
181 | |
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(unowned_int: &stack_int); // Ok |
188 | takes_pointer(unowned_int: unowned_int1); // Ok |
189 | takes_pointer(unowned_int: owned_int1); // Ok |
190 | takes_pointer(unowned_int: 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(unowned_int: 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(unowned_int: 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 |
235 | ClassWithOwner() : owner_var(nullptr) {} // Ok |
236 | |
237 | 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 | |
240 | ClassWithOwner(gsl::owner<ArbitraryClass *> other) : owner_var(other) {} // Ok |
241 | |
242 | ClassWithOwner(gsl::owner<ArbitraryClass *> data, int /* unused */) { // Ok |
243 | owner_var = data; // Ok |
244 | } |
245 | |
246 | 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 | |
251 | ClassWithOwner(ClassWithOwner &&other) : owner_var{other.owner_var} {} // Ok |
252 | |
253 | 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. |
260 | 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 | |
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 |
298 | HeapArray() : _data(nullptr), size(0) {} // Ok |
299 | HeapArray(int size) : _data(new int[size]), size(size) {} // Ok |
300 | 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 | } |
306 | 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 | |
310 | HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok |
311 | other._data = nullptr; // Ok |
312 | other.size = 0; |
313 | } |
314 | |
315 | HeapArray<T> &operator=(HeapArray<T> &&other) { |
316 | _data = other._data; // Ok, NOLINT warning here about bad types, why? |
317 | size = other.size; |
318 | return *this; |
319 | } |
320 | |
321 | ~HeapArray() { delete[] _data; } // Ok |
322 | |
323 | T *data() { return _data; } // Ok NOLINT, because it "looks" like a factory |
324 | |
325 | gsl::owner<T *> _data; |
326 | unsigned int size; |
327 | }; |
328 | |
329 | void test_inner_template() { |
330 | HeapArray<int> Array1; |
331 | HeapArray<int> Array2(100); |
332 | HeapArray<int> Array3(100, 0); |
333 | HeapArray<int> Array4(100, 0, nullptr); |
334 | |
335 | Array1 = static_cast<HeapArray<int> &&>(Array2); |
336 | HeapArray<int> Array5(static_cast<HeapArray<int> &&>(Array3)); |
337 | |
338 | int *NonOwningPtr = Array1.data(); // Ok |
339 | gsl::owner<int *> OwningPtr = Array1.data(); // Bad, since it does not return the owner |
340 | // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *' |
341 | } |
342 | |
343 | // FIXME: Typededuction removes the owner - wrapper, therefore gsl::owner can not be used |
344 | // with Template classes like this. Is there a walkaround? |
345 | template <typename T> |
346 | struct TemplateValue { |
347 | TemplateValue() = default; |
348 | TemplateValue(T t) : val{t} {} |
349 | |
350 | void setVal(const T &t) { val = t; } |
351 | const T getVal() const { return val; } |
352 | |
353 | T val; |
354 | }; |
355 | |
356 | // FIXME: Same typededcution problems |
357 | template <typename T> |
358 | void template_function(T t) { |
359 | gsl::owner<int *> owner_t = t; // Probably bad, since type deduction still wrong |
360 | // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'T' |
361 | // CHECK-NOTES: [[@LINE-2]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *' |
362 | } |
363 | |
364 | // FIXME: Same typededcution problems |
365 | void test_templates() { |
366 | int stack_int = 42; |
367 | int *stack_ptr1 = &stack_int; |
368 | |
369 | TemplateValue<gsl::owner<int *>> Owner0; // Ok, T should be owner, but is int* |
370 | |
371 | TemplateValue<gsl::owner<int *>> Owner1(new int(42)); // Ok, T should be owner, but is int* |
372 | Owner1.setVal(&stack_int); // Bad since non-owner assignment |
373 | Owner1.setVal(stack_ptr1); // Bad since non-owner assignment |
374 | //Owner1.setVal(new int(42)); // Ok, but since type deduction is wrong, this one is considered harmful |
375 | |
376 | int *stack_ptr2 = Owner1.getVal(); // Bad, initializing non-owner with owner |
377 | |
378 | TemplateValue<int *> NonOwner1(new int(42)); // Bad, T is int *, hence dynamic memory to non-owner |
379 | gsl::owner<int *> IntOwner1 = NonOwner1.getVal(); // Bad, since owner initialized with non-owner |
380 | // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *' |
381 | |
382 | template_function(t: IntOwner1); // Ok, but not actually ok, since type deduction removes owner |
383 | template_function(t: stack_ptr1); // Bad, but type deduction gets it wrong |
384 | } |
385 | |
386 | namespace PR63994 { |
387 | struct A { |
388 | virtual ~A() {} |
389 | }; |
390 | |
391 | struct B : public A {}; |
392 | |
393 | A* foo(int x) { |
394 | return new B; |
395 | // 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<>' |
396 | } |
397 | } |
398 | |
399 | namespace PR59389 { |
400 | struct S { |
401 | S(); |
402 | S(int); |
403 | |
404 | int value = 1; |
405 | }; |
406 | |
407 | void testLambdaInFunctionNegative() { |
408 | const auto MakeS = []() -> ::gsl::owner<S*> { |
409 | return ::gsl::owner<S*>{new S{}}; |
410 | }; |
411 | } |
412 | |
413 | void testLambdaInFunctionPositive() { |
414 | const auto MakeS = []() -> S* { |
415 | return ::gsl::owner<S*>{new S{}}; |
416 | // 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<>' |
417 | }; |
418 | } |
419 | |
420 | void testFunctionInFunctionNegative() { |
421 | struct C { |
422 | ::gsl::owner<S*> test() { |
423 | return ::gsl::owner<S*>{new S{}}; |
424 | } |
425 | }; |
426 | } |
427 | |
428 | void testFunctionInFunctionPositive() { |
429 | struct C { |
430 | S* test() { |
431 | return ::gsl::owner<S*>{new S{}}; |
432 | // 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<>' |
433 | } |
434 | }; |
435 | } |
436 | |
437 | ::gsl::owner<S*> testReverseLambdaNegative() { |
438 | const auto MakeI = [] -> int { return 5; }; |
439 | return ::gsl::owner<S*>{new S(MakeI())}; |
440 | } |
441 | |
442 | S* testReverseLambdaPositive() { |
443 | const auto MakeI = [] -> int { return 5; }; |
444 | return ::gsl::owner<S*>{new S(MakeI())}; |
445 | // 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<>' |
446 | } |
447 | |
448 | ::gsl::owner<S*> testReverseFunctionNegative() { |
449 | struct C { |
450 | int test() { return 5; } |
451 | }; |
452 | return ::gsl::owner<S*>{new S(C().test())}; |
453 | } |
454 | |
455 | S* testReverseFunctionPositive() { |
456 | struct C { |
457 | int test() { return 5; } |
458 | }; |
459 | return ::gsl::owner<S*>{new S(C().test())}; |
460 | // 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<>' |
461 | } |
462 | |
463 | void testLambdaInLambdaNegative() { |
464 | const auto MakeS = []() -> ::gsl::owner<S*> { |
465 | const auto MakeI = []() -> int { return 5; }; |
466 | return ::gsl::owner<S*>{new S(MakeI())}; |
467 | }; |
468 | } |
469 | |
470 | void testLambdaInLambdaPositive() { |
471 | const auto MakeS = []() -> S* { |
472 | const auto MakeI = []() -> int { return 5; }; |
473 | return ::gsl::owner<S*>{new S(MakeI())}; |
474 | // 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<>' |
475 | }; |
476 | } |
477 | |
478 | void testLambdaInLambdaWithDoubleReturns() { |
479 | const auto MakeS = []() -> S* { |
480 | const auto MakeS2 = []() -> S* { |
481 | return ::gsl::owner<S*>{new S(1)}; |
482 | // 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] |
483 | }; |
484 | return ::gsl::owner<S*>{new S(2)}; |
485 | // 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<>' |
486 | }; |
487 | } |
488 | |
489 | void testReverseLambdaInLambdaNegative() { |
490 | const auto MakeI = []() -> int { |
491 | const auto MakeS = []() -> ::gsl::owner<S*> { return new S(); }; |
492 | return 5; |
493 | }; |
494 | } |
495 | |
496 | void testReverseLambdaInLambdaPositive() { |
497 | const auto MakeI = []() -> int { |
498 | const auto MakeS = []() -> S* { return new S(); }; |
499 | // 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<>' |
500 | return 5; |
501 | }; |
502 | } |
503 | } |
504 | |