brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.4 KiB · 4209db1 Raw
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