1 // RUN: %check_clang_tidy %s cppcoreguidelines-avoid-const-or-ref-data-members %t 2 namespace std { 3 template <typename T> 4 struct unique_ptr {}; 5 6 template <typename T> 7 struct shared_ptr {}; 8 } // namespace std 9 10 namespace gsl { 11 template <typename T> 12 struct not_null {}; 13 } // namespace gsl 14 15 struct Ok { 16 int i; 17 int *p; 18 const int *pc; 19 std::unique_ptr<int> up; 20 std::shared_ptr<int> sp; 21 gsl::not_null<int*> n; 22 }; 23 24 struct ConstMember { 25 const int c; 26 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const int' is const qualified [cppcoreguidelines-avoid-const-or-ref-data-members] 27 }; 28 29 struct LvalueRefMember { 30 int &lr; 31 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'int &' is a reference 32 }; 33 34 struct ConstRefMember { 35 const int &cr; 36 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const int &' is a reference 37 }; 38 39 struct RvalueRefMember { 40 int &&rr; 41 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'int &&' is a reference 42 }; 43 44 struct ConstAndRefMembers { 45 const int c; 46 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const int' is const qualified 47 int &lr; 48 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'int &' is a reference 49 const int &cr; 50 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const int &' is a reference 51 int &&rr; 52 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'int &&' is a reference 53 }; 54 55 struct Foo {}; 56 57 struct Ok2 { 58 Foo i; 59 Foo *p; 60 const Foo *pc; 61 std::unique_ptr<Foo> up; 62 std::shared_ptr<Foo> sp; 63 gsl::not_null<Foo*> n; 64 }; 65 66 struct ConstMember2 { 67 const Foo c; 68 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const Foo' is const qualified 69 }; 70 71 struct LvalueRefMember2 { 72 Foo &lr; 73 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'Foo &' is a reference 74 }; 75 76 struct ConstRefMember2 { 77 const Foo &cr; 78 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const Foo &' is a reference 79 }; 80 81 struct RvalueRefMember2 { 82 Foo &&rr; 83 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'Foo &&' is a reference 84 }; 85 86 struct ConstAndRefMembers2 { 87 const Foo c; 88 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'const Foo' is const qualified 89 Foo &lr; 90 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'lr' of type 'Foo &' is a reference 91 const Foo &cr; 92 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'cr' of type 'const Foo &' is a reference 93 Foo &&rr; 94 // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: member 'rr' of type 'Foo &&' is a reference 95 }; 96 97 using ConstType = const int; 98 using RefType = int &; 99 using ConstRefType = const int &; 100 using RefRefType = int &&; 101 102 struct WithAlias { 103 ConstType c; 104 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'c' of type 'ConstType' (aka 'const int') is const qualified 105 RefType lr; 106 // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: member 'lr' of type 'RefType' (aka 'int &') is a reference 107 ConstRefType cr; 108 // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: member 'cr' of type 'ConstRefType' (aka 'const int &') is a reference 109 RefRefType rr; 110 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'rr' of type 'RefRefType' (aka 'int &&') is a reference 111 }; 112 113 template <int N> 114 using Array = int[N]; 115 116 struct ConstArrayMember { 117 const Array<1> c; 118 // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: member 'c' of type 'const Array<1>' (aka 'const int[1]') is const qualified 119 }; 120 121 struct LvalueRefArrayMember { 122 Array<2> &lr; 123 // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: member 'lr' of type 'Array<2> &' (aka 'int (&)[2]') is a reference 124 }; 125 126 struct ConstLvalueRefArrayMember { 127 const Array<3> &cr; 128 // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: member 'cr' of type 'const Array<3> &' (aka 'const int (&)[3]') is a reference 129 }; 130 131 struct RvalueRefArrayMember { 132 Array<4> &&rr; 133 // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: member 'rr' of type 'Array<4> &&' (aka 'int (&&)[4]') is a reference 134 }; 135 136 template <typename T> 137 struct TemplatedOk { 138 T t; 139 }; 140 141 template <typename T> 142 struct TemplatedConst { 143 T t; 144 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'const int' is const qualified 145 }; 146 147 template <typename T> 148 struct TemplatedConstRef { 149 T t; 150 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'const int &' is a reference 151 }; 152 153 template <typename T> 154 struct TemplatedRefRef { 155 T t; 156 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'int &&' is a reference 157 }; 158 159 template <typename T> 160 struct TemplatedRef { 161 T t; 162 // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: member 't' of type 'int &' is a reference 163 }; 164 165 TemplatedOk<int> t1{}; 166 TemplatedConst<const int> t2{123}; 167 TemplatedConstRef<const int &> t3{123}; 168 TemplatedRefRef<int &&> t4{123}; 169 TemplatedRef<int &> t5{t1.t}; 170 171 // Lambdas capturing const or ref members should not trigger warnings 172 void lambdas() 173 { 174 int x1{123}; 175 const int x2{123}; 176 const int& x3{123}; 177 int&& x4{123}; 178 int& x5{x1}; 179 180 auto v1 = [x1]{}; 181 auto v2 = [x2]{}; 182 auto v3 = [x3]{}; 183 auto v4 = [x4]{}; 184 auto v5 = [x5]{}; 185 186 auto r1 = [&x1]{}; 187 auto r2 = [&x2]{}; 188 auto r3 = [&x3]{}; 189 auto r4 = [&x4]{}; 190 auto r5 = [&x5]{}; 191 192 auto iv = [=]{ 193 auto c1 = x1; 194 auto c2 = x2; 195 auto c3 = x3; 196 auto c4 = x4; 197 auto c5 = x5; 198 }; 199 200 auto ir = [&]{ 201 auto c1 = x1; 202 auto c2 = x2; 203 auto c3 = x3; 204 auto c4 = x4; 205 auto c5 = x5; 206 }; 207 } 208 209 struct NonCopyableWithRef 210 { 211 NonCopyableWithRef(NonCopyableWithRef const&) = delete; 212 NonCopyableWithRef& operator=(NonCopyableWithRef const&) = delete; 213 NonCopyableWithRef(NonCopyableWithRef&&) = default; 214 NonCopyableWithRef& operator=(NonCopyableWithRef&&) = default; 215 216 int& x; 217 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference 218 }; 219 220 struct NonMovableWithRef 221 { 222 NonMovableWithRef(NonMovableWithRef const&) = default; 223 NonMovableWithRef& operator=(NonMovableWithRef const&) = default; 224 NonMovableWithRef(NonMovableWithRef&&) = delete; 225 NonMovableWithRef& operator=(NonMovableWithRef&&) = delete; 226 227 int& x; 228 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference 229 }; 230 231 struct NonCopyableNonMovableWithRef 232 { 233 NonCopyableNonMovableWithRef(NonCopyableNonMovableWithRef const&) = delete; 234 NonCopyableNonMovableWithRef(NonCopyableNonMovableWithRef&&) = delete; 235 NonCopyableNonMovableWithRef& operator=(NonCopyableNonMovableWithRef const&) = delete; 236 NonCopyableNonMovableWithRef& operator=(NonCopyableNonMovableWithRef&&) = delete; 237 238 int& x; // OK, non copyable nor movable 239 }; 240 241 struct NonCopyable 242 { 243 NonCopyable(NonCopyable const&) = delete; 244 NonCopyable& operator=(NonCopyable const&) = delete; 245 NonCopyable(NonCopyable&&) = default; 246 NonCopyable& operator=(NonCopyable&&) = default; 247 }; 248 249 struct NonMovable 250 { 251 NonMovable(NonMovable const&) = default; 252 NonMovable& operator=(NonMovable const&) = default; 253 NonMovable(NonMovable&&) = delete; 254 NonMovable& operator=(NonMovable&&) = delete; 255 }; 256 257 struct NonCopyableNonMovable 258 { 259 NonCopyableNonMovable(NonCopyableNonMovable const&) = delete; 260 NonCopyableNonMovable(NonCopyableNonMovable&&) = delete; 261 NonCopyableNonMovable& operator=(NonCopyableNonMovable const&) = delete; 262 NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete; 263 }; 264 265 // Test inheritance 266 struct InheritFromNonCopyable : NonCopyable 267 { 268 int& x; 269 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference 270 }; 271 272 struct InheritFromNonMovable : NonMovable 273 { 274 int& x; 275 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference 276 }; 277 278 struct InheritFromNonCopyableNonMovable : NonCopyableNonMovable 279 { 280 int& x; // OK, non copyable nor movable 281 }; 282 283 struct InheritBothFromNonCopyableAndNonMovable : NonCopyable, NonMovable 284 { 285 int& x; // OK, non copyable nor movable 286 }; 287 288 template<class T> struct TemplateInheritFromNonCopyable : NonCopyable 289 { 290 int& x; 291 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference 292 }; 293 294 template<class T> struct TemplateInheritFromNonMovable : NonMovable 295 { 296 int& x; 297 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'x' of type 'int &' is a reference 298 }; 299 300 template<class T> struct TemplateInheritFromNonCopyableNonMovable : NonCopyableNonMovable 301 { 302 int& x; // OK, non copyable nor movable 303 }; 304 305 template<class T> struct TemplateInheritBothFromNonCopyableAndNonMovable : NonCopyable, NonMovable 306 { 307 int& x; // OK, non copyable nor movable 308 }; 309 310 // Test composition 311 struct ContainsNonCopyable 312 { 313 NonCopyable x; 314 int& y; 315 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'y' of type 'int &' is a reference 316 }; 317 318 struct ContainsNonMovable 319 { 320 NonMovable x; 321 int& y; 322 // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: member 'y' of type 'int &' is a reference 323 }; 324 325 struct ContainsNonCopyableNonMovable 326 { 327 NonCopyableNonMovable x; 328 int& y; // OK, non copyable nor movable 329 }; 330 331 struct ContainsBothNonCopyableAndNonMovable 332 { 333 NonCopyable x; 334 NonMovable y; 335 int& z; // OK, non copyable nor movable 336 }; 337 338 // If copies are deleted and moves are not declared, moves are not implicitly declared, 339 // so the class is also not movable and we should not warn 340 struct NonCopyableMovesNotDeclared 341 { 342 NonCopyableMovesNotDeclared(NonCopyableMovesNotDeclared const&) = delete; 343 NonCopyableMovesNotDeclared& operator=(NonCopyableMovesNotDeclared const&) = delete; 344 345 int& x; // OK, non copyable nor movable 346 }; 347 348 // If moves are deleted but copies are not declared, copies are implicitly deleted, 349 // so the class is also not copyable and we should not warn 350 struct NonMovableCopiesNotDeclared 351 { 352 NonMovableCopiesNotDeclared(NonMovableCopiesNotDeclared&&) = delete; 353 NonMovableCopiesNotDeclared& operator=(NonMovableCopiesNotDeclared&&) = delete; 354 355 int& x; // OK, non copyable nor movable 356 }; 357