1 // RUN: %check_clang_tidy %s cppcoreguidelines-virtual-class-destructor %t -- --fix-notes 2 3 // CHECK-MESSAGES: :[[@LINE+4]]:8: warning: destructor of 'PrivateVirtualBaseStruct' is private and prevents using the type [cppcoreguidelines-virtual-class-destructor] 4 // CHECK-MESSAGES: :[[@LINE+3]]:8: note: make it public and virtual 5 // CHECK-MESSAGES: :[[@LINE+2]]:8: note: make it protected 6 // As we have 2 conflicting fixes in notes, no fix is applied. 7 struct PrivateVirtualBaseStruct { 8 virtual void f(); 9 10 private: ~PrivateVirtualBaseStructPrivateVirtualBaseStruct11 virtual ~PrivateVirtualBaseStruct() {} 12 }; 13 14 struct PublicVirtualBaseStruct { // OK 15 virtual void f(); ~PublicVirtualBaseStructPublicVirtualBaseStruct16 virtual ~PublicVirtualBaseStruct() {} 17 }; 18 19 // CHECK-MESSAGES: :[[@LINE+2]]:8: warning: destructor of 'ProtectedVirtualBaseStruct' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 20 // CHECK-MESSAGES: :[[@LINE+1]]:8: note: make it protected and non-virtual 21 struct ProtectedVirtualBaseStruct { 22 virtual void f(); 23 24 protected: ~ProtectedVirtualBaseStructProtectedVirtualBaseStruct25 virtual ~ProtectedVirtualBaseStruct() {} 26 // CHECK-FIXES: ~ProtectedVirtualBaseStruct() {} 27 }; 28 29 // CHECK-MESSAGES: :[[@LINE+2]]:8: warning: destructor of 'ProtectedVirtualDefaultBaseStruct' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 30 // CHECK-MESSAGES: :[[@LINE+1]]:8: note: make it protected and non-virtual 31 struct ProtectedVirtualDefaultBaseStruct { 32 virtual void f(); 33 34 protected: 35 virtual ~ProtectedVirtualDefaultBaseStruct() = default; 36 // CHECK-FIXES: ~ProtectedVirtualDefaultBaseStruct() = default; 37 }; 38 39 // CHECK-MESSAGES: :[[@LINE+4]]:8: warning: destructor of 'PrivateNonVirtualBaseStruct' is private and prevents using the type [cppcoreguidelines-virtual-class-destructor] 40 // CHECK-MESSAGES: :[[@LINE+3]]:8: note: make it public and virtual 41 // CHECK-MESSAGES: :[[@LINE+2]]:8: note: make it protected 42 // As we have 2 conflicting fixes in notes, no fix is applied. 43 struct PrivateNonVirtualBaseStruct { 44 virtual void f(); 45 46 private: ~PrivateNonVirtualBaseStructPrivateNonVirtualBaseStruct47 ~PrivateNonVirtualBaseStruct() {} 48 }; 49 50 // CHECK-MESSAGES: :[[@LINE+2]]:8: warning: destructor of 'PublicNonVirtualBaseStruct' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 51 // CHECK-MESSAGES: :[[@LINE+1]]:8: note: make it public and virtual 52 struct PublicNonVirtualBaseStruct { 53 virtual void f(); ~PublicNonVirtualBaseStructPublicNonVirtualBaseStruct54 ~PublicNonVirtualBaseStruct() {} 55 // CHECK-FIXES: virtual ~PublicNonVirtualBaseStruct() {} 56 }; 57 58 struct PublicNonVirtualNonBaseStruct { // OK according to C.35, since this struct does not have any virtual methods. 59 void f(); ~PublicNonVirtualNonBaseStructPublicNonVirtualNonBaseStruct60 ~PublicNonVirtualNonBaseStruct() {} 61 }; 62 63 // CHECK-MESSAGES: :[[@LINE+4]]:8: warning: destructor of 'PublicImplicitNonVirtualBaseStruct' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 64 // CHECK-MESSAGES: :[[@LINE+3]]:8: note: make it public and virtual 65 // CHECK-FIXES: struct PublicImplicitNonVirtualBaseStruct { 66 // CHECK-FIXES-NEXT: virtual ~PublicImplicitNonVirtualBaseStruct() = default; 67 struct PublicImplicitNonVirtualBaseStruct { 68 virtual void f(); 69 }; 70 71 // CHECK-MESSAGES: :[[@LINE+5]]:8: warning: destructor of 'PublicASImplicitNonVirtualBaseStruct' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 72 // CHECK-MESSAGES: :[[@LINE+4]]:8: note: make it public and virtual 73 // CHECK-FIXES: struct PublicASImplicitNonVirtualBaseStruct { 74 // CHECK-FIXES-NEXT: virtual ~PublicASImplicitNonVirtualBaseStruct() = default; 75 // CHECK-FIXES-NEXT: private: 76 struct PublicASImplicitNonVirtualBaseStruct { 77 private: 78 virtual void f(); 79 }; 80 81 struct ProtectedNonVirtualBaseStruct { // OK 82 virtual void f(); 83 84 protected: ~ProtectedNonVirtualBaseStructProtectedNonVirtualBaseStruct85 ~ProtectedNonVirtualBaseStruct() {} 86 }; 87 88 // CHECK-MESSAGES: :[[@LINE+4]]:7: warning: destructor of 'PrivateVirtualBaseClass' is private and prevents using the type [cppcoreguidelines-virtual-class-destructor] 89 // CHECK-MESSAGES: :[[@LINE+3]]:7: note: make it public and virtual 90 // CHECK-MESSAGES: :[[@LINE+2]]:7: note: make it protected 91 // As we have 2 conflicting fixes in notes, no fix is applied. 92 class PrivateVirtualBaseClass { 93 virtual void f(); ~PrivateVirtualBaseClass()94 virtual ~PrivateVirtualBaseClass() {} 95 }; 96 97 class PublicVirtualBaseClass { // OK 98 virtual void f(); 99 100 public: ~PublicVirtualBaseClass()101 virtual ~PublicVirtualBaseClass() {} 102 }; 103 104 // CHECK-MESSAGES: :[[@LINE+2]]:7: warning: destructor of 'ProtectedVirtualBaseClass' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 105 // CHECK-MESSAGES: :[[@LINE+1]]:7: note: make it protected and non-virtual 106 class ProtectedVirtualBaseClass { 107 virtual void f(); 108 109 protected: ~ProtectedVirtualBaseClass()110 virtual ~ProtectedVirtualBaseClass() {} 111 // CHECK-FIXES: ~ProtectedVirtualBaseClass() {} 112 }; 113 114 // CHECK-MESSAGES: :[[@LINE+5]]:7: warning: destructor of 'PublicImplicitNonVirtualBaseClass' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 115 // CHECK-MESSAGES: :[[@LINE+4]]:7: note: make it public and virtual 116 // CHECK-FIXES: public: 117 // CHECK-FIXES-NEXT: virtual ~PublicImplicitNonVirtualBaseClass() = default; 118 // CHECK-FIXES-NEXT: }; 119 class PublicImplicitNonVirtualBaseClass { 120 virtual void f(); 121 }; 122 123 // CHECK-MESSAGES: :[[@LINE+6]]:7: warning: destructor of 'PublicASImplicitNonVirtualBaseClass' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 124 // CHECK-MESSAGES: :[[@LINE+5]]:7: note: make it public and virtual 125 // CHECK-FIXES: public: 126 // CHECK-FIXES-NEXT: virtual ~PublicASImplicitNonVirtualBaseClass() = default; 127 // CHECK-FIXES-NEXT: int foo = 42; 128 // CHECK-FIXES-NEXT: }; 129 class PublicASImplicitNonVirtualBaseClass { 130 virtual void f(); 131 132 public: 133 int foo = 42; 134 }; 135 136 // CHECK-MESSAGES: :[[@LINE+2]]:7: warning: destructor of 'PublicNonVirtualBaseClass' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 137 // CHECK-MESSAGES: :[[@LINE+1]]:7: note: make it public and virtual 138 class PublicNonVirtualBaseClass { 139 virtual void f(); 140 141 public: ~PublicNonVirtualBaseClass()142 ~PublicNonVirtualBaseClass() {} 143 // CHECK-FIXES: virtual ~PublicNonVirtualBaseClass() {} 144 }; 145 146 class PublicNonVirtualNonBaseClass { // OK according to C.35, since this class does not have any virtual methods. 147 void f(); 148 149 public: ~PublicNonVirtualNonBaseClass()150 ~PublicNonVirtualNonBaseClass() {} 151 }; 152 153 class ProtectedNonVirtualClass { // OK 154 public: 155 virtual void f(); 156 157 protected: ~ProtectedNonVirtualClass()158 ~ProtectedNonVirtualClass() {} 159 }; 160 161 // CHECK-MESSAGES: :[[@LINE+7]]:7: warning: destructor of 'OverridingDerivedClass' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 162 // CHECK-MESSAGES: :[[@LINE+6]]:7: note: make it public and virtual 163 // CHECK-FIXES: class OverridingDerivedClass : ProtectedNonVirtualClass { 164 // CHECK-FIXES-NEXT: public: 165 // CHECK-FIXES-NEXT: virtual ~OverridingDerivedClass() = default; 166 // CHECK-FIXES-NEXT: void f() override; 167 // CHECK-FIXES-NEXT: }; 168 class OverridingDerivedClass : ProtectedNonVirtualClass { 169 public: 170 void f() override; // is implicitly virtual 171 }; 172 173 // CHECK-MESSAGES: :[[@LINE+7]]:7: warning: destructor of 'NonOverridingDerivedClass' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 174 // CHECK-MESSAGES: :[[@LINE+6]]:7: note: make it public and virtual 175 // CHECK-FIXES: class NonOverridingDerivedClass : ProtectedNonVirtualClass { 176 // CHECK-FIXES-NEXT: void m(); 177 // CHECK-FIXES-NEXT: public: 178 // CHECK-FIXES-NEXT: virtual ~NonOverridingDerivedClass() = default; 179 // CHECK-FIXES-NEXT: }; 180 class NonOverridingDerivedClass : ProtectedNonVirtualClass { 181 void m(); 182 }; 183 // inherits virtual method 184 185 // CHECK-MESSAGES: :[[@LINE+6]]:8: warning: destructor of 'OverridingDerivedStruct' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 186 // CHECK-MESSAGES: :[[@LINE+5]]:8: note: make it public and virtual 187 // CHECK-FIXES: struct OverridingDerivedStruct : ProtectedNonVirtualBaseStruct { 188 // CHECK-FIXES-NEXT: virtual ~OverridingDerivedStruct() = default; 189 // CHECK-FIXES-NEXT: void f() override; 190 // CHECK-FIXES-NEXT: }; 191 struct OverridingDerivedStruct : ProtectedNonVirtualBaseStruct { 192 void f() override; // is implicitly virtual 193 }; 194 195 // CHECK-MESSAGES: :[[@LINE+6]]:8: warning: destructor of 'NonOverridingDerivedStruct' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 196 // CHECK-MESSAGES: :[[@LINE+5]]:8: note: make it public and virtual 197 // CHECK-FIXES: struct NonOverridingDerivedStruct : ProtectedNonVirtualBaseStruct { 198 // CHECK-FIXES-NEXT: virtual ~NonOverridingDerivedStruct() = default; 199 // CHECK-FIXES-NEXT: void m(); 200 // CHECK-FIXES-NEXT: }; 201 struct NonOverridingDerivedStruct : ProtectedNonVirtualBaseStruct { 202 void m(); 203 }; 204 // inherits virtual method 205 206 namespace Bugzilla_51912 { 207 // Fixes https://bugs.llvm.org/show_bug.cgi?id=51912 208 209 // Forward declarations 210 // CHECK-MESSAGES-NOT: :[[@LINE+1]]:8: warning: destructor of 'ForwardDeclaredStruct' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 211 struct ForwardDeclaredStruct; 212 213 struct ForwardDeclaredStruct : PublicVirtualBaseStruct { 214 }; 215 216 // Normal Template 217 // CHECK-MESSAGES-NOT: :[[@LINE+2]]:8: warning: destructor of 'TemplatedDerived' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 218 template <typename T> 219 struct TemplatedDerived : PublicVirtualBaseStruct { 220 }; 221 222 TemplatedDerived<int> InstantiationWithInt; 223 224 // Derived from template, base has virtual dtor 225 // CHECK-MESSAGES-NOT: :[[@LINE+2]]:8: warning: destructor of 'DerivedFromTemplateVirtualBaseStruct' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 226 template <typename T> 227 struct DerivedFromTemplateVirtualBaseStruct : T { 228 virtual void foo(); 229 }; 230 231 DerivedFromTemplateVirtualBaseStruct<PublicVirtualBaseStruct> InstantiationWithPublicVirtualBaseStruct; 232 233 // Derived from template, base has *not* virtual dtor 234 // CHECK-MESSAGES: :[[@LINE+7]]:8: warning: destructor of 'DerivedFromTemplateNonVirtualBaseStruct<PublicNonVirtualBaseStruct>' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 235 // CHECK-MESSAGES: :[[@LINE+6]]:8: note: make it public and virtual 236 // CHECK-FIXES: struct DerivedFromTemplateNonVirtualBaseStruct : T { 237 // CHECK-FIXES-NEXT: virtual ~DerivedFromTemplateNonVirtualBaseStruct() = default; 238 // CHECK-FIXES-NEXT: virtual void foo(); 239 // CHECK-FIXES-NEXT: }; 240 template <typename T> 241 struct DerivedFromTemplateNonVirtualBaseStruct : T { 242 virtual void foo(); 243 }; 244 245 DerivedFromTemplateNonVirtualBaseStruct<PublicNonVirtualBaseStruct> InstantiationWithPublicNonVirtualBaseStruct; 246 247 // Derived from template, base has virtual dtor, to be used in a typedef 248 // CHECK-MESSAGES-NOT: :[[@LINE+2]]:8: warning: destructor of 'DerivedFromTemplateVirtualBaseStruct2' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 249 template <typename T> 250 struct DerivedFromTemplateVirtualBaseStruct2 : T { 251 virtual void foo(); 252 }; 253 254 using DerivedFromTemplateVirtualBaseStruct2Typedef = DerivedFromTemplateVirtualBaseStruct2<PublicVirtualBaseStruct>; 255 DerivedFromTemplateVirtualBaseStruct2Typedef InstantiationWithPublicVirtualBaseStruct2; 256 257 // Derived from template, base has *not* virtual dtor, to be used in a typedef 258 // CHECK-MESSAGES: :[[@LINE+7]]:8: warning: destructor of 'DerivedFromTemplateNonVirtualBaseStruct2<PublicNonVirtualBaseStruct>' is public and non-virtual [cppcoreguidelines-virtual-class-destructor] 259 // CHECK-MESSAGES: :[[@LINE+6]]:8: note: make it public and virtual 260 // CHECK-FIXES: struct DerivedFromTemplateNonVirtualBaseStruct2 : T { 261 // CHECK-FIXES-NEXT: virtual ~DerivedFromTemplateNonVirtualBaseStruct2() = default; 262 // CHECK-FIXES-NEXT: virtual void foo(); 263 // CHECK-FIXES-NEXT: }; 264 template <typename T> 265 struct DerivedFromTemplateNonVirtualBaseStruct2 : T { 266 virtual void foo(); 267 }; 268 269 using DerivedFromTemplateNonVirtualBaseStruct2Typedef = DerivedFromTemplateNonVirtualBaseStruct2<PublicNonVirtualBaseStruct>; 270 DerivedFromTemplateNonVirtualBaseStruct2Typedef InstantiationWithPublicNonVirtualBaseStruct2; 271 272 } // namespace Bugzilla_51912 273 274 namespace macro_tests { 275 #define MY_VIRTUAL virtual 276 #define CONCAT(x, y) x##y 277 278 // CHECK-MESSAGES: :[[@LINE+2]]:7: warning: destructor of 'FooBar1' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 279 // CHECK-MESSAGES: :[[@LINE+1]]:7: note: make it protected and non-virtual 280 class FooBar1 { 281 protected: 282 CONCAT(vir, tual) CONCAT(~Foo, Bar1()); // no-fixit 283 }; 284 285 // CHECK-MESSAGES: :[[@LINE+2]]:7: warning: destructor of 'FooBar2' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 286 // CHECK-MESSAGES: :[[@LINE+1]]:7: note: make it protected and non-virtual 287 class FooBar2 { 288 protected: 289 virtual CONCAT(~Foo, Bar2()); // FIXME: We should have a fixit for this. 290 }; 291 292 // CHECK-MESSAGES: :[[@LINE+6]]:7: warning: destructor of 'FooBar3' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 293 // CHECK-MESSAGES: :[[@LINE+5]]:7: note: make it protected and non-virtual 294 // CHECK-FIXES: class FooBar3 { 295 // CHECK-FIXES-NEXT: protected: 296 // CHECK-FIXES-NEXT: ~FooBar3(); 297 // CHECK-FIXES-NEXT: }; 298 class FooBar3 { 299 protected: 300 CONCAT(vir, tual) ~FooBar3(); 301 }; 302 303 // CHECK-MESSAGES: :[[@LINE+6]]:7: warning: destructor of 'FooBar4' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 304 // CHECK-MESSAGES: :[[@LINE+5]]:7: note: make it protected and non-virtual 305 // CHECK-FIXES: class FooBar4 { 306 // CHECK-FIXES-NEXT: protected: 307 // CHECK-FIXES-NEXT: ~CONCAT(Foo, Bar4()); 308 // CHECK-FIXES-NEXT: }; 309 class FooBar4 { 310 protected: 311 CONCAT(vir, tual) ~CONCAT(Foo, Bar4()); 312 }; 313 314 // CHECK-MESSAGES: :[[@LINE+3]]:7: warning: destructor of 'FooBar5' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 315 // CHECK-MESSAGES: :[[@LINE+2]]:7: note: make it protected and non-virtual 316 #define XMACRO(COLUMN1, COLUMN2) COLUMN1 COLUMN2 317 class FooBar5 { 318 protected: 319 XMACRO(CONCAT(vir, tual), ~CONCAT(Foo, Bar5());) // no-crash, no-fixit 320 }; 321 322 // CHECK-MESSAGES: :[[@LINE+2]]:7: warning: destructor of 'FooBar6' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 323 // CHECK-MESSAGES: :[[@LINE+1]]:7: note: make it protected and non-virtual 324 class FooBar6 { 325 protected: 326 MY_VIRTUAL ~FooBar6(); // FIXME: We should have a fixit for this. 327 }; 328 329 #undef XMACRO 330 #undef CONCAT 331 #undef MY_VIRTUAL 332 } // namespace macro_tests 333 334 namespace FinalClassCannotBeBaseClass { 335 class Base { 336 public: 337 Base() = default; 338 virtual void func() = 0; 339 340 protected: 341 ~Base() = default; 342 }; 343 344 // no-warning: 'MostDerived' cannot be a base class, since it's marked 'final'. 345 class MostDerived final : public Base { 346 public: 347 MostDerived() = default; 348 ~MostDerived() = default; 349 void func() final; 350 }; 351 } // namespace FinalClassCannotBeBaseClass 352