brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.0 KiB · 4e024de Raw
337 lines · plain
1// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UnretainedLambdaCapturesChecker -fobjc-arc -verify %s2 3#include "objc-mock-types.h"4 5namespace std {6 7template <typename T>8class unique_ptr {9private:10  T *t;11 12public:13  unique_ptr() : t(nullptr) { }14  unique_ptr(T *t) : t(t) { }15  ~unique_ptr() {16    if (t)17      delete t;18  }19  template <typename U> unique_ptr(unique_ptr<U>&& u)20    : t(u.t)21  {22    u.t = nullptr;23  }24  T *get() const { return t; }25  T *operator->() const { return t; }26  T &operator*() const { return *t; }27  unique_ptr &operator=(T *) { return *this; }28  explicit operator bool() const { return !!t; }29};30 31};32 33namespace WTF {34 35namespace Detail {36 37template<typename Out, typename... In>38class CallableWrapperBase {39public:40    virtual ~CallableWrapperBase() { }41    virtual Out call(In...) = 0;42};43 44template<typename, typename, typename...> class CallableWrapper;45 46template<typename CallableType, typename Out, typename... In>47class CallableWrapper : public CallableWrapperBase<Out, In...> {48public:49    explicit CallableWrapper(CallableType& callable)50        : m_callable(callable) { }51    Out call(In... in) final { return m_callable(in...); }52 53private:54    CallableType m_callable;55};56 57} // namespace Detail58 59template<typename> class Function;60 61template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>*);62 63template <typename Out, typename... In>64class Function<Out(In...)> {65public:66    using Impl = Detail::CallableWrapperBase<Out, In...>;67 68    Function() = default;69 70    template<typename FunctionType>71    Function(FunctionType f)72        : m_callableWrapper(new Detail::CallableWrapper<FunctionType, Out, In...>(f)) { }73 74    Out operator()(In... in) const { return m_callableWrapper->call(in...); }75    explicit operator bool() const { return !!m_callableWrapper; }76 77private:78    enum AdoptTag { Adopt };79    Function(Impl* impl, AdoptTag)80        : m_callableWrapper(impl)81    {82    }83 84    friend Function adopt<Out, In...>(Impl*);85 86    std::unique_ptr<Impl> m_callableWrapper;87};88 89template<typename Out, typename... In> Function<Out(In...)> adopt(Detail::CallableWrapperBase<Out, In...>* impl)90{91    return Function<Out(In...)>(impl, Function<Out(In...)>::Adopt);92}93 94template <typename KeyType, typename ValueType>95class HashMap {96public:97  HashMap();98  HashMap([[clang::noescape]] const Function<ValueType()>&);99  void ensure(const KeyType&, [[clang::noescape]] const Function<ValueType()>&);100  bool operator+([[clang::noescape]] const Function<ValueType()>&) const;101  static void ifAny(HashMap, [[clang::noescape]] const Function<bool(ValueType)>&);102 103private:104  ValueType* m_table { nullptr };105};106 107} // namespace WTF108 109struct A {110  static void b();111};112 113SomeObj* make_obj();114CFMutableArrayRef make_cf();115dispatch_queue_t make_os();116 117void someFunction();118template <typename Callback> void call(Callback callback) {119  someFunction();120  callback();121}122void callAsync(const WTF::Function<void()>&);123 124void raw_ptr() {125  SomeObj* obj = make_obj();126  auto foo1 = [obj](){127    [obj doWork];128  };129  auto foo2 = [&obj](){130    [obj doWork];131  };132  auto foo3 = [&](){133    [obj doWork];134    obj = nullptr;135  };136  auto foo4 = [=](){137    [obj doWork];138  };139  140  auto cf = make_cf();141  auto bar1 = [cf](){142    // expected-warning@-1{{Captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}143    CFArrayAppendValue(cf, nullptr);144  };145  auto bar2 = [&cf](){146    // expected-warning@-1{{Captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}147    CFArrayAppendValue(cf, nullptr);148  };149  auto bar3 = [&](){150    CFArrayAppendValue(cf, nullptr);151    // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}152    cf = nullptr;153  };154  auto bar4 = [=](){155    CFArrayAppendValue(cf, nullptr);156    // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}157  };158 159  auto os = make_os();160  auto baz1 = [os](){161    dispatch_queue_get_label(os);162  };163  auto baz2 = [&os](){164    dispatch_queue_get_label(os);165  };166  auto baz3 = [&](){167    dispatch_queue_get_label(os);168    os = nullptr;169  };170  auto baz4 = [=](){171    dispatch_queue_get_label(os);172  };173 174  call(foo1);175  call(foo2);176  call(foo3);177  call(foo4);178 179  call(bar1);180  call(bar2);181  call(bar3);182  call(bar4);183 184  call(baz1);185  call(baz2);186  call(baz3);187  call(baz4);188}189 190void quiet() {191// This code is not expected to trigger any warnings.192  SomeObj *obj;193 194  auto foo3 = [&]() {};195  auto foo4 = [=]() {};196 197  call(foo3);198  call(foo4);199 200  obj = nullptr;201}202 203template <typename Callback>204void map(SomeObj* start, [[clang::noescape]] Callback&& callback)205{206  while (start) {207    callback(start);208    start = [start next];209  }210}211 212template <typename Callback1, typename Callback2>213void doubleMap(SomeObj* start, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)214{215  while (start) {216    callback1(start);217    callback2(start);218    start = [start next];219  }220}221 222template <typename Callback1, typename Callback2>223void get_count_cf(CFArrayRef array, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)224{225  auto count = CFArrayGetCount(array);226  callback1(count);227  callback2(count);228}229 230template <typename Callback1, typename Callback2>231void get_count_os(dispatch_queue_t queue, [[clang::noescape]] Callback1&& callback1, Callback2&& callback2)232{233  auto* label = dispatch_queue_get_label(queue);234  callback1(label);235  callback2(label);236}237 238void noescape_lambda() {239  SomeObj* someObj = make_obj();240  SomeObj* otherObj = make_obj();241  map(make_obj(), [&](SomeObj *obj) {242    [otherObj doWork];243  });244  doubleMap(make_obj(), [&](SomeObj *obj) {245    [otherObj doWork];246  }, [&](SomeObj *obj) {247    [otherObj doWork];248  });249  ([&] {250    [someObj doWork];251  })();252 253  CFMutableArrayRef someCF = make_cf();254  get_count_cf(make_cf(), [&](CFIndex count) {255    CFArrayAppendValue(someCF, nullptr);256  }, [&](CFIndex count) {257    CFArrayAppendValue(someCF, nullptr);258    // expected-warning@-1{{Implicitly captured reference 'someCF' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}259  });260 261  dispatch_queue_t someOS = make_os();262  get_count_os(make_os(), [&](const char* label) {263    dispatch_queue_get_label(someOS);264  }, [&](const char* label) {265    dispatch_queue_get_label(someOS);266  });267}268 269void callFunctionOpaque(WTF::Function<void()>&&);270void callFunction(WTF::Function<void()>&& function) {271  someFunction();272  function();273}274 275void lambda_converted_to_function(SomeObj* obj, CFMutableArrayRef cf, dispatch_queue_t os)276{277  callFunction([&]() {278    [obj doWork];279    CFArrayAppendValue(cf, nullptr);280    // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}281    dispatch_queue_get_label(os);282  });283  callFunctionOpaque([&]() {284    [obj doWork];285    CFArrayAppendValue(cf, nullptr);286    // expected-warning@-1{{Implicitly captured reference 'cf' to unretained type is unsafe [alpha.webkit.UnretainedLambdaCapturesChecker]}}287    dispatch_queue_get_label(os);288  });289}290 291@interface ObjWithSelf : NSObject {292  RetainPtr<id> delegate;293  OSObjectPtr<dispatch_queue_t> queue;294}295-(void)doWork;296-(void)doMoreWork;297-(void)run;298@end299 300@implementation ObjWithSelf301-(void)doWork {302  auto doWork = [&] {303    someFunction();304    [delegate doWork];305  };306  auto doMoreWork = [=] {307    someFunction();308    [delegate doWork];309  };310  auto doExtraWork = [&, protectedSelf = retainPtr(self)] {311    someFunction();312    [delegate doWork];313  };314  auto* queuePtr = queue.get();315  auto doAdditionalWork = [&] {316    someFunction();317    dispatch_queue_get_label(queuePtr);318  };319  callFunctionOpaque(doWork);320  callFunctionOpaque(doMoreWork);321  callFunctionOpaque(doExtraWork);322  callFunctionOpaque(doAdditionalWork);323}324 325-(void)doMoreWork {326  auto doWork = [self, protectedSelf = retainPtr(self)] {327    someFunction();328    [self doWork];329  };330  callFunctionOpaque(doWork);331}332 333-(void)run {334  someFunction();335}336@end337