// RUN: %check_clang_tidy %s cppcoreguidelines-avoid-const-or-ref-data-members %t namespace std { template struct unique_ptr {}; template struct shared_ptr {}; } // namespace std namespace gsl { template struct not_null {}; } // namespace gsl struct Ok { int i; int *p; const int *pc; std::unique_ptr up; std::shared_ptr sp; gsl::not_null n; }; struct ConstMember { const int c; // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const int' is const qualified [cppcoreguidelines-avoid-const-or-ref-data-members] }; struct LvalueRefMember { int &lr; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'int &' is a reference }; struct ConstRefMember { const int &cr; // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const int &' is a reference }; struct RvalueRefMember { int &&rr; // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'int &&' is a reference }; struct ConstAndRefMembers { const int c; // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const int' is const qualified int &lr; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'int &' is a reference const int &cr; // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const int &' is a reference int &&rr; // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'int &&' is a reference }; struct Foo {}; struct Ok2 { Foo i; Foo *p; const Foo *pc; std::unique_ptr up; std::shared_ptr sp; gsl::not_null n; }; struct ConstMember2 { const Foo c; // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const Foo' is const qualified }; struct LvalueRefMember2 { Foo &lr; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'Foo &' is a reference }; struct ConstRefMember2 { const Foo &cr; // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const Foo &' is a reference }; struct RvalueRefMember2 { Foo &&rr; // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'Foo &&' is a reference }; struct ConstAndRefMembers2 { const Foo c; // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const Foo' is const qualified Foo &lr; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'Foo &' is a reference const Foo &cr; // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const Foo &' is a reference Foo &&rr; // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'Foo &&' is a reference }; using ConstType = const int; using RefType = int &; using ConstRefType = const int &; using RefRefType = int &&; struct WithAlias { ConstType c; // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'ConstType' (aka 'const int') is const qualified RefType lr; // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: member 'lr' of type 'RefType' (aka 'int &') is a reference ConstRefType cr; // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: member 'cr' of type 'ConstRefType' (aka 'const int &') is a reference RefRefType rr; // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'rr' of type 'RefRefType' (aka 'int &&') is a reference }; template using Array = int[N]; struct ConstArrayMember { const Array<1> c; // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: member 'c' of type 'const Array<1>' (aka 'const int[1]') is const qualified }; struct LvalueRefArrayMember { Array<2> &lr; // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'lr' of type 'Array<2> &' (aka 'int (&)[2]') is a reference }; struct ConstLvalueRefArrayMember { const Array<3> &cr; // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: member 'cr' of type 'const Array<3> &' (aka 'const int (&)[3]') is a reference }; struct RvalueRefArrayMember { Array<4> &&rr; // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'rr' of type 'Array<4> &&' (aka 'int (&&)[4]') is a reference }; template struct TemplatedOk { T t; }; template struct TemplatedConst { T t; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'const int' is const qualified }; template struct TemplatedConstRef { T t; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'const int &' is a reference }; template struct TemplatedRefRef { T t; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'int &&' is a reference }; template struct TemplatedRef { T t; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'int &' is a reference }; TemplatedOk t1{}; TemplatedConst t2{123}; TemplatedConstRef t3{123}; TemplatedRefRef t4{123}; TemplatedRef t5{t1.t}; // Lambdas capturing const or ref members should not trigger warnings void lambdas() { int x1{123}; const int x2{123}; const int& x3{123}; int&& x4{123}; int& x5{x1}; auto v1 = [x1]{}; auto v2 = [x2]{}; auto v3 = [x3]{}; auto v4 = [x4]{}; auto v5 = [x5]{}; auto r1 = [&x1]{}; auto r2 = [&x2]{}; auto r3 = [&x3]{}; auto r4 = [&x4]{}; auto r5 = [&x5]{}; auto iv = [=]{ auto c1 = x1; auto c2 = x2; auto c3 = x3; auto c4 = x4; auto c5 = x5; }; auto ir = [&]{ auto c1 = x1; auto c2 = x2; auto c3 = x3; auto c4 = x4; auto c5 = x5; }; } struct NonCopyableWithRef { NonCopyableWithRef(NonCopyableWithRef const&) = delete; NonCopyableWithRef& operator=(NonCopyableWithRef const&) = delete; NonCopyableWithRef(NonCopyableWithRef&&) = default; NonCopyableWithRef& operator=(NonCopyableWithRef&&) = default; int& x; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference }; struct NonMovableWithRef { NonMovableWithRef(NonMovableWithRef const&) = default; NonMovableWithRef& operator=(NonMovableWithRef const&) = default; NonMovableWithRef(NonMovableWithRef&&) = delete; NonMovableWithRef& operator=(NonMovableWithRef&&) = delete; int& x; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference }; struct NonCopyableNonMovableWithRef { NonCopyableNonMovableWithRef(NonCopyableNonMovableWithRef const&) = delete; NonCopyableNonMovableWithRef(NonCopyableNonMovableWithRef&&) = delete; NonCopyableNonMovableWithRef& operator=(NonCopyableNonMovableWithRef const&) = delete; NonCopyableNonMovableWithRef& operator=(NonCopyableNonMovableWithRef&&) = delete; int& x; // OK, non copyable nor movable }; struct NonCopyable { NonCopyable(NonCopyable const&) = delete; NonCopyable& operator=(NonCopyable const&) = delete; NonCopyable(NonCopyable&&) = default; NonCopyable& operator=(NonCopyable&&) = default; }; struct NonMovable { NonMovable(NonMovable const&) = default; NonMovable& operator=(NonMovable const&) = default; NonMovable(NonMovable&&) = delete; NonMovable& operator=(NonMovable&&) = delete; }; struct NonCopyableNonMovable { NonCopyableNonMovable(NonCopyableNonMovable const&) = delete; NonCopyableNonMovable(NonCopyableNonMovable&&) = delete; NonCopyableNonMovable& operator=(NonCopyableNonMovable const&) = delete; NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete; }; // Test inheritance struct InheritFromNonCopyable : NonCopyable { int& x; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference }; struct InheritFromNonMovable : NonMovable { int& x; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference }; struct InheritFromNonCopyableNonMovable : NonCopyableNonMovable { int& x; // OK, non copyable nor movable }; struct InheritBothFromNonCopyableAndNonMovable : NonCopyable, NonMovable { int& x; // OK, non copyable nor movable }; template struct TemplateInheritFromNonCopyable : NonCopyable { int& x; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference }; template struct TemplateInheritFromNonMovable : NonMovable { int& x; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference }; template struct TemplateInheritFromNonCopyableNonMovable : NonCopyableNonMovable { int& x; // OK, non copyable nor movable }; template struct TemplateInheritBothFromNonCopyableAndNonMovable : NonCopyable, NonMovable { int& x; // OK, non copyable nor movable }; // Test composition struct ContainsNonCopyable { NonCopyable x; int& y; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'y' of type 'int &' is a reference }; struct ContainsNonMovable { NonMovable x; int& y; // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'y' of type 'int &' is a reference }; struct ContainsNonCopyableNonMovable { NonCopyableNonMovable x; int& y; // OK, non copyable nor movable }; struct ContainsBothNonCopyableAndNonMovable { NonCopyable x; NonMovable y; int& z; // OK, non copyable nor movable }; // If copies are deleted and moves are not declared, moves are not implicitly declared, // so the class is also not movable and we should not warn struct NonCopyableMovesNotDeclared { NonCopyableMovesNotDeclared(NonCopyableMovesNotDeclared const&) = delete; NonCopyableMovesNotDeclared& operator=(NonCopyableMovesNotDeclared const&) = delete; int& x; // OK, non copyable nor movable }; // If moves are deleted but copies are not declared, copies are implicitly deleted, // so the class is also not copyable and we should not warn struct NonMovableCopiesNotDeclared { NonMovableCopiesNotDeclared(NonMovableCopiesNotDeclared&&) = delete; NonMovableCopiesNotDeclared& operator=(NonMovableCopiesNotDeclared&&) = delete; int& x; // OK, non copyable nor movable };