xref: /llvm-project/clang/test/Analysis/Checkers/WebKit/ref-cntbl-base-virtual-dtor-templates.cpp (revision faef8b4aa245a671e2013319e8073a9fc52ae12e)
1 // RUN: %clang_analyze_cc1 -analyzer-checker=webkit.RefCntblBaseVirtualDtor -verify %s
2 
3 struct RefCntblBase {
refRefCntblBase4   void ref() {}
derefRefCntblBase5   void deref() {}
6 };
7 
8 template<class T>
9 struct DerivedClassTmpl1 : T { };
10 // expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl1<RefCntblBase>' but doesn't have virtual destructor}}
11 
12 DerivedClassTmpl1<RefCntblBase> a;
foo(DerivedClassTmpl1<RefCntblBase> & obj)13 void foo(DerivedClassTmpl1<RefCntblBase>& obj) { obj.deref(); }
14 
15 template<class T>
16 struct DerivedClassTmpl2 : T { };
17 // expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl2<RefCntblBase>' but doesn't have virtual destructor}}
18 
foo(T)19 template<class T> int foo(T) { DerivedClassTmpl2<T> f; return 42; }
20 int b = foo(RefCntblBase{});
21 
22 
23 template<class T>
24 struct DerivedClassTmpl3 : T { };
25 // expected-warning@-1{{Struct 'RefCntblBase' is used as a base of struct 'DerivedClassTmpl3<RefCntblBase>' but doesn't have virtual destructor}}
26 
27 typedef DerivedClassTmpl3<RefCntblBase> Foo;
28 Foo c;
29 
30 namespace WTF {
31 
32 class RefCountedBase {
33 public:
ref() const34   void ref() const { ++count; }
35 
36 protected:
derefBase() const37   bool derefBase() const
38   {
39     return !--count;
40   }
41 
42 private:
43   mutable unsigned count;
44 };
45 
46 template <typename T>
47 class RefCounted : public RefCountedBase {
48 public:
deref() const49   void deref() const {
50     if (derefBase())
51       delete const_cast<T*>(static_cast<const T*>(this));
52   }
53 
54 protected:
RefCounted()55   RefCounted() { }
56 };
57 
58 template <typename X, typename T>
59 class ExoticRefCounted : public RefCountedBase {
60 public:
deref() const61   void deref() const {
62     if (derefBase())
63       delete (const_cast<T*>(static_cast<const T*>(this)));
64   }
65 };
66 
67 template <typename X, typename T>
68 class BadBase : RefCountedBase {
69 public:
deref() const70   void deref() const {
71     if (derefBase())
72       delete (const_cast<X*>(static_cast<const X*>(this)));
73   }
74 };
75 
76 template <typename T>
77 class FancyDeref {
78 public:
ref() const79   void ref() const
80   {
81     ++refCount;
82   }
83 
deref() const84   void deref() const
85   {
86     --refCount;
87     if (refCount)
88       return;
89     auto deleteThis = [this] {
90       delete static_cast<const T*>(this);
91     };
92     deleteThis();
93   }
94 private:
95   mutable unsigned refCount { 0 };
96 };
97 
98 namespace Detail {
99 
100   template<typename Out, typename... In>
101   class CallableWrapperBase {
102   public:
~CallableWrapperBase()103     virtual ~CallableWrapperBase() { }
104     virtual Out call(In...) = 0;
105   };
106 
107   template<typename, typename, typename...> class CallableWrapper;
108 
109   template<typename CallableType, typename Out, typename... In>
110   class CallableWrapper : public CallableWrapperBase<Out, In...> {
111   public:
CallableWrapper(CallableType && callable)112     explicit CallableWrapper(CallableType&& callable)
113         : m_callable(WTFMove(callable)) { }
114     CallableWrapper(const CallableWrapper&) = delete;
115     CallableWrapper& operator=(const CallableWrapper&) = delete;
call(In...in)116     Out call(In... in) final { return m_callable(in...); }
117   private:
118     CallableType m_callable;
119   };
120 
121 } // namespace Detail
122 
123 template<typename> class Function;
124 
125 template <typename Out, typename... In>
126 class Function<Out(In...)> {
127 public:
128   using Impl = Detail::CallableWrapperBase<Out, In...>;
129 
130   Function() = default;
131 
132   template<typename CallableType>
Function(CallableType && callable)133   Function(CallableType&& callable)
134       : m_callableWrapper(new Detail::CallableWrapper<CallableType, Out, In...>>(callable)) { }
135 
136   template<typename FunctionType>
Function(FunctionType f)137   Function(FunctionType f)
138       : m_callableWrapper(new Detail::CallableWrapper<FunctionType, Out, In...>>(f)) { }
139 
~Function()140   ~Function() {
141   }
142 
operator ()(In...in) const143   Out operator()(In... in) const {
144       ASSERT(m_callableWrapper);
145       return m_callableWrapper->call(in...);
146   }
147 
operator bool() const148   explicit operator bool() const { return !!m_callableWrapper; }
149 
150 private:
151   Impl* m_callableWrapper;
152 };
153 
154 void ensureOnMainThread(const Function<void()>&& function);
155 
156 enum class DestructionThread { Any, MainThread };
157 
158 template <typename T, DestructionThread destructionThread = DestructionThread::Any>
159 class FancyDeref2 {
160 public:
ref() const161   void ref() const
162   {
163     ++refCount;
164   }
165 
deref() const166   void deref() const
167   {
168     --refCount;
169     if (refCount)
170       return;
171     const_cast<FancyDeref2<T, destructionThread>*>(this)->destroy();
172   }
173 
174 private:
destroy()175   void destroy() {
176     delete static_cast<T*>(this);
177   }
178   mutable unsigned refCount { 0 };
179 };
180 
181 template <typename S>
182 class DerivedFancyDeref2 : public FancyDeref2<S> {
183 };
184 
185 template <typename T>
186 class BadFancyDeref {
187 public:
ref() const188   void ref() const
189   {
190     ++refCount;
191   }
192 
deref() const193   void deref() const
194   {
195     --refCount;
196     if (refCount)
197       return;
198     auto deleteThis = [this] {
199       delete static_cast<const T*>(this);
200     };
201     delete this;
202   }
203 private:
204   mutable unsigned refCount { 0 };
205 };
206 
207 template <typename T>
208 class ThreadSafeRefCounted {
209 public:
ref() const210   void ref() const { ++refCount; }
deref() const211   void deref() const {
212     if (!--refCount)
213       delete const_cast<T*>(static_cast<const T*>(this));
214   }
215 private:
216   mutable unsigned refCount { 0 };
217 };
218 
219 template <typename T>
220 class ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr {
221 public:
ref() const222   void ref() const { ++refCount; }
deref() const223   void deref() const {
224     if (!--refCount)
225       delete const_cast<T*>(static_cast<const T*>(this));
226   }
227 private:
228   mutable unsigned refCount { 0 };
229 };
230 
231 } // namespace WTF
232 
233 class DerivedClass4 : public WTF::RefCounted<DerivedClass4> { };
234 
235 class DerivedClass4b : public WTF::ExoticRefCounted<int, DerivedClass4b> { };
236 
237 class DerivedClass4cSub;
238 class DerivedClass4c : public WTF::BadBase<DerivedClass4cSub, DerivedClass4c> { };
239 // expected-warning@-1{{Class 'WTF::BadBase<DerivedClass4cSub, DerivedClass4c>' is used as a base of class 'DerivedClass4c' but doesn't have virtual destructor}}
240 class DerivedClass4cSub : public DerivedClass4c { };
UseDerivedClass4c(DerivedClass4c & obj)241 void UseDerivedClass4c(DerivedClass4c &obj) { obj.deref(); }
242 
243 class DerivedClass4d : public WTF::RefCounted<DerivedClass4d> {
244 public:
~DerivedClass4d()245   virtual ~DerivedClass4d() { }
246 };
247 class DerivedClass4dSub : public DerivedClass4d { };
248 
249 class DerivedClass5 : public DerivedClass4 { };
250 // expected-warning@-1{{Class 'DerivedClass4' is used as a base of class 'DerivedClass5' but doesn't have virtual destructor}}
UseDerivedClass5(DerivedClass5 & obj)251 void UseDerivedClass5(DerivedClass5 &obj) { obj.deref(); }
252 
253 class DerivedClass6 : public WTF::ThreadSafeRefCounted<DerivedClass6> { };
UseDerivedClass6(DerivedClass6 & obj)254 void UseDerivedClass6(DerivedClass6 &obj) { obj.deref(); }
255 
256 class DerivedClass7 : public DerivedClass6 { };
257 // expected-warning@-1{{Class 'DerivedClass6' is used as a base of class 'DerivedClass7' but doesn't have virtual destructor}}
UseDerivedClass7(DerivedClass7 & obj)258 void UseDerivedClass7(DerivedClass7 &obj) { obj.deref(); }
259 
260 class DerivedClass8 : public WTF::ThreadSafeRefCountedAndCanMakeThreadSafeWeakPtr<DerivedClass8> { };
UseDerivedClass8(DerivedClass8 & obj)261 void UseDerivedClass8(DerivedClass8 &obj) { obj.deref(); }
262 
263 class DerivedClass9 : public DerivedClass8 { };
264 // expected-warning@-1{{Class 'DerivedClass8' is used as a base of class 'DerivedClass9' but doesn't have virtual destructor}}
UseDerivedClass9(DerivedClass9 & obj)265 void UseDerivedClass9(DerivedClass9 &obj) { obj.deref(); }
266 
267 class DerivedClass10 : public WTF::FancyDeref<DerivedClass10> { };
UseDerivedClass10(DerivedClass10 & obj)268 void UseDerivedClass10(DerivedClass10 &obj) { obj.deref(); }
269 
270 class DerivedClass10b : public WTF::DerivedFancyDeref2<DerivedClass10b> { };
UseDerivedClass10b(DerivedClass10b & obj)271 void UseDerivedClass10b(DerivedClass10b &obj) { obj.deref(); }
272 
273 class DerivedClass10c : public WTF::BadFancyDeref<DerivedClass10c> { };
274 // expected-warning@-1{{Class 'WTF::BadFancyDeref<DerivedClass10c>' is used as a base of class 'DerivedClass10c' but doesn't have virtual destructor}}
UseDerivedClass10c(DerivedClass10c & obj)275 void UseDerivedClass10c(DerivedClass10c &obj) { obj.deref(); }
276 
277 class BaseClass1 {
278 public:
ref() const279   void ref() const { ++refCount; }
280   void deref() const;
281 private:
282   enum class Type { Base, Derived } type { Type::Base };
283   mutable unsigned refCount { 0 };
284 };
285 
286 class DerivedClass11 : public BaseClass1 { };
287 
deref() const288 void BaseClass1::deref() const
289 {
290   --refCount;
291   if (refCount)
292     return;
293   switch (type) {
294   case Type::Base:
295     delete const_cast<BaseClass1*>(this);
296     break;
297   case Type::Derived:
298     delete const_cast<DerivedClass11*>(static_cast<const DerivedClass11*>(this));
299     break;
300   }
301 }
302 
UseDerivedClass11(DerivedClass11 & obj)303 void UseDerivedClass11(DerivedClass11& obj) { obj.deref(); }
304 
305 class BaseClass2;
306 static void deleteBase2(BaseClass2*);
307 
308 class BaseClass2 {
309 public:
ref() const310   void ref() const { ++refCount; }
deref() const311   void deref() const
312   {
313     if (!--refCount)
314       deleteBase2(const_cast<BaseClass2*>(this));
315   }
isDerived()316   virtual bool isDerived() { return false; }
317 private:
318   mutable unsigned refCount { 0 };
319 };
320 
321 class DerivedClass12 : public BaseClass2 {
isDerived()322   bool isDerived() final { return true; }
323 };
324 
UseDerivedClass11(DerivedClass12 & obj)325 void UseDerivedClass11(DerivedClass12& obj) { obj.deref(); }
326 
deleteBase2(BaseClass2 * obj)327 void deleteBase2(BaseClass2* obj) {
328   if (obj->isDerived())
329     delete static_cast<DerivedClass12*>(obj);
330   else
331     delete obj;
332 }
333 
334 class BaseClass3 {
335 public:
ref() const336   void ref() const { ++refCount; }
deref() const337   void deref() const
338   {
339     if (!--refCount)
340       const_cast<BaseClass3*>(this)->destory();
341   }
isDerived()342   virtual bool isDerived() { return false; }
343 
344 private:
345   void destory();
346 
347   mutable unsigned refCount { 0 };
348 };
349 
350 class DerivedClass13 : public BaseClass3 {
isDerived()351   bool isDerived() final { return true; }
352 };
353 
UseDerivedClass11(DerivedClass13 & obj)354 void UseDerivedClass11(DerivedClass13& obj) { obj.deref(); }
355 
destory()356 void BaseClass3::destory() {
357   if (isDerived())
358     delete static_cast<DerivedClass13*>(this);
359   else
360     delete this;
361 }
362 
363 class RecursiveBaseClass {
364 public:
ref() const365   void ref() const {
366     if (otherObject)
367       otherObject->ref();
368     else
369       ++refCount;
370   }
deref() const371   void deref() const {
372     if (otherObject)
373       otherObject->deref();
374     else {
375       --refCount;
376       if (refCount)
377         return;
378       delete this;
379     }
380   }
381 private:
382   RecursiveBaseClass* otherObject { nullptr };
383   mutable unsigned refCount { 0 };
384 };
385 
386 class RecursiveDerivedClass : public RecursiveBaseClass { };
387 // expected-warning@-1{{Class 'RecursiveBaseClass' is used as a base of class 'RecursiveDerivedClass' but doesn't have virtual destructor}}
388 
389 class DerivedClass14 : public WTF::RefCounted<DerivedClass14> {
390 public:
~DerivedClass14()391   virtual ~DerivedClass14() { }
392 };
393 
UseDerivedClass14(DerivedClass14 & obj)394 void UseDerivedClass14(DerivedClass14& obj) { obj.deref(); }
395 
396 class DerivedClass15 : public DerivedClass14 { };
397 
UseDerivedClass15(DerivedClass15 & obj)398 void UseDerivedClass15(DerivedClass15& obj) { obj.deref(); }
399