xref: /llvm-project/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/owning-memory.cpp (revision 8009bbec59d1c5d47ae06c431647ebee6d886ff2)
189a1d03eSRichard // RUN: %check_clang_tidy %s cppcoreguidelines-owning-memory %t
289a1d03eSRichard 
389a1d03eSRichard namespace gsl {
489a1d03eSRichard template <class T>
589a1d03eSRichard using owner = T;
689a1d03eSRichard } // namespace gsl
789a1d03eSRichard 
889a1d03eSRichard template <typename T>
989a1d03eSRichard class unique_ptr {
1089a1d03eSRichard public:
unique_ptr(gsl::owner<T> resource)1189a1d03eSRichard   unique_ptr(gsl::owner<T> resource) : memory(resource) {}
1289a1d03eSRichard   unique_ptr(const unique_ptr<T> &) = default;
1389a1d03eSRichard 
~unique_ptr()1489a1d03eSRichard   ~unique_ptr() { delete memory; }
1589a1d03eSRichard 
1689a1d03eSRichard private:
1789a1d03eSRichard   gsl::owner<T> memory;
1889a1d03eSRichard };
1989a1d03eSRichard 
takes_owner(gsl::owner<int * > owned_int)2089a1d03eSRichard void takes_owner(gsl::owner<int *> owned_int) {
2189a1d03eSRichard }
2289a1d03eSRichard 
takes_pointer(int * unowned_int)2389a1d03eSRichard void takes_pointer(int *unowned_int) {
2489a1d03eSRichard }
2589a1d03eSRichard 
takes_owner_and_more(int some_int,gsl::owner<int * > owned_int,float f)2689a1d03eSRichard void takes_owner_and_more(int some_int, gsl::owner<int *> owned_int, float f) {
2789a1d03eSRichard }
2889a1d03eSRichard 
2989a1d03eSRichard template <typename T>
takes_templated_owner(gsl::owner<T> owned_T)3089a1d03eSRichard void takes_templated_owner(gsl::owner<T> owned_T) {
3189a1d03eSRichard }
3289a1d03eSRichard 
returns_owner1()3389a1d03eSRichard gsl::owner<int *> returns_owner1() { return gsl::owner<int *>(new int(42)); } // Ok
returns_owner2()3489a1d03eSRichard gsl::owner<int *> returns_owner2() { return new int(42); }                    // Ok
3589a1d03eSRichard 
returns_no_owner1()3689a1d03eSRichard int *returns_no_owner1() { return nullptr; }
returns_no_owner2()3789a1d03eSRichard int *returns_no_owner2() {
3889a1d03eSRichard   return new int(42);
3989a1d03eSRichard   // 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<>'
4089a1d03eSRichard }
returns_no_owner3()4189a1d03eSRichard int *returns_no_owner3() {
4289a1d03eSRichard   int *should_be_owner = new int(42);
4389a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
4489a1d03eSRichard   return should_be_owner;
4589a1d03eSRichard }
returns_no_owner4()4689a1d03eSRichard int *returns_no_owner4() {
4789a1d03eSRichard   gsl::owner<int *> owner = new int(42);
4889a1d03eSRichard   return owner;
4989a1d03eSRichard   // 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<>'
5089a1d03eSRichard }
5189a1d03eSRichard 
returns_no_owner5()5289a1d03eSRichard unique_ptr<int *> returns_no_owner5() {
5389a1d03eSRichard   return unique_ptr<int *>(new int(42)); // Ok
5489a1d03eSRichard }
5589a1d03eSRichard 
5689a1d03eSRichard /// FIXME: CSA finds it, but the report is misleading. Ownersemantics can catch this
5789a1d03eSRichard /// by flow analysis similar to bugprone-use-after-move.
csa_not_finding_leak()5889a1d03eSRichard void csa_not_finding_leak() {
5989a1d03eSRichard   gsl::owner<int *> o1 = new int(42); // Ok
6089a1d03eSRichard 
6189a1d03eSRichard   gsl::owner<int *> o2 = o1; // Ok
6289a1d03eSRichard   o2 = new int(45);          // conceptual leak, the memory from o1 is now leaked, since its considered moved in the guidelines
6389a1d03eSRichard 
6489a1d03eSRichard   delete o2;
6589a1d03eSRichard   // actual leak occurs here, its found, but mixed
6689a1d03eSRichard   delete o1;
6789a1d03eSRichard }
6889a1d03eSRichard 
test_assignment_and_initialization()6989a1d03eSRichard void test_assignment_and_initialization() {
7089a1d03eSRichard   int stack_int1 = 15;
7189a1d03eSRichard   int stack_int2;
7289a1d03eSRichard 
7389a1d03eSRichard   gsl::owner<int *> owned_int1 = &stack_int1; // BAD
7489a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
7589a1d03eSRichard 
7689a1d03eSRichard   gsl::owner<int *> owned_int2;
7789a1d03eSRichard   owned_int2 = &stack_int2; // BAD since no owner, bad since uninitialized
7889a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
7989a1d03eSRichard 
8089a1d03eSRichard   gsl::owner<int *> owned_int3 = new int(42); // Good
8189a1d03eSRichard   owned_int3 = nullptr;                       // Good
8289a1d03eSRichard 
8389a1d03eSRichard   gsl::owner<int *> owned_int4(nullptr); // Ok
8489a1d03eSRichard   owned_int4 = new int(42);              // Good
8589a1d03eSRichard 
8689a1d03eSRichard   gsl::owner<int *> owned_int5 = owned_int3; // Good
8789a1d03eSRichard 
8889a1d03eSRichard   gsl::owner<int *> owned_int6{nullptr}; // Ok
8989a1d03eSRichard   owned_int6 = owned_int4;               // Good
9089a1d03eSRichard 
9189a1d03eSRichard   // FIXME:, flow analysis for the case of reassignment. Value must be released before
9289a1d03eSRichard   owned_int6 = owned_int3; // BAD, because reassignment without resource release
9389a1d03eSRichard 
9489a1d03eSRichard   auto owned_int7 = returns_owner1(); // Ok, since type deduction does not eliminate the owner wrapper
9589a1d03eSRichard 
9689a1d03eSRichard   const auto owned_int8 = returns_owner2(); // Ok, since type deduction does not eliminate the owner wrapper
9789a1d03eSRichard 
9889a1d03eSRichard   gsl::owner<int *> owned_int9 = returns_owner1(); // Ok
9989a1d03eSRichard   int *unowned_int3 = returns_owner1();            // Bad
10089a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
10189a1d03eSRichard 
10289a1d03eSRichard   gsl::owner<int *> owned_int10;
10389a1d03eSRichard   owned_int10 = returns_owner1(); // Ok
10489a1d03eSRichard 
10589a1d03eSRichard   int *unowned_int4;
10689a1d03eSRichard   unowned_int4 = returns_owner1(); // Bad
10789a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
10889a1d03eSRichard 
10989a1d03eSRichard   gsl::owner<int *> owned_int11 = returns_no_owner1(); // Bad since no owner
11089a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
11189a1d03eSRichard 
11289a1d03eSRichard   gsl::owner<int *> owned_int12;
11389a1d03eSRichard   owned_int12 = returns_no_owner1(); // Bad since no owner
11489a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
11589a1d03eSRichard 
11689a1d03eSRichard   int *unowned_int5 = returns_no_owner1(); // Ok
11789a1d03eSRichard   int *unowned_int6;
11889a1d03eSRichard   unowned_int6 = returns_no_owner1(); // Ok
11989a1d03eSRichard 
12089a1d03eSRichard   int *unowned_int7 = new int(42); // Bad, since resource not assigned to an owner
12189a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
12289a1d03eSRichard 
12389a1d03eSRichard   int *unowned_int8;
12489a1d03eSRichard   unowned_int8 = new int(42);
12589a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: assigning newly created 'gsl::owner<>' to non-owner 'int *'
12689a1d03eSRichard 
12789a1d03eSRichard   gsl::owner<int *> owned_int13 = nullptr; // Ok
12889a1d03eSRichard }
12989a1d03eSRichard 
test_deletion()13089a1d03eSRichard void test_deletion() {
13189a1d03eSRichard   gsl::owner<int *> owned_int1 = new int(42);
13289a1d03eSRichard   delete owned_int1; // Good
13389a1d03eSRichard 
13489a1d03eSRichard   gsl::owner<int *> owned_int2 = new int[42];
13589a1d03eSRichard   delete[] owned_int2; // Good
13689a1d03eSRichard 
13789a1d03eSRichard   int *unowned_int1 = new int(42); // BAD, since new creates and owner
13889a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
13989a1d03eSRichard   delete unowned_int1; // BAD, since no owner
14089a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
14189a1d03eSRichard   // CHECK-NOTES: [[@LINE-4]]:3: note: variable declared here
14289a1d03eSRichard 
14389a1d03eSRichard   int *unowned_int2 = new int[42]; // BAD, since new creates and owner
14489a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: initializing non-owner 'int *' with a newly created 'gsl::owner<>'
14589a1d03eSRichard   delete[] unowned_int2; // BAD since no owner
14689a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: deleting a pointer through a type that is not marked 'gsl::owner<>'; consider using a smart pointer instead
14789a1d03eSRichard   // CHECK-NOTES: [[@LINE-4]]:3: note: variable declared here
14889a1d03eSRichard 
14989a1d03eSRichard   delete new int(42);   // Technically ok, but stupid
15089a1d03eSRichard   delete[] new int[42]; // Technically ok, but stupid
15189a1d03eSRichard }
15289a1d03eSRichard 
test_owner_function_calls()15389a1d03eSRichard void test_owner_function_calls() {
15489a1d03eSRichard   int stack_int = 42;
15589a1d03eSRichard   int *unowned_int1 = &stack_int;
15689a1d03eSRichard   takes_owner(&stack_int); // BAD
15789a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
15889a1d03eSRichard   takes_owner(unowned_int1); // BAD
15989a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
16089a1d03eSRichard 
16189a1d03eSRichard   gsl::owner<int *> owned_int1 = new int(42);
16289a1d03eSRichard   takes_owner(owned_int1); // Ok
16389a1d03eSRichard 
16489a1d03eSRichard   takes_owner_and_more(42, &stack_int, 42.0f); // BAD
16589a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *'
16689a1d03eSRichard   takes_owner_and_more(42, unowned_int1, 42.0f); // BAD
16789a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:28: warning: expected argument of type 'gsl::owner<>'; got 'int *'
16889a1d03eSRichard 
16989a1d03eSRichard   takes_owner_and_more(42, new int(42), 42.0f); // Ok, since new is consumed by owner
17089a1d03eSRichard   takes_owner_and_more(42, owned_int1, 42.0f);  // Ok, since owner as argument
17189a1d03eSRichard 
17289a1d03eSRichard   takes_templated_owner(owned_int1);   // Ok
17389a1d03eSRichard   takes_templated_owner(new int(42));  // Ok
17489a1d03eSRichard   takes_templated_owner(unowned_int1); // Bad
17589a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:25: warning: expected argument of type 'gsl::owner<>'; got 'int *'
17689a1d03eSRichard 
17789a1d03eSRichard   takes_owner(returns_owner1());    // Ok
17889a1d03eSRichard   takes_owner(returns_no_owner1()); // BAD
17989a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:15: warning: expected argument of type 'gsl::owner<>'; got 'int *'
18089a1d03eSRichard }
18189a1d03eSRichard 
test_unowned_function_calls()18289a1d03eSRichard void test_unowned_function_calls() {
18389a1d03eSRichard   int stack_int = 42;
18489a1d03eSRichard   int *unowned_int1 = &stack_int;
18589a1d03eSRichard   gsl::owner<int *> owned_int1 = new int(42);
18689a1d03eSRichard 
18789a1d03eSRichard   takes_pointer(&stack_int);   // Ok
18889a1d03eSRichard   takes_pointer(unowned_int1); // Ok
18989a1d03eSRichard   takes_pointer(owned_int1);   // Ok
19089a1d03eSRichard   takes_pointer(new int(42));  // Bad, since new creates and owner
19189a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
19289a1d03eSRichard 
19389a1d03eSRichard   takes_pointer(returns_owner1()); // Bad
19489a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:17: warning: initializing non-owner argument of type 'int *' with a newly created 'gsl::owner<>'
19589a1d03eSRichard 
19689a1d03eSRichard   takes_pointer(returns_no_owner1()); // Ok
19789a1d03eSRichard }
19889a1d03eSRichard 
19989a1d03eSRichard // FIXME: Typedefing owner<> to something else does not work.
20089a1d03eSRichard // This might be necessary for code already having a similar typedef like owner<> and
20189a1d03eSRichard // replacing it with owner<>. This might be the same problem as with templates.
20289a1d03eSRichard // The canonical type will ignore the owner<> alias, since its a typedef as well.
20389a1d03eSRichard //
20489a1d03eSRichard // Check, if owners hidden by typedef are handled the same as 'obvious' owners.
20589a1d03eSRichard #if 0
20689a1d03eSRichard using heap_int = gsl::owner<int *>;
20789a1d03eSRichard typedef gsl::owner<float *> heap_float;
20889a1d03eSRichard 
20989a1d03eSRichard // This tests only a subset, assuming that the check will either see through the
21089a1d03eSRichard // typedef or not (it doesn't!).
21189a1d03eSRichard void test_typedefed_values() {
21289a1d03eSRichard   // Modern typedef.
21389a1d03eSRichard   int StackInt1 = 42;
21489a1d03eSRichard   heap_int HeapInt1 = &StackInt1;
21589a1d03eSRichard   // CHECK MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'int *'
21689a1d03eSRichard 
21789a1d03eSRichard   //FIXME: Typedef not considered correctly here.
21889a1d03eSRichard   // heap_int HeapInt2 = new int(42); // Ok
21989a1d03eSRichard   takes_pointer(HeapInt1); // Ok
22089a1d03eSRichard   takes_owner(HeapInt1);   // Ok
22189a1d03eSRichard 
22289a1d03eSRichard   // Traditional typedef.
22389a1d03eSRichard   float StackFloat1 = 42.0f;
22489a1d03eSRichard   heap_float HeapFloat1 = &StackFloat1;
22589a1d03eSRichard   // CHECK MESSAGES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'float *'
22689a1d03eSRichard 
22789a1d03eSRichard   //FIXME: Typedef not considered correctly here.
22889a1d03eSRichard   // heap_float HeapFloat2 = new float(42.0f);
22989a1d03eSRichard   HeapFloat2 = HeapFloat1; // Ok
23089a1d03eSRichard }
23189a1d03eSRichard #endif
23289a1d03eSRichard 
23389a1d03eSRichard struct ArbitraryClass {};
23489a1d03eSRichard struct ClassWithOwner {                    // Does not define destructor, necessary with owner
ClassWithOwnerClassWithOwner23589a1d03eSRichard   ClassWithOwner() : owner_var(nullptr) {} // Ok
23689a1d03eSRichard 
ClassWithOwnerClassWithOwner23789a1d03eSRichard   ClassWithOwner(ArbitraryClass &other) : owner_var(&other) {}
23889a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:43: warning: expected initialization of owner member variable with value of type 'gsl::owner<>'; got 'ArbitraryClass *'
23989a1d03eSRichard 
ClassWithOwnerClassWithOwner24089a1d03eSRichard   ClassWithOwner(gsl::owner<ArbitraryClass *> other) : owner_var(other) {} // Ok
24189a1d03eSRichard 
ClassWithOwnerClassWithOwner24289a1d03eSRichard   ClassWithOwner(gsl::owner<ArbitraryClass *> data, int /* unused */) { // Ok
24389a1d03eSRichard     owner_var = data;                                                   // Ok
24489a1d03eSRichard   }
24589a1d03eSRichard 
ClassWithOwnerClassWithOwner24689a1d03eSRichard   ClassWithOwner(ArbitraryClass *bad_data, int /* unused */, int /* unused */) {
24789a1d03eSRichard     owner_var = bad_data;
24889a1d03eSRichard     // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
24989a1d03eSRichard   }
25089a1d03eSRichard 
ClassWithOwnerClassWithOwner25189a1d03eSRichard   ClassWithOwner(ClassWithOwner &&other) : owner_var{other.owner_var} {} // Ok
25289a1d03eSRichard 
operator =ClassWithOwner25389a1d03eSRichard   ClassWithOwner &operator=(ClassWithOwner &&other) {
25489a1d03eSRichard     owner_var = other.owner_var; // Ok
25589a1d03eSRichard     return *this;
25689a1d03eSRichard   }
25789a1d03eSRichard 
25889a1d03eSRichard   // Returning means, that the owner is "moved", so the class should not access this
25989a1d03eSRichard   // variable anymore after this method gets called.
buggy_but_returns_ownerClassWithOwner26089a1d03eSRichard   gsl::owner<ArbitraryClass *> buggy_but_returns_owner() { return owner_var; }
26189a1d03eSRichard 
26289a1d03eSRichard   gsl::owner<ArbitraryClass *> owner_var;
26389a1d03eSRichard   // 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
26489a1d03eSRichard };
26589a1d03eSRichard 
26689a1d03eSRichard class DefaultedDestructor {         // Bad since default constructor with owner
26789a1d03eSRichard   ~DefaultedDestructor() = default; // Bad, since will not destroy the owner
26889a1d03eSRichard   gsl::owner<int *> Owner;
26989a1d03eSRichard   // 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
27089a1d03eSRichard };
27189a1d03eSRichard 
27289a1d03eSRichard struct DeletedDestructor {
27389a1d03eSRichard   ~DeletedDestructor() = delete;
27489a1d03eSRichard   gsl::owner<int *> Owner;
27589a1d03eSRichard   // 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
27689a1d03eSRichard };
27789a1d03eSRichard 
test_class_with_owner()27889a1d03eSRichard void test_class_with_owner() {
27989a1d03eSRichard   ArbitraryClass A;
28089a1d03eSRichard   ClassWithOwner C1;                                                   // Ok
28189a1d03eSRichard   ClassWithOwner C2{A};                                                // Bad, since the owner would be initialized with an non-owner, but catched in the class
28289a1d03eSRichard   ClassWithOwner C3{gsl::owner<ArbitraryClass *>(new ArbitraryClass)}; // Ok
28389a1d03eSRichard 
28489a1d03eSRichard   const auto Owner1 = C3.buggy_but_returns_owner(); // Ok, deduces Owner1 to owner<ArbitraryClass *> const
28589a1d03eSRichard 
28689a1d03eSRichard   auto Owner2 = C2.buggy_but_returns_owner(); // Ok, deduces Owner2 to owner<ArbitraryClass *>
28789a1d03eSRichard 
28889a1d03eSRichard   Owner2 = &A; // BAD, since type deduction resulted in owner<ArbitraryClass *>
28989a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
29089a1d03eSRichard 
29189a1d03eSRichard   gsl::owner<ArbitraryClass *> Owner3 = C1.buggy_but_returns_owner(); // Ok, still an owner
29289a1d03eSRichard   Owner3 = &A;                                                        // Bad, since assignment of non-owner to owner
29389a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected assignment source to be of type 'gsl::owner<>'; got 'ArbitraryClass *'
29489a1d03eSRichard }
29589a1d03eSRichard 
29689a1d03eSRichard template <typename T>
29789a1d03eSRichard struct HeapArray {                                          // Ok, since destructor with owner
HeapArrayHeapArray29889a1d03eSRichard   HeapArray() : _data(nullptr), size(0) {}                  // Ok
HeapArrayHeapArray29989a1d03eSRichard   HeapArray(int size) : _data(new int[size]), size(size) {} // Ok
HeapArrayHeapArray30089a1d03eSRichard   HeapArray(int size, T val) {
30189a1d03eSRichard     _data = new int[size]; // Ok
30289a1d03eSRichard     size = size;
30389a1d03eSRichard     for (auto i = 0u; i < size; ++i)
30489a1d03eSRichard       _data[i] = val; // Ok
30589a1d03eSRichard   }
HeapArrayHeapArray30689a1d03eSRichard   HeapArray(int size, T val, int *problematic) : _data{problematic}, size(size) {} // Bad
30789a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:50: warning: expected initialization of owner member variable with value of type 'gsl::owner<>'; got 'void'
30889a1d03eSRichard   // FIXME: void is incorrect type, probably wrong thing matched
30989a1d03eSRichard 
HeapArrayHeapArray31089a1d03eSRichard   HeapArray(HeapArray &&other) : _data(other._data), size(other.size) { // Ok
31189a1d03eSRichard     other._data = nullptr;                                              // Ok
312*8009bbecSKrystian Stasiowski     // CHECK-NOTES: [[@LINE-1]]:5: warning: expected assignment source to be of type 'gsl::owner<>'; got 'std::nullptr_t'
313*8009bbecSKrystian Stasiowski     // FIXME: This warning is emitted because an ImplicitCastExpr for the NullToPointer conversion isn't created for dependent types.
31489a1d03eSRichard     other.size = 0;
31589a1d03eSRichard   }
31689a1d03eSRichard 
operator =HeapArray31789a1d03eSRichard   HeapArray<T> &operator=(HeapArray<T> &&other) {
31889a1d03eSRichard     _data = other._data; // Ok, NOLINT warning here about bad types, why?
31989a1d03eSRichard     size = other.size;
32089a1d03eSRichard     return *this;
32189a1d03eSRichard   }
32289a1d03eSRichard 
~HeapArrayHeapArray32389a1d03eSRichard   ~HeapArray() { delete[] _data; } // Ok
32489a1d03eSRichard 
dataHeapArray32589a1d03eSRichard   T *data() { return _data; } // Ok NOLINT, because it "looks" like a factory
32689a1d03eSRichard 
32789a1d03eSRichard   gsl::owner<T *> _data;
32889a1d03eSRichard   unsigned int size;
32989a1d03eSRichard };
33089a1d03eSRichard 
test_inner_template()33189a1d03eSRichard void test_inner_template() {
33289a1d03eSRichard   HeapArray<int> Array1;
33389a1d03eSRichard   HeapArray<int> Array2(100);
33489a1d03eSRichard   HeapArray<int> Array3(100, 0);
33589a1d03eSRichard   HeapArray<int> Array4(100, 0, nullptr);
33689a1d03eSRichard 
33789a1d03eSRichard   Array1 = static_cast<HeapArray<int> &&>(Array2);
33889a1d03eSRichard   HeapArray<int> Array5(static_cast<HeapArray<int> &&>(Array3));
33989a1d03eSRichard 
34089a1d03eSRichard   int *NonOwningPtr = Array1.data();           // Ok
34189a1d03eSRichard   gsl::owner<int *> OwningPtr = Array1.data(); // Bad, since it does not return the owner
34289a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
34389a1d03eSRichard }
34489a1d03eSRichard 
34589a1d03eSRichard // FIXME: Typededuction removes the owner - wrapper, therefore gsl::owner can not be used
34689a1d03eSRichard // with Template classes like this. Is there a walkaround?
34789a1d03eSRichard template <typename T>
34889a1d03eSRichard struct TemplateValue {
34989a1d03eSRichard   TemplateValue() = default;
TemplateValueTemplateValue35089a1d03eSRichard   TemplateValue(T t) : val{t} {}
35189a1d03eSRichard 
setValTemplateValue35289a1d03eSRichard   void setVal(const T &t) { val = t; }
getValTemplateValue35389a1d03eSRichard   const T getVal() const { return val; }
35489a1d03eSRichard 
35589a1d03eSRichard   T val;
35689a1d03eSRichard };
35789a1d03eSRichard 
35889a1d03eSRichard // FIXME: Same typededcution problems
35989a1d03eSRichard template <typename T>
template_function(T t)36089a1d03eSRichard void template_function(T t) {
36189a1d03eSRichard   gsl::owner<int *> owner_t = t; // Probably bad, since type deduction still wrong
36289a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'T'
36389a1d03eSRichard   // CHECK-NOTES: [[@LINE-2]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
36489a1d03eSRichard }
36589a1d03eSRichard 
36689a1d03eSRichard // FIXME: Same typededcution problems
test_templates()36789a1d03eSRichard void test_templates() {
36889a1d03eSRichard   int stack_int = 42;
36989a1d03eSRichard   int *stack_ptr1 = &stack_int;
37089a1d03eSRichard 
37189a1d03eSRichard   TemplateValue<gsl::owner<int *>> Owner0; // Ok, T should be owner, but is int*
37289a1d03eSRichard 
37389a1d03eSRichard   TemplateValue<gsl::owner<int *>> Owner1(new int(42)); // Ok, T should be owner, but is int*
37489a1d03eSRichard   Owner1.setVal(&stack_int);                            // Bad since non-owner assignment
37589a1d03eSRichard   Owner1.setVal(stack_ptr1);                            // Bad since non-owner assignment
37689a1d03eSRichard   //Owner1.setVal(new int(42)); // Ok, but since type deduction is wrong, this one is considered harmful
37789a1d03eSRichard 
37889a1d03eSRichard   int *stack_ptr2 = Owner1.getVal(); // Bad, initializing non-owner with owner
37989a1d03eSRichard 
38089a1d03eSRichard   TemplateValue<int *> NonOwner1(new int(42));      // Bad, T is int *, hence dynamic memory to non-owner
38189a1d03eSRichard   gsl::owner<int *> IntOwner1 = NonOwner1.getVal(); // Bad, since owner initialized with non-owner
38289a1d03eSRichard   // CHECK-NOTES: [[@LINE-1]]:3: warning: expected initialization with value of type 'gsl::owner<>'; got 'int *'
38389a1d03eSRichard 
38489a1d03eSRichard   template_function(IntOwner1);  // Ok, but not actually ok, since type deduction removes owner
38589a1d03eSRichard   template_function(stack_ptr1); // Bad, but type deduction gets it wrong
38689a1d03eSRichard }
3875b5b75bfSPiotr Zegar 
3885b5b75bfSPiotr Zegar namespace PR63994 {
3895b5b75bfSPiotr Zegar   struct A {
~APR63994::A3905b5b75bfSPiotr Zegar     virtual ~A() {}
3915b5b75bfSPiotr Zegar   };
3925b5b75bfSPiotr Zegar 
3935b5b75bfSPiotr Zegar   struct B : public A {};
3945b5b75bfSPiotr Zegar 
foo(int x)3955b5b75bfSPiotr Zegar   A* foo(int x) {
3965b5b75bfSPiotr Zegar     return new B;
3975b5b75bfSPiotr Zegar     // 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<>'
3985b5b75bfSPiotr Zegar   }
3995b5b75bfSPiotr Zegar }
4000a40f5d1SPiotr Zegar 
4010a40f5d1SPiotr Zegar namespace PR59389 {
4020a40f5d1SPiotr Zegar   struct S {
4030a40f5d1SPiotr Zegar     S();
4040a40f5d1SPiotr Zegar     S(int);
4050a40f5d1SPiotr Zegar 
4060a40f5d1SPiotr Zegar     int value = 1;
4070a40f5d1SPiotr Zegar   };
4080a40f5d1SPiotr Zegar 
testLambdaInFunctionNegative()4090a40f5d1SPiotr Zegar   void testLambdaInFunctionNegative() {
4100a40f5d1SPiotr Zegar     const auto MakeS = []() -> ::gsl::owner<S*> {
4110a40f5d1SPiotr Zegar       return ::gsl::owner<S*>{new S{}};
4120a40f5d1SPiotr Zegar     };
4130a40f5d1SPiotr Zegar   }
4140a40f5d1SPiotr Zegar 
testLambdaInFunctionPositive()4150a40f5d1SPiotr Zegar   void testLambdaInFunctionPositive() {
4160a40f5d1SPiotr Zegar     const auto MakeS = []() -> S* {
4170a40f5d1SPiotr Zegar       return ::gsl::owner<S*>{new S{}};
4180a40f5d1SPiotr Zegar       // 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<>'
4190a40f5d1SPiotr Zegar     };
4200a40f5d1SPiotr Zegar   }
4210a40f5d1SPiotr Zegar 
testFunctionInFunctionNegative()4220a40f5d1SPiotr Zegar   void testFunctionInFunctionNegative() {
4230a40f5d1SPiotr Zegar     struct C {
4240a40f5d1SPiotr Zegar       ::gsl::owner<S*> test() {
4250a40f5d1SPiotr Zegar         return ::gsl::owner<S*>{new S{}};
4260a40f5d1SPiotr Zegar       }
4270a40f5d1SPiotr Zegar     };
4280a40f5d1SPiotr Zegar   }
4290a40f5d1SPiotr Zegar 
testFunctionInFunctionPositive()4300a40f5d1SPiotr Zegar   void testFunctionInFunctionPositive() {
4310a40f5d1SPiotr Zegar     struct C {
4320a40f5d1SPiotr Zegar       S* test() {
4330a40f5d1SPiotr Zegar         return ::gsl::owner<S*>{new S{}};
4340a40f5d1SPiotr Zegar         // 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<>'
4350a40f5d1SPiotr Zegar       }
4360a40f5d1SPiotr Zegar     };
4370a40f5d1SPiotr Zegar   }
4380a40f5d1SPiotr Zegar 
testReverseLambdaNegative()4390a40f5d1SPiotr Zegar   ::gsl::owner<S*> testReverseLambdaNegative() {
4400a40f5d1SPiotr Zegar     const auto MakeI = [] -> int { return 5; };
4410a40f5d1SPiotr Zegar     return ::gsl::owner<S*>{new S(MakeI())};
4420a40f5d1SPiotr Zegar   }
4430a40f5d1SPiotr Zegar 
testReverseLambdaPositive()4440a40f5d1SPiotr Zegar   S* testReverseLambdaPositive() {
4450a40f5d1SPiotr Zegar     const auto MakeI = [] -> int { return 5; };
4460a40f5d1SPiotr Zegar     return ::gsl::owner<S*>{new S(MakeI())};
4470a40f5d1SPiotr Zegar     // 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<>'
4480a40f5d1SPiotr Zegar   }
4490a40f5d1SPiotr Zegar 
testReverseFunctionNegative()4500a40f5d1SPiotr Zegar   ::gsl::owner<S*> testReverseFunctionNegative() {
4510a40f5d1SPiotr Zegar     struct C {
4520a40f5d1SPiotr Zegar       int test() { return 5; }
4530a40f5d1SPiotr Zegar     };
4540a40f5d1SPiotr Zegar     return ::gsl::owner<S*>{new S(C().test())};
4550a40f5d1SPiotr Zegar   }
4560a40f5d1SPiotr Zegar 
testReverseFunctionPositive()4570a40f5d1SPiotr Zegar   S* testReverseFunctionPositive() {
4580a40f5d1SPiotr Zegar     struct C {
4590a40f5d1SPiotr Zegar       int test() { return 5; }
4600a40f5d1SPiotr Zegar     };
4610a40f5d1SPiotr Zegar     return ::gsl::owner<S*>{new S(C().test())};
4620a40f5d1SPiotr Zegar     // 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<>'
4630a40f5d1SPiotr Zegar   }
4640a40f5d1SPiotr Zegar 
testLambdaInLambdaNegative()4650a40f5d1SPiotr Zegar   void testLambdaInLambdaNegative() {
4660a40f5d1SPiotr Zegar     const auto MakeS = []() -> ::gsl::owner<S*> {
4670a40f5d1SPiotr Zegar       const auto MakeI = []() -> int { return 5; };
4680a40f5d1SPiotr Zegar       return ::gsl::owner<S*>{new S(MakeI())};
4690a40f5d1SPiotr Zegar     };
4700a40f5d1SPiotr Zegar   }
4710a40f5d1SPiotr Zegar 
testLambdaInLambdaPositive()4720a40f5d1SPiotr Zegar   void testLambdaInLambdaPositive() {
4730a40f5d1SPiotr Zegar     const auto MakeS = []() -> S* {
4740a40f5d1SPiotr Zegar       const auto MakeI = []() -> int { return 5; };
4750a40f5d1SPiotr Zegar       return ::gsl::owner<S*>{new S(MakeI())};
4760a40f5d1SPiotr Zegar       // 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<>'
4770a40f5d1SPiotr Zegar     };
4780a40f5d1SPiotr Zegar   }
4790a40f5d1SPiotr Zegar 
testLambdaInLambdaWithDoubleReturns()4800a40f5d1SPiotr Zegar   void testLambdaInLambdaWithDoubleReturns() {
4810a40f5d1SPiotr Zegar     const auto MakeS = []() -> S* {
4820a40f5d1SPiotr Zegar       const auto MakeS2 = []() -> S* {
4830a40f5d1SPiotr Zegar         return ::gsl::owner<S*>{new S(1)};
4840a40f5d1SPiotr Zegar         // 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]
4850a40f5d1SPiotr Zegar       };
4860a40f5d1SPiotr Zegar       return ::gsl::owner<S*>{new S(2)};
4870a40f5d1SPiotr Zegar       // 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<>'
4880a40f5d1SPiotr Zegar     };
4890a40f5d1SPiotr Zegar   }
4900a40f5d1SPiotr Zegar 
testReverseLambdaInLambdaNegative()4910a40f5d1SPiotr Zegar   void testReverseLambdaInLambdaNegative() {
4920a40f5d1SPiotr Zegar     const auto MakeI = []() -> int {
4930a40f5d1SPiotr Zegar       const auto MakeS = []() -> ::gsl::owner<S*> { return new S(); };
4940a40f5d1SPiotr Zegar       return 5;
4950a40f5d1SPiotr Zegar     };
4960a40f5d1SPiotr Zegar   }
4970a40f5d1SPiotr Zegar 
testReverseLambdaInLambdaPositive()4980a40f5d1SPiotr Zegar   void testReverseLambdaInLambdaPositive() {
4990a40f5d1SPiotr Zegar     const auto MakeI = []() -> int {
5000a40f5d1SPiotr Zegar       const auto MakeS = []() -> S* { return new S(); };
5010a40f5d1SPiotr Zegar       // 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<>'
5020a40f5d1SPiotr Zegar       return 5;
5030a40f5d1SPiotr Zegar     };
5040a40f5d1SPiotr Zegar   }
5050a40f5d1SPiotr Zegar }
506