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 according 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 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 | |