243 lines · cpp
1// RUN: %clang_analyze_cc1 -analyzer-checker=webkit.RefCntblBaseVirtualDtor -verify %s2 3#include "mock-types.h"4 5namespace Detail {6 7template<typename Out, typename... In>8class CallableWrapperBase {9public:10 virtual ~CallableWrapperBase() { }11 virtual Out call(In...) = 0;12};13 14template<typename, typename, typename...> class CallableWrapper;15 16template<typename CallableType, typename Out, typename... In>17class CallableWrapper : public CallableWrapperBase<Out, In...> {18public:19 explicit CallableWrapper(CallableType&& callable)20 : m_callable(WTFMove(callable)) { }21 CallableWrapper(const CallableWrapper&) = delete;22 CallableWrapper& operator=(const CallableWrapper&) = delete;23 Out call(In... in) final;24private:25 CallableType m_callable;26};27 28} // namespace Detail29 30template<typename> class Function;31 32template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>*);33 34template <typename Out, typename... In>35class Function<Out(In...)> {36public:37 using Impl = Detail::CallableWrapperBase<Out, In...>;38 39 Function() = default;40 41 template<typename FunctionType>42 Function(FunctionType f);43 44 Out operator()(In... in) const;45 explicit operator bool() const { return !!m_callableWrapper; }46 47private:48 enum AdoptTag { Adopt };49 Function(Impl* impl, AdoptTag)50 : m_callableWrapper(impl)51 {52 }53 54 friend Function adopt<Out, In...>(Impl*);55 56 Impl* m_callableWrapper;57};58 59template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>* impl)60{61 return Function<Out(In...)>(impl, Function<Out(In...)>::Adopt);62}63 64enum class DestructionThread : unsigned char { Any, Main, MainRunLoop };65void ensureOnMainThread(Function<void()>&&); // Sync if called on main thread, async otherwise.66void ensureOnMainRunLoop(Function<void()>&&); // Sync if called on main run loop, async otherwise.67 68class ThreadSafeRefCountedBase {69public:70 ThreadSafeRefCountedBase() = default;71 72 void ref() const73 {74 ++m_refCount;75 }76 77 bool hasOneRef() const78 {79 return refCount() == 1;80 }81 82 unsigned refCount() const83 {84 return m_refCount;85 }86 87protected:88 bool derefBase() const89 {90 if (!--m_refCount) {91 m_refCount = 1;92 return true;93 }94 return false;95 }96 97private:98 mutable unsigned m_refCount { 1 };99};100 101template<class T, DestructionThread destructionThread = DestructionThread::Any> class ThreadSafeRefCounted : public ThreadSafeRefCountedBase {102public:103 void deref() const104 {105 if (!derefBase())106 return;107 108 if constexpr (destructionThread == DestructionThread::Any) {109 delete static_cast<const T*>(this);110 } else if constexpr (destructionThread == DestructionThread::Main) {111 ensureOnMainThread([this] {112 delete static_cast<const T*>(this);113 });114 } else if constexpr (destructionThread == DestructionThread::MainRunLoop) {115 auto deleteThis = [this] {116 delete static_cast<const T*>(this);117 };118 ensureOnMainThread(deleteThis);119 }120 }121 122protected:123 ThreadSafeRefCounted() = default;124};125 126class FancyRefCountedClass final : public ThreadSafeRefCounted<FancyRefCountedClass, DestructionThread::Main> {127public:128 static Ref<FancyRefCountedClass> create()129 {130 return adoptRef(*new FancyRefCountedClass());131 }132 133 virtual ~FancyRefCountedClass();134 135private:136 FancyRefCountedClass();137};138 139template<class T, DestructionThread destructionThread = DestructionThread::Any> class BadThreadSafeRefCounted : public ThreadSafeRefCountedBase {140public:141 void deref() const142 {143 if (!derefBase())144 return;145 146 [this] {147 delete static_cast<const T*>(this);148 };149 }150 151protected:152 BadThreadSafeRefCounted() = default;153};154 155class FancyRefCountedClass2 final : public ThreadSafeRefCounted<FancyRefCountedClass, DestructionThread::Main> {156// expected-warning@-1{{Class 'ThreadSafeRefCounted<FancyRefCountedClass, DestructionThread::Main>' is used as a base of class 'FancyRefCountedClass2' but doesn't have virtual destructor}}157public:158 static Ref<FancyRefCountedClass2> create()159 {160 return adoptRef(*new FancyRefCountedClass2());161 }162 163 virtual ~FancyRefCountedClass2();164 165private:166 FancyRefCountedClass2();167};168 169template<class T, DestructionThread destructionThread = DestructionThread::Any> class NestedThreadSafeRefCounted : public ThreadSafeRefCountedBase {170public:171 void deref() const172 {173 if (!derefBase())174 return;175 ensureOnMainRunLoop([&] {176 auto destroyThis = [&] {177 delete static_cast<const T*>(this);178 };179 destroyThis();180 });181 }182 183protected:184 NestedThreadSafeRefCounted() = default;185};186 187class FancyRefCountedClass3 final : public NestedThreadSafeRefCounted<FancyRefCountedClass3, DestructionThread::Main> {188public:189 static Ref<FancyRefCountedClass3> create()190 {191 return adoptRef(*new FancyRefCountedClass3());192 }193 194 virtual ~FancyRefCountedClass3();195 196private:197 FancyRefCountedClass3();198};199 200template<class T, DestructionThread destructionThread = DestructionThread::Any> class BadNestedThreadSafeRefCounted : public ThreadSafeRefCountedBase {201public:202 void deref() const203 {204 if (!derefBase())205 return;206 ensureOnMainThread([&] {207 auto destroyThis = [&] {208 delete static_cast<const T*>(this);209 };210 });211 }212 213protected:214 BadNestedThreadSafeRefCounted() = default;215};216 217class FancyRefCountedClass4 final : public BadNestedThreadSafeRefCounted<FancyRefCountedClass4, DestructionThread::Main> {218// expected-warning@-1{{Class 'BadNestedThreadSafeRefCounted<FancyRefCountedClass4, DestructionThread::Main>' is used as a base of class 'FancyRefCountedClass4' but doesn't have virtual destructor}}219public:220 static Ref<FancyRefCountedClass4> create()221 {222 return adoptRef(*new FancyRefCountedClass4());223 }224 225 virtual ~FancyRefCountedClass4();226 227private:228 FancyRefCountedClass4();229};230 231class FancyRefCountedClass5 final : public ThreadSafeRefCounted<FancyRefCountedClass5, DestructionThread::MainRunLoop> {232public:233 static Ref<FancyRefCountedClass5> create()234 {235 return adoptRef(*new FancyRefCountedClass5());236 }237 238 virtual ~FancyRefCountedClass5();239 240private:241 FancyRefCountedClass5();242};243