xref: /llvm-project/clang/test/Analysis/Checkers/WebKit/uncounted-obj-arg.cpp (revision 73b577cc8c8a8ceeac87de5953a2c643e125d43e)
1 // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
2 
3 #include "mock-types.h"
4 #include "mock-system-header.h"
5 
6 void WTFBreakpointTrap();
7 void WTFCrashWithInfo(int, const char*, const char*, int);
8 void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion);
9 void WTFReportBacktrace(void);
10 
11 void WTFCrash(void);
12 void WTFCrashWithSecurityImplication(void);
13 
14 inline void compilerFenceForCrash()
15 {
16     asm volatile("" ::: "memory");
17 }
18 
19 inline void isIntegralOrPointerType() { }
20 
21 template<typename T, typename... Types>
22 void isIntegralOrPointerType(T, Types... types)
23 {
24     static_assert(sizeof(char) < sizeof(short), "All types need to be bitwise_cast-able to integral type for logging");
25     isIntegralOrPointerType(types...);
26 }
27 
28 #define CRASH_WITH_INFO(...) do { \
29     isIntegralOrPointerType(__VA_ARGS__); \
30     compilerFenceForCrash(); \
31     WTFBreakpointTrap(); \
32     __builtin_unreachable(); \
33 } while (0)
34 
35 #define RELEASE_ASSERT(assertion, ...) do { \
36     if (!(assertion)) \
37         CRASH_WITH_INFO(__VA_ARGS__); \
38 } while (0)
39 
40 #define ASSERT(assertion, ...) do { \
41     if (!(assertion)) { \
42         WTFReportAssertionFailure(__FILE__, __LINE__, __PRETTY_FUNCTION__, #assertion); \
43         CRASH_WITH_INFO(__VA_ARGS__); \
44     } \
45 } while (0)
46 
47 #if !defined(ALWAYS_INLINE)
48 #define ALWAYS_INLINE inline
49 #endif
50 
51 void WTFCrashWithInfoImpl(int line, const char* file, const char* function, int counter, unsigned long reason);
52 void WTFCrashWithInfo(int line, const char* file, const char* function, int counter);
53 
54 template<typename T>
55 ALWAYS_INLINE unsigned long wtfCrashArg(T* arg) { return reinterpret_cast<unsigned long>(arg); }
56 
57 template<typename T>
58 ALWAYS_INLINE unsigned long wtfCrashArg(T arg) { return arg; }
59 
60 template<typename T>
61 void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, T reason)
62 {
63     WTFCrashWithInfoImpl(line, file, function, counter, wtfCrashArg(reason));
64 }
65 
66 template<typename ToType, typename FromType>
67 ToType bitwise_cast(FromType from);
68 
69 namespace std {
70 
71 template<typename T>
72 T* addressof(T& arg);
73 
74 template<typename T>
75 T&& forward(T& arg);
76 
77 template<typename T>
78 T&& move( T&& t );
79 
80 } // namespace std
81 
82 bool isMainThread();
83 bool isMainThreadOrGCThread();
84 bool isMainRunLoop();
85 bool isWebThread();
86 bool isUIThread();
87 bool mayBeGCThread();
88 
89 enum class Flags : unsigned short {
90   Flag1 = 1 << 0,
91   Flag2 = 1 << 1,
92   Flag3 = 1 << 2,
93 };
94 
95 template<typename E> class OptionSet {
96 public:
97   using StorageType = unsigned short;
98 
99   static constexpr OptionSet fromRaw(StorageType rawValue) {
100     return OptionSet(static_cast<E>(rawValue), FromRawValue);
101   }
102 
103   constexpr OptionSet() = default;
104 
105   constexpr OptionSet(E e)
106     : m_storage(static_cast<StorageType>(e)) {
107   }
108 
109   constexpr StorageType toRaw() const { return m_storage; }
110 
111   constexpr bool isEmpty() const { return !m_storage; }
112 
113   constexpr explicit operator bool() const { return !isEmpty(); }
114 
115   constexpr bool contains(E option) const { return containsAny(option); }
116   constexpr bool containsAny(OptionSet optionSet) const {
117     return !!(*this & optionSet);
118   }
119 
120   constexpr bool containsAll(OptionSet optionSet) const {
121     return (*this & optionSet) == optionSet;
122   }
123 
124   constexpr void add(OptionSet optionSet) { m_storage |= optionSet.m_storage; }
125 
126   constexpr void remove(OptionSet optionSet)
127   {
128       m_storage &= ~optionSet.m_storage;
129   }
130 
131   constexpr void set(OptionSet optionSet, bool value)
132   {
133     if (value)
134       add(optionSet);
135     else
136       remove(optionSet);
137   }
138 
139   constexpr friend OptionSet operator|(OptionSet lhs, OptionSet rhs) {
140     return fromRaw(lhs.m_storage | rhs.m_storage);
141   }
142 
143   constexpr friend OptionSet operator&(OptionSet lhs, OptionSet rhs) {
144     return fromRaw(lhs.m_storage & rhs.m_storage);
145   }
146 
147   constexpr friend OptionSet operator-(OptionSet lhs, OptionSet rhs) {
148     return fromRaw(lhs.m_storage & ~rhs.m_storage);
149   }
150 
151   constexpr friend OptionSet operator^(OptionSet lhs, OptionSet rhs) {
152     return fromRaw(lhs.m_storage ^ rhs.m_storage);
153   }
154 
155 private:
156   enum InitializationTag { FromRawValue };
157   constexpr OptionSet(E e, InitializationTag)
158     : m_storage(static_cast<StorageType>(e)) {
159   }
160   StorageType m_storage { 0 };
161 };
162 
163 int atoi(const char* str);
164 
165 class Number {
166 public:
167   Number(int v) : v(v) { }
168   Number(double);
169   Number(const char* str) : v(atoi(str)) { }
170   Number operator+(const Number&);
171   Number& operator++() { ++v; return *this; }
172   Number operator++(int) { Number returnValue(v); ++v; return returnValue; }
173   const int& value() const { return v; }
174   void someMethod();
175 
176 private:
177   int v;
178 };
179 
180 class DerivedNumber : public Number {
181 public:
182   DerivedNumber(char c) : Number(c - '0') { }
183   DerivedNumber(const char* str) : Number(atoi(str)) { }
184 };
185 
186 class ComplexNumber {
187 public:
188   ComplexNumber() : realPart(0), complexPart(0) { }
189   ComplexNumber(int real, const char* str) : realPart(real), complexPart(str) { }
190   ComplexNumber(const ComplexNumber&);
191   ComplexNumber& operator++() { realPart.someMethod(); return *this; }
192   ComplexNumber operator++(int);
193   ComplexNumber& operator<<(int);
194   ComplexNumber& operator+();
195 
196   const Number& real() const { return realPart; }
197 
198 private:
199   Number realPart;
200   Number complexPart;
201 };
202 
203 class ObjectWithNonTrivialDestructor {
204 public:
205   ObjectWithNonTrivialDestructor() { }
206   ObjectWithNonTrivialDestructor(unsigned v) : v(v) { }
207   ~ObjectWithNonTrivialDestructor() { }
208 
209   unsigned value() const { return v; }
210 
211 private:
212   unsigned v { 0 };
213 };
214 
215 class ObjectWithMutatingDestructor {
216 public:
217   ObjectWithMutatingDestructor() : n(0) { }
218   ObjectWithMutatingDestructor(int n) : n(n) { }
219   ~ObjectWithMutatingDestructor() { n.someMethod(); }
220 
221   unsigned value() const { return n.value(); }
222 
223 private:
224   Number n;
225 };
226 
227 class BaseType {
228 public:
229   BaseType() : n(0) { }
230   BaseType(int v) : n(v) { }
231   BaseType(const char*);
232 private:
233   Number n;
234 };
235 
236 class SomeType : public BaseType {
237 public:
238   using BaseType::BaseType;
239 };
240 
241 void __libcpp_verbose_abort(const char *__format, ...);
242 
243 class RefCounted {
244 public:
245   void ref() const;
246   void deref() const;
247 
248   void method();
249   void someFunction();
250   int otherFunction();
251   unsigned recursiveTrivialFunction(int n) { return !n ? 1 : recursiveTrivialFunction(n - 1);  }
252   unsigned recursiveComplexFunction(int n) { return !n ? otherFunction() : recursiveComplexFunction(n - 1);  }
253   unsigned mutuallyRecursiveFunction1(int n) { return n < 0 ? 1 : (n % 2 ? mutuallyRecursiveFunction2(n - 2) : mutuallyRecursiveFunction1(n - 1)); }
254   unsigned mutuallyRecursiveFunction2(int n) { return n < 0 ? 1 : (n % 3 ? mutuallyRecursiveFunction2(n - 3) : mutuallyRecursiveFunction1(n - 2)); }
255   unsigned mutuallyRecursiveFunction3(int n) { return n < 0 ? 1 : (n % 5 ? mutuallyRecursiveFunction3(n - 5) : mutuallyRecursiveFunction4(n - 3)); }
256   unsigned mutuallyRecursiveFunction4(int n) { return n < 0 ? 1 : (n % 7 ? otherFunction() : mutuallyRecursiveFunction3(n - 3)); }
257   unsigned recursiveFunction5(unsigned n) { return n > 100 ? 2 : (n % 2 ? recursiveFunction5(n + 1) : recursiveFunction6(n + 2)); }
258   unsigned recursiveFunction6(unsigned n) { return n > 100 ? 3 : (n % 2 ? recursiveFunction6(n % 7) : recursiveFunction7(n % 5)); }
259   unsigned recursiveFunction7(unsigned n) { return n > 100 ? 5 : recursiveFunction7(n * 5); }
260 
261   void mutuallyRecursive8() { mutuallyRecursive9(); someFunction(); }
262   void mutuallyRecursive9() { mutuallyRecursive8(); }
263 
264   int recursiveCost() {
265     unsigned totalCost = 0;
266     for (unsigned i = 0; i < sizeof(children)/sizeof(*children); ++i) {
267       if (auto* child = children[i])
268         totalCost += child->recursiveCost();
269     }
270     return totalCost;
271   }
272 
273   int trivial1() { return 123; }
274   float trivial2() { return 0.3; }
275   float trivial3() { return (float)0.4; }
276   float trivial4() { return 0.5f; }
277   char trivial5() { return 'a'; }
278   const char *trivial6() { return "abc"; }
279   int trivial7() { return (1); }
280   Number trivial8() { return Number { 5 }; }
281   int trivial9() { return 3 + 4; }
282   int trivial10() { return 0x1010 | 0x1; }
283   int trivial11(int v) { return v + 1; }
284   const char *trivial12(char *p) { return p ? "str" : "null"; }
285   int trivial13(int v) {
286     if (v)
287       return 123;
288     else
289       return 0;
290   }
291   int trivial14(int v) {
292     switch (v) {
293       case 1:
294         return 100;
295       case 2:
296         return 200;
297       default:
298         return 300;
299     }
300     return 0;
301   }
302   void *trivial15() { return static_cast<void*>(this); }
303   unsigned long trivial16() { return *reinterpret_cast<unsigned long*>(this); }
304   RefCounted& trivial17() const { return const_cast<RefCounted&>(*this); }
305   RefCounted& trivial18() const { RELEASE_ASSERT(this, "this must be not null"); return const_cast<RefCounted&>(*this); }
306   void trivial19() const { return; }
307 
308   static constexpr unsigned numBits = 4;
309   int trivial20() { return v >> numBits; }
310 
311   const int* trivial21() { return number ? &number->value() : nullptr; }
312 
313   enum class Enum : unsigned short  {
314       Value1 = 1,
315       Value2 = 2,
316   };
317   bool trivial22() { return enumValue == Enum::Value1; }
318 
319   bool trivial23() const { return OptionSet<Flags>::fromRaw(v).contains(Flags::Flag1); }
320   int trivial24() const { ASSERT(v); return v; }
321   unsigned trivial25() const { return __c11_atomic_load((volatile _Atomic(unsigned) *)&v, __ATOMIC_RELAXED); }
322   bool trivial26() { bool hasValue = v; return !hasValue; }
323   bool trivial27(int v) { bool value; value = v ? 1 : 0; return value; }
324   bool trivial28() { return true; }
325   bool trivial29() { return false; }
326   unsigned trivial30(unsigned v) { unsigned r = 0xff; r |= v; return r; }
327   int trivial31(int* v) { return v[0]; }
328   unsigned trivial32() { return sizeof(int); }
329   unsigned trivial33() { return ~0xff; }
330   template <unsigned v> unsigned trivial34() { return v; }
331   void trivial35() { v++; }
332   void trivial36() { ++(*number); }
333   void trivial37() { (*number)++; }
334   void trivial38() { v++; if (__builtin_expect(!!(number), 1)) (*number)++; }
335   int trivial39() { return -v; }
336   int trivial40() { return v << 2; }
337   unsigned trivial41() { v = ++s_v; return v; }
338   unsigned trivial42() { return bitwise_cast<unsigned long>(nullptr); }
339   Number* trivial43() { return std::addressof(*number); }
340   Number* trivial44() { return new Number(1); }
341   ComplexNumber* trivial45() { return new ComplexNumber(); }
342   void trivial46() { ASSERT(isMainThread()); }
343   void trivial47() { ASSERT(isMainThreadOrGCThread()); }
344   void trivial48() { ASSERT(isMainRunLoop()); }
345   void trivial49() { ASSERT(isWebThread()); }
346   void trivial50() { ASSERT(isUIThread()); }
347   void trivial51() { ASSERT(mayBeGCThread()); }
348   void trivial52() { WTFCrash(); }
349   void trivial53() { WTFCrashWithSecurityImplication(); }
350   unsigned trivial54() { return ComplexNumber().real().value(); }
351   Number&& trivial55() { return std::forward(*number); }
352   unsigned trivial56() { Number n { 5 }; return std::move(n).value(); }
353   void trivial57() { do { break; } while (1); }
354   void trivial58() { do { continue; } while (0); }
355   void trivial59() {
356     do { goto label; }
357     while (0);
358   label:
359     return;
360   }
361   unsigned trivial60() { return ObjectWithNonTrivialDestructor { 5 }.value(); }
362   unsigned trivial61() { return DerivedNumber('7').value(); }
363   void trivial62() { WTFReportBacktrace(); }
364   SomeType trivial63() { return SomeType(0); }
365   SomeType trivial64() { return SomeType(); }
366   void trivial65() {
367     __libcpp_verbose_abort("%s", "aborting");
368   }
369   RefPtr<RefCounted> trivial66() { return children[0]; }
370   Ref<RefCounted> trivial67() { return *children[0]; }
371 
372   static RefCounted& singleton() {
373     static RefCounted s_RefCounted;
374     s_RefCounted.ref();
375     return s_RefCounted;
376   }
377 
378   static RefCounted& otherSingleton() {
379     static RefCounted s_RefCounted;
380     s_RefCounted.ref();
381     return s_RefCounted;
382   }
383 
384   Number nonTrivial1() { return Number(3) + Number(4); }
385   Number nonTrivial2() { return Number { 0.3 }; }
386   int nonTrivial3() { return v ? otherFunction() : 0; }
387   int nonTrivial4() {
388     if (v)
389       return 8;
390     else
391       return otherFunction();
392   }
393 
394   int nonTrivial5() {
395     if (v)
396       return otherFunction();
397     else
398       return 9;
399   }
400 
401   int nonTrivial6() {
402     if (otherFunction())
403       return 1;
404     else
405       return 0;
406   }
407 
408   int nonTrivial7() {
409     switch (v) {
410       case 1:
411         return otherFunction();
412       default:
413         return 7;
414     }
415   }
416 
417   int nonTrivial8() {
418     switch (v) {
419       case 1:
420         return 9;
421       default:
422         return otherFunction();
423     }
424   }
425 
426   int nonTrivial9() {
427     switch (otherFunction()) {
428       case 0:
429         return -1;
430       default:
431         return 12;
432     }
433   }
434 
435   static unsigned* another();
436   unsigned nonTrivial10() const {
437     return __c11_atomic_load((volatile _Atomic(unsigned) *)another(), __ATOMIC_RELAXED);
438   }
439 
440   void nonTrivial11() {
441     Number num(0.3);
442   }
443 
444   bool nonTrivial12() {
445     bool val = otherFunction();
446     return val;
447   }
448 
449   int nonTrivial13() { return ~otherFunction(); }
450   int nonTrivial14() { int r = 0xff; r |= otherFunction(); return r; }
451   void nonTrivial15() { ++complex; }
452   void nonTrivial16() { complex++; }
453   ComplexNumber nonTrivial17() { return complex << 2; }
454   ComplexNumber nonTrivial18() { return +complex; }
455   ComplexNumber* nonTrivial19() { return new ComplexNumber(complex); }
456   unsigned nonTrivial20() { return ObjectWithMutatingDestructor { 7 }.value(); }
457   unsigned nonTrivial21() { return Number("123").value(); }
458   unsigned nonTrivial22() { return ComplexNumber(123, "456").real().value(); }
459   unsigned nonTrivial23() { return DerivedNumber("123").value(); }
460   SomeType nonTrivial24() { return SomeType("123"); }
461 
462   static unsigned s_v;
463   unsigned v { 0 };
464   Number* number { nullptr };
465   ComplexNumber complex;
466   Enum enumValue { Enum::Value1 };
467   RefCounted* children[4];
468 };
469 
470 unsigned RefCounted::s_v = 0;
471 
472 RefCounted* refCountedObj();
473 
474 void test()
475 {
476   refCountedObj()->someFunction();
477   // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
478 }
479 
480 class UnrelatedClass {
481   RefPtr<RefCounted> Field;
482   bool value;
483 
484 public:
485   RefCounted &getFieldTrivial() { return *Field.get(); }
486   RefCounted *getFieldTernary() { return value ? Field.get() : nullptr; }
487 
488   void test() {
489     getFieldTrivial().trivial1(); // no-warning
490     getFieldTrivial().trivial2(); // no-warning
491     getFieldTrivial().trivial3(); // no-warning
492     getFieldTrivial().trivial4(); // no-warning
493     getFieldTrivial().trivial5(); // no-warning
494     getFieldTrivial().trivial6(); // no-warning
495     getFieldTrivial().trivial7(); // no-warning
496     getFieldTrivial().trivial8(); // no-warning
497     getFieldTrivial().trivial9(); // no-warning
498     getFieldTrivial().trivial10(); // no-warning
499     getFieldTrivial().trivial11(1); // no-warning
500     getFieldTrivial().trivial12(nullptr); // no-warning
501     getFieldTrivial().trivial13(0); // no-warning
502     getFieldTrivial().trivial14(3); // no-warning
503     getFieldTrivial().trivial15(); // no-warning
504     getFieldTrivial().trivial16(); // no-warning
505     getFieldTrivial().trivial17(); // no-warning
506     getFieldTrivial().trivial18(); // no-warning
507     getFieldTrivial().trivial19(); // no-warning
508     getFieldTrivial().trivial20(); // no-warning
509     getFieldTrivial().trivial21(); // no-warning
510     getFieldTrivial().trivial22(); // no-warning
511     getFieldTrivial().trivial23(); // no-warning
512     getFieldTrivial().trivial24(); // no-warning
513     getFieldTrivial().trivial25(); // no-warning
514     getFieldTrivial().trivial26(); // no-warning
515     getFieldTrivial().trivial27(5); // no-warning
516     getFieldTrivial().trivial28(); // no-warning
517     getFieldTrivial().trivial29(); // no-warning
518     getFieldTrivial().trivial30(7); // no-warning
519     int a[] = {1, 2};
520     getFieldTrivial().trivial31(a); // no-warning
521     getFieldTrivial().trivial32(); // no-warning
522     getFieldTrivial().trivial33(); // no-warning
523     getFieldTrivial().trivial34<7>(); // no-warning
524     getFieldTrivial().trivial35(); // no-warning
525     getFieldTrivial().trivial36(); // no-warning
526     getFieldTrivial().trivial37(); // no-warning
527     getFieldTrivial().trivial38(); // no-warning
528     getFieldTrivial().trivial39(); // no-warning
529     getFieldTrivial().trivial40(); // no-warning
530     getFieldTrivial().trivial41(); // no-warning
531     getFieldTrivial().trivial42(); // no-warning
532     getFieldTrivial().trivial43(); // no-warning
533     getFieldTrivial().trivial44(); // no-warning
534     getFieldTrivial().trivial45(); // no-warning
535     getFieldTrivial().trivial46(); // no-warning
536     getFieldTrivial().trivial47(); // no-warning
537     getFieldTrivial().trivial48(); // no-warning
538     getFieldTrivial().trivial49(); // no-warning
539     getFieldTrivial().trivial50(); // no-warning
540     getFieldTrivial().trivial51(); // no-warning
541     getFieldTrivial().trivial52(); // no-warning
542     getFieldTrivial().trivial53(); // no-warning
543     getFieldTrivial().trivial54(); // no-warning
544     getFieldTrivial().trivial55(); // no-warning
545     getFieldTrivial().trivial56(); // no-warning
546     getFieldTrivial().trivial57(); // no-warning
547     getFieldTrivial().trivial58(); // no-warning
548     getFieldTrivial().trivial59(); // no-warning
549     getFieldTrivial().trivial60(); // no-warning
550     getFieldTrivial().trivial61(); // no-warning
551     getFieldTrivial().trivial62(); // no-warning
552     getFieldTrivial().trivial63(); // no-warning
553     getFieldTrivial().trivial64(); // no-warning
554     getFieldTrivial().trivial65(); // no-warning
555     getFieldTrivial().trivial66()->trivial6(); // no-warning
556     getFieldTrivial().trivial67()->trivial6(); // no-warning
557 
558     RefCounted::singleton().trivial18(); // no-warning
559     RefCounted::singleton().someFunction(); // no-warning
560     RefCounted::otherSingleton().trivial18(); // no-warning
561     RefCounted::otherSingleton().someFunction(); // no-warning
562 
563     getFieldTrivial().recursiveTrivialFunction(7); // no-warning
564     getFieldTrivial().recursiveComplexFunction(9);
565     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
566     getFieldTrivial().mutuallyRecursiveFunction1(11); // no-warning
567     getFieldTrivial().mutuallyRecursiveFunction2(13); // no-warning
568     getFieldTrivial().mutuallyRecursiveFunction3(17);
569     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
570     getFieldTrivial().mutuallyRecursiveFunction4(19);
571     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
572     getFieldTrivial().recursiveFunction5(23); // no-warning
573     getFieldTrivial().recursiveFunction6(29); // no-warning
574     getFieldTrivial().recursiveFunction7(31); // no-warning
575 
576     getFieldTrivial().mutuallyRecursive8();
577     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
578     getFieldTrivial().mutuallyRecursive9();
579     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
580 
581     getFieldTrivial().recursiveCost(); // no-warning
582 
583     getFieldTrivial().someFunction();
584     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
585     getFieldTrivial().nonTrivial1();
586     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
587     getFieldTrivial().nonTrivial2();
588     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
589     getFieldTrivial().nonTrivial3();
590     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
591     getFieldTrivial().nonTrivial4();
592     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
593     getFieldTrivial().nonTrivial5();
594     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
595     getFieldTrivial().nonTrivial6();
596     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
597     getFieldTrivial().nonTrivial7();
598     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
599     getFieldTrivial().nonTrivial8();
600     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
601     getFieldTrivial().nonTrivial9();
602     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
603     getFieldTrivial().nonTrivial10();
604     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
605     getFieldTrivial().nonTrivial11();
606     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
607     getFieldTrivial().nonTrivial12();
608     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
609     getFieldTrivial().nonTrivial13();
610     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
611     getFieldTrivial().nonTrivial14();
612     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
613     getFieldTrivial().nonTrivial15();
614     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
615     getFieldTrivial().nonTrivial16();
616     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
617     getFieldTrivial().nonTrivial17();
618     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
619     getFieldTrivial().nonTrivial18();
620     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
621     getFieldTrivial().nonTrivial19();
622     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
623     getFieldTrivial().nonTrivial20();
624     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
625     getFieldTrivial().nonTrivial21();
626     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
627     getFieldTrivial().nonTrivial22();
628     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
629     getFieldTrivial().nonTrivial23();
630     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
631     getFieldTrivial().nonTrivial24();
632     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
633   }
634 
635   void setField(RefCounted*);
636 };
637 
638 class UnrelatedClass2 {
639   RefPtr<UnrelatedClass> Field;
640 
641 public:
642   UnrelatedClass &getFieldTrivial() { return *Field.get(); }
643   RefCounted &getFieldTrivialRecursively() { return getFieldTrivial().getFieldTrivial(); }
644   RefCounted *getFieldTrivialTernary() { return Field ? Field->getFieldTernary() : nullptr; }
645 
646   template<typename T, typename ... AdditionalArgs>
647   void callSetField(T&& item, AdditionalArgs&&... args)
648   {
649     item.setField(std::forward<AdditionalArgs>(args)...);
650   }
651 
652   template<typename T, typename ... AdditionalArgs>
653   void callSetField2(T&& item, AdditionalArgs&&... args)
654   {
655     item.setField(std::move<AdditionalArgs>(args)...);
656   }
657 
658   void test() {
659     getFieldTrivialRecursively().trivial1(); // no-warning
660     getFieldTrivialTernary()->trivial2(); // no-warning
661     getFieldTrivialRecursively().someFunction();
662     // expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
663     callSetField(getFieldTrivial(), refCountedObj()); // no-warning
664   }
665 };
666 
667 RefPtr<RefCounted> object();
668 void someFunction(const RefCounted&);
669 
670 void test2() {
671     someFunction(*object());
672 }
673 
674 void system_header() {
675   callMethod<RefCountable>(object);
676 }
677