| 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 | // 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 | |
| 317 | 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 | |
| 323 | ~HeapArray() { delete[] _data; } // Ok |
| 324 | |
| 325 | T *data() { return _data; } // Ok NOLINT, because it "looks" like a factory |
| 326 | |
| 327 | gsl::owner<T *> _data; |
| 328 | unsigned int size; |
| 329 | }; |
| 330 | |
| 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; |
| 350 | TemplateValue(T t) : val{t} {} |
| 351 | |
| 352 | void setVal(const T &t) { val = t; } |
| 353 | const T getVal() const { return val; } |
| 354 | |
| 355 | T val; |
| 356 | }; |
| 357 | |
| 358 | // FIXME: Same typededcution problems |
| 359 | template <typename 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 |
| 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(t: IntOwner1); // Ok, but not actually ok, since type deduction removes owner |
| 385 | template_function(t: stack_ptr1); // Bad, but type deduction gets it wrong |
| 386 | } |
| 387 | |
| 388 | namespace PR63994 { |
| 389 | struct A { |
| 390 | virtual ~A() {} |
| 391 | }; |
| 392 | |
| 393 | struct B : public A {}; |
| 394 | |
| 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 | |
| 409 | void testLambdaInFunctionNegative() { |
| 410 | const auto MakeS = []() -> ::gsl::owner<S*> { |
| 411 | return ::gsl::owner<S*>{new S{}}; |
| 412 | }; |
| 413 | } |
| 414 | |
| 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 | |
| 422 | void testFunctionInFunctionNegative() { |
| 423 | struct C { |
| 424 | ::gsl::owner<S*> test() { |
| 425 | return ::gsl::owner<S*>{new S{}}; |
| 426 | } |
| 427 | }; |
| 428 | } |
| 429 | |
| 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 | |
| 439 | ::gsl::owner<S*> testReverseLambdaNegative() { |
| 440 | const auto MakeI = [] -> int { return 5; }; |
| 441 | return ::gsl::owner<S*>{new S(MakeI())}; |
| 442 | } |
| 443 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 491 | void testReverseLambdaInLambdaNegative() { |
| 492 | const auto MakeI = []() -> int { |
| 493 | const auto MakeS = []() -> ::gsl::owner<S*> { return new S(); }; |
| 494 | return 5; |
| 495 | }; |
| 496 | } |
| 497 | |
| 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 | |