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