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: 11 virtual ~PrivateVirtualBaseStruct() {} 12 }; 13 14 struct PublicVirtualBaseStruct { // OK 15 virtual void f(); 16 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: 25 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: 47 ~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(); 54 ~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(); 60 ~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: 85 ~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(); 94 virtual ~PrivateVirtualBaseClass() {} 95 }; 96 97 class PublicVirtualBaseClass { // OK 98 virtual void f(); 99 100 public: 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: 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: 142 ~PublicNonVirtualBaseClass() {} 143 // CHECK-FIXES: virtual ~PublicNonVirtualBaseClass() {} 144 }; 145 146 class PublicNonVirtualNonBaseClass { // OK accoring to C.35, since this class does not have any virtual methods. 147 void f(); 148 149 public: 150 ~PublicNonVirtualNonBaseClass() {} 151 }; 152 153 class ProtectedNonVirtualClass { // OK 154 public: 155 virtual void f(); 156 157 protected: 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 CONCAT(x, y) x##y 276 277 // CHECK-MESSAGES: :[[@LINE+2]]:7: warning: destructor of 'FooBar1' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 278 // CHECK-MESSAGES: :[[@LINE+1]]:7: note: make it protected and non-virtual 279 class FooBar1 { 280 protected: 281 CONCAT(vir, tual) CONCAT(~Foo, Bar1()); // no-fixit 282 }; 283 284 // CHECK-MESSAGES: :[[@LINE+2]]:7: warning: destructor of 'FooBar2' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 285 // CHECK-MESSAGES: :[[@LINE+1]]:7: note: make it protected and non-virtual 286 class FooBar2 { 287 protected: 288 virtual CONCAT(~Foo, Bar2()); // FIXME: We should have a fixit for this. 289 }; 290 291 // CHECK-MESSAGES: :[[@LINE+6]]:7: warning: destructor of 'FooBar3' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 292 // CHECK-MESSAGES: :[[@LINE+5]]:7: note: make it protected and non-virtual 293 // CHECK-FIXES: class FooBar3 { 294 // CHECK-FIXES-NEXT: protected: 295 // CHECK-FIXES-NEXT: ~FooBar3(); 296 // CHECK-FIXES-NEXT: }; 297 class FooBar3 { 298 protected: 299 CONCAT(vir, tual) ~FooBar3(); 300 }; 301 302 // CHECK-MESSAGES: :[[@LINE+6]]:7: warning: destructor of 'FooBar4' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 303 // CHECK-MESSAGES: :[[@LINE+5]]:7: note: make it protected and non-virtual 304 // CHECK-FIXES: class FooBar4 { 305 // CHECK-FIXES-NEXT: protected: 306 // CHECK-FIXES-NEXT: ~CONCAT(Foo, Bar4()); 307 // CHECK-FIXES-NEXT: }; 308 class FooBar4 { 309 protected: 310 CONCAT(vir, tual) ~CONCAT(Foo, Bar4()); 311 }; 312 313 // CHECK-MESSAGES: :[[@LINE+3]]:7: warning: destructor of 'FooBar5' is protected and virtual [cppcoreguidelines-virtual-class-destructor] 314 // CHECK-MESSAGES: :[[@LINE+2]]:7: note: make it protected and non-virtual 315 #define XMACRO(COLUMN1, COLUMN2) COLUMN1 COLUMN2 316 class FooBar5 { 317 protected: 318 XMACRO(CONCAT(vir, tual), ~CONCAT(Foo, Bar5());) // no-crash, no-fixit 319 }; 320 #undef XMACRO 321 #undef CONCAT 322 } // namespace macro_tests 323 324 namespace FinalClassCannotBeBaseClass { 325 class Base { 326 public: 327 Base() = default; 328 virtual void func() = 0; 329 330 protected: 331 ~Base() = default; 332 }; 333 334 // no-warning: 'MostDerived' cannot be a base class, since it's marked 'final'. 335 class MostDerived final : public Base { 336 public: 337 MostDerived() = default; 338 ~MostDerived() = default; 339 void func() final; 340 }; 341 } // namespace FinalClassCannotBeBaseClass 342