// RUN: %check_clang_tidy %s cppcoreguidelines-avoid-const-or-ref-data-members %t
namespace std {
template <typename T>
struct unique_ptr {};
template <typename T>
struct shared_ptr {};
} // namespace std
namespace gsl {
template <typename T>
struct not_null {};
} // namespace gsl
struct Ok {
int i;
int *p;
const int *pc;
std::unique_ptr<int> up;
std::shared_ptr<int> sp;
gsl::not_null<int*> 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<Foo> up;
std::shared_ptr<Foo> sp;
gsl::not_null<Foo*> 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 <int N>
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 <typename T>
struct TemplatedOk {
T t;
};
template <typename T>
struct TemplatedConst {
T t;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'const int' is const qualified
};
template <typename T>
struct TemplatedConstRef {
T t;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'const int &' is a reference
};
template <typename T>
struct TemplatedRefRef {
T t;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'int &&' is a reference
};
template <typename T>
struct TemplatedRef {
T t;
// CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'int &' is a reference
};
TemplatedOk<int> t1{};
TemplatedConst<const int> t2{123};
TemplatedConstRef<const int &> t3{123};
TemplatedRefRef<int &&> t4{123};
TemplatedRef<int &> 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
};
// 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
};