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