Treat member function calls to ref() and incrementCheckedPtrCount() as trivial so that a function which returns RefPtr/Ref out of a raw reference / pointer is also considered trivial.
677 lines
23 KiB
C++
677 lines
23 KiB
C++
// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
|
|
|
|
#include "mock-types.h"
|
|
#include "mock-system-header.h"
|
|
|
|
void WTFBreakpointTrap();
|
|
void WTFCrashWithInfo(int, const char*, const char*, int);
|
|
void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion);
|
|
void WTFReportBacktrace(void);
|
|
|
|
void WTFCrash(void);
|
|
void WTFCrashWithSecurityImplication(void);
|
|
|
|
inline void compilerFenceForCrash()
|
|
{
|
|
asm volatile("" ::: "memory");
|
|
}
|
|
|
|
inline void isIntegralOrPointerType() { }
|
|
|
|
template<typename T, typename... Types>
|
|
void isIntegralOrPointerType(T, Types... types)
|
|
{
|
|
static_assert(sizeof(char) < sizeof(short), "All types need to be bitwise_cast-able to integral type for logging");
|
|
isIntegralOrPointerType(types...);
|
|
}
|
|
|
|
#define CRASH_WITH_INFO(...) do { \
|
|
isIntegralOrPointerType(__VA_ARGS__); \
|
|
compilerFenceForCrash(); \
|
|
WTFBreakpointTrap(); \
|
|
__builtin_unreachable(); \
|
|
} while (0)
|
|
|
|
#define RELEASE_ASSERT(assertion, ...) do { \
|
|
if (!(assertion)) \
|
|
CRASH_WITH_INFO(__VA_ARGS__); \
|
|
} while (0)
|
|
|
|
#define ASSERT(assertion, ...) do { \
|
|
if (!(assertion)) { \
|
|
WTFReportAssertionFailure(__FILE__, __LINE__, __PRETTY_FUNCTION__, #assertion); \
|
|
CRASH_WITH_INFO(__VA_ARGS__); \
|
|
} \
|
|
} while (0)
|
|
|
|
#if !defined(ALWAYS_INLINE)
|
|
#define ALWAYS_INLINE inline
|
|
#endif
|
|
|
|
void WTFCrashWithInfoImpl(int line, const char* file, const char* function, int counter, unsigned long reason);
|
|
void WTFCrashWithInfo(int line, const char* file, const char* function, int counter);
|
|
|
|
template<typename T>
|
|
ALWAYS_INLINE unsigned long wtfCrashArg(T* arg) { return reinterpret_cast<unsigned long>(arg); }
|
|
|
|
template<typename T>
|
|
ALWAYS_INLINE unsigned long wtfCrashArg(T arg) { return arg; }
|
|
|
|
template<typename T>
|
|
void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, T reason)
|
|
{
|
|
WTFCrashWithInfoImpl(line, file, function, counter, wtfCrashArg(reason));
|
|
}
|
|
|
|
template<typename ToType, typename FromType>
|
|
ToType bitwise_cast(FromType from);
|
|
|
|
namespace std {
|
|
|
|
template<typename T>
|
|
T* addressof(T& arg);
|
|
|
|
template<typename T>
|
|
T&& forward(T& arg);
|
|
|
|
template<typename T>
|
|
T&& move( T&& t );
|
|
|
|
} // namespace std
|
|
|
|
bool isMainThread();
|
|
bool isMainThreadOrGCThread();
|
|
bool isMainRunLoop();
|
|
bool isWebThread();
|
|
bool isUIThread();
|
|
bool mayBeGCThread();
|
|
|
|
enum class Flags : unsigned short {
|
|
Flag1 = 1 << 0,
|
|
Flag2 = 1 << 1,
|
|
Flag3 = 1 << 2,
|
|
};
|
|
|
|
template<typename E> class OptionSet {
|
|
public:
|
|
using StorageType = unsigned short;
|
|
|
|
static constexpr OptionSet fromRaw(StorageType rawValue) {
|
|
return OptionSet(static_cast<E>(rawValue), FromRawValue);
|
|
}
|
|
|
|
constexpr OptionSet() = default;
|
|
|
|
constexpr OptionSet(E e)
|
|
: m_storage(static_cast<StorageType>(e)) {
|
|
}
|
|
|
|
constexpr StorageType toRaw() const { return m_storage; }
|
|
|
|
constexpr bool isEmpty() const { return !m_storage; }
|
|
|
|
constexpr explicit operator bool() const { return !isEmpty(); }
|
|
|
|
constexpr bool contains(E option) const { return containsAny(option); }
|
|
constexpr bool containsAny(OptionSet optionSet) const {
|
|
return !!(*this & optionSet);
|
|
}
|
|
|
|
constexpr bool containsAll(OptionSet optionSet) const {
|
|
return (*this & optionSet) == optionSet;
|
|
}
|
|
|
|
constexpr void add(OptionSet optionSet) { m_storage |= optionSet.m_storage; }
|
|
|
|
constexpr void remove(OptionSet optionSet)
|
|
{
|
|
m_storage &= ~optionSet.m_storage;
|
|
}
|
|
|
|
constexpr void set(OptionSet optionSet, bool value)
|
|
{
|
|
if (value)
|
|
add(optionSet);
|
|
else
|
|
remove(optionSet);
|
|
}
|
|
|
|
constexpr friend OptionSet operator|(OptionSet lhs, OptionSet rhs) {
|
|
return fromRaw(lhs.m_storage | rhs.m_storage);
|
|
}
|
|
|
|
constexpr friend OptionSet operator&(OptionSet lhs, OptionSet rhs) {
|
|
return fromRaw(lhs.m_storage & rhs.m_storage);
|
|
}
|
|
|
|
constexpr friend OptionSet operator-(OptionSet lhs, OptionSet rhs) {
|
|
return fromRaw(lhs.m_storage & ~rhs.m_storage);
|
|
}
|
|
|
|
constexpr friend OptionSet operator^(OptionSet lhs, OptionSet rhs) {
|
|
return fromRaw(lhs.m_storage ^ rhs.m_storage);
|
|
}
|
|
|
|
private:
|
|
enum InitializationTag { FromRawValue };
|
|
constexpr OptionSet(E e, InitializationTag)
|
|
: m_storage(static_cast<StorageType>(e)) {
|
|
}
|
|
StorageType m_storage { 0 };
|
|
};
|
|
|
|
int atoi(const char* str);
|
|
|
|
class Number {
|
|
public:
|
|
Number(int v) : v(v) { }
|
|
Number(double);
|
|
Number(const char* str) : v(atoi(str)) { }
|
|
Number operator+(const Number&);
|
|
Number& operator++() { ++v; return *this; }
|
|
Number operator++(int) { Number returnValue(v); ++v; return returnValue; }
|
|
const int& value() const { return v; }
|
|
void someMethod();
|
|
|
|
private:
|
|
int v;
|
|
};
|
|
|
|
class DerivedNumber : public Number {
|
|
public:
|
|
DerivedNumber(char c) : Number(c - '0') { }
|
|
DerivedNumber(const char* str) : Number(atoi(str)) { }
|
|
};
|
|
|
|
class ComplexNumber {
|
|
public:
|
|
ComplexNumber() : realPart(0), complexPart(0) { }
|
|
ComplexNumber(int real, const char* str) : realPart(real), complexPart(str) { }
|
|
ComplexNumber(const ComplexNumber&);
|
|
ComplexNumber& operator++() { realPart.someMethod(); return *this; }
|
|
ComplexNumber operator++(int);
|
|
ComplexNumber& operator<<(int);
|
|
ComplexNumber& operator+();
|
|
|
|
const Number& real() const { return realPart; }
|
|
|
|
private:
|
|
Number realPart;
|
|
Number complexPart;
|
|
};
|
|
|
|
class ObjectWithNonTrivialDestructor {
|
|
public:
|
|
ObjectWithNonTrivialDestructor() { }
|
|
ObjectWithNonTrivialDestructor(unsigned v) : v(v) { }
|
|
~ObjectWithNonTrivialDestructor() { }
|
|
|
|
unsigned value() const { return v; }
|
|
|
|
private:
|
|
unsigned v { 0 };
|
|
};
|
|
|
|
class ObjectWithMutatingDestructor {
|
|
public:
|
|
ObjectWithMutatingDestructor() : n(0) { }
|
|
ObjectWithMutatingDestructor(int n) : n(n) { }
|
|
~ObjectWithMutatingDestructor() { n.someMethod(); }
|
|
|
|
unsigned value() const { return n.value(); }
|
|
|
|
private:
|
|
Number n;
|
|
};
|
|
|
|
class BaseType {
|
|
public:
|
|
BaseType() : n(0) { }
|
|
BaseType(int v) : n(v) { }
|
|
BaseType(const char*);
|
|
private:
|
|
Number n;
|
|
};
|
|
|
|
class SomeType : public BaseType {
|
|
public:
|
|
using BaseType::BaseType;
|
|
};
|
|
|
|
void __libcpp_verbose_abort(const char *__format, ...);
|
|
|
|
class RefCounted {
|
|
public:
|
|
void ref() const;
|
|
void deref() const;
|
|
|
|
void method();
|
|
void someFunction();
|
|
int otherFunction();
|
|
unsigned recursiveTrivialFunction(int n) { return !n ? 1 : recursiveTrivialFunction(n - 1); }
|
|
unsigned recursiveComplexFunction(int n) { return !n ? otherFunction() : recursiveComplexFunction(n - 1); }
|
|
unsigned mutuallyRecursiveFunction1(int n) { return n < 0 ? 1 : (n % 2 ? mutuallyRecursiveFunction2(n - 2) : mutuallyRecursiveFunction1(n - 1)); }
|
|
unsigned mutuallyRecursiveFunction2(int n) { return n < 0 ? 1 : (n % 3 ? mutuallyRecursiveFunction2(n - 3) : mutuallyRecursiveFunction1(n - 2)); }
|
|
unsigned mutuallyRecursiveFunction3(int n) { return n < 0 ? 1 : (n % 5 ? mutuallyRecursiveFunction3(n - 5) : mutuallyRecursiveFunction4(n - 3)); }
|
|
unsigned mutuallyRecursiveFunction4(int n) { return n < 0 ? 1 : (n % 7 ? otherFunction() : mutuallyRecursiveFunction3(n - 3)); }
|
|
unsigned recursiveFunction5(unsigned n) { return n > 100 ? 2 : (n % 2 ? recursiveFunction5(n + 1) : recursiveFunction6(n + 2)); }
|
|
unsigned recursiveFunction6(unsigned n) { return n > 100 ? 3 : (n % 2 ? recursiveFunction6(n % 7) : recursiveFunction7(n % 5)); }
|
|
unsigned recursiveFunction7(unsigned n) { return n > 100 ? 5 : recursiveFunction7(n * 5); }
|
|
|
|
void mutuallyRecursive8() { mutuallyRecursive9(); someFunction(); }
|
|
void mutuallyRecursive9() { mutuallyRecursive8(); }
|
|
|
|
int recursiveCost() {
|
|
unsigned totalCost = 0;
|
|
for (unsigned i = 0; i < sizeof(children)/sizeof(*children); ++i) {
|
|
if (auto* child = children[i])
|
|
totalCost += child->recursiveCost();
|
|
}
|
|
return totalCost;
|
|
}
|
|
|
|
int trivial1() { return 123; }
|
|
float trivial2() { return 0.3; }
|
|
float trivial3() { return (float)0.4; }
|
|
float trivial4() { return 0.5f; }
|
|
char trivial5() { return 'a'; }
|
|
const char *trivial6() { return "abc"; }
|
|
int trivial7() { return (1); }
|
|
Number trivial8() { return Number { 5 }; }
|
|
int trivial9() { return 3 + 4; }
|
|
int trivial10() { return 0x1010 | 0x1; }
|
|
int trivial11(int v) { return v + 1; }
|
|
const char *trivial12(char *p) { return p ? "str" : "null"; }
|
|
int trivial13(int v) {
|
|
if (v)
|
|
return 123;
|
|
else
|
|
return 0;
|
|
}
|
|
int trivial14(int v) {
|
|
switch (v) {
|
|
case 1:
|
|
return 100;
|
|
case 2:
|
|
return 200;
|
|
default:
|
|
return 300;
|
|
}
|
|
return 0;
|
|
}
|
|
void *trivial15() { return static_cast<void*>(this); }
|
|
unsigned long trivial16() { return *reinterpret_cast<unsigned long*>(this); }
|
|
RefCounted& trivial17() const { return const_cast<RefCounted&>(*this); }
|
|
RefCounted& trivial18() const { RELEASE_ASSERT(this, "this must be not null"); return const_cast<RefCounted&>(*this); }
|
|
void trivial19() const { return; }
|
|
|
|
static constexpr unsigned numBits = 4;
|
|
int trivial20() { return v >> numBits; }
|
|
|
|
const int* trivial21() { return number ? &number->value() : nullptr; }
|
|
|
|
enum class Enum : unsigned short {
|
|
Value1 = 1,
|
|
Value2 = 2,
|
|
};
|
|
bool trivial22() { return enumValue == Enum::Value1; }
|
|
|
|
bool trivial23() const { return OptionSet<Flags>::fromRaw(v).contains(Flags::Flag1); }
|
|
int trivial24() const { ASSERT(v); return v; }
|
|
unsigned trivial25() const { return __c11_atomic_load((volatile _Atomic(unsigned) *)&v, __ATOMIC_RELAXED); }
|
|
bool trivial26() { bool hasValue = v; return !hasValue; }
|
|
bool trivial27(int v) { bool value; value = v ? 1 : 0; return value; }
|
|
bool trivial28() { return true; }
|
|
bool trivial29() { return false; }
|
|
unsigned trivial30(unsigned v) { unsigned r = 0xff; r |= v; return r; }
|
|
int trivial31(int* v) { return v[0]; }
|
|
unsigned trivial32() { return sizeof(int); }
|
|
unsigned trivial33() { return ~0xff; }
|
|
template <unsigned v> unsigned trivial34() { return v; }
|
|
void trivial35() { v++; }
|
|
void trivial36() { ++(*number); }
|
|
void trivial37() { (*number)++; }
|
|
void trivial38() { v++; if (__builtin_expect(!!(number), 1)) (*number)++; }
|
|
int trivial39() { return -v; }
|
|
int trivial40() { return v << 2; }
|
|
unsigned trivial41() { v = ++s_v; return v; }
|
|
unsigned trivial42() { return bitwise_cast<unsigned long>(nullptr); }
|
|
Number* trivial43() { return std::addressof(*number); }
|
|
Number* trivial44() { return new Number(1); }
|
|
ComplexNumber* trivial45() { return new ComplexNumber(); }
|
|
void trivial46() { ASSERT(isMainThread()); }
|
|
void trivial47() { ASSERT(isMainThreadOrGCThread()); }
|
|
void trivial48() { ASSERT(isMainRunLoop()); }
|
|
void trivial49() { ASSERT(isWebThread()); }
|
|
void trivial50() { ASSERT(isUIThread()); }
|
|
void trivial51() { ASSERT(mayBeGCThread()); }
|
|
void trivial52() { WTFCrash(); }
|
|
void trivial53() { WTFCrashWithSecurityImplication(); }
|
|
unsigned trivial54() { return ComplexNumber().real().value(); }
|
|
Number&& trivial55() { return std::forward(*number); }
|
|
unsigned trivial56() { Number n { 5 }; return std::move(n).value(); }
|
|
void trivial57() { do { break; } while (1); }
|
|
void trivial58() { do { continue; } while (0); }
|
|
void trivial59() {
|
|
do { goto label; }
|
|
while (0);
|
|
label:
|
|
return;
|
|
}
|
|
unsigned trivial60() { return ObjectWithNonTrivialDestructor { 5 }.value(); }
|
|
unsigned trivial61() { return DerivedNumber('7').value(); }
|
|
void trivial62() { WTFReportBacktrace(); }
|
|
SomeType trivial63() { return SomeType(0); }
|
|
SomeType trivial64() { return SomeType(); }
|
|
void trivial65() {
|
|
__libcpp_verbose_abort("%s", "aborting");
|
|
}
|
|
RefPtr<RefCounted> trivial66() { return children[0]; }
|
|
Ref<RefCounted> trivial67() { return *children[0]; }
|
|
|
|
static RefCounted& singleton() {
|
|
static RefCounted s_RefCounted;
|
|
s_RefCounted.ref();
|
|
return s_RefCounted;
|
|
}
|
|
|
|
static RefCounted& otherSingleton() {
|
|
static RefCounted s_RefCounted;
|
|
s_RefCounted.ref();
|
|
return s_RefCounted;
|
|
}
|
|
|
|
Number nonTrivial1() { return Number(3) + Number(4); }
|
|
Number nonTrivial2() { return Number { 0.3 }; }
|
|
int nonTrivial3() { return v ? otherFunction() : 0; }
|
|
int nonTrivial4() {
|
|
if (v)
|
|
return 8;
|
|
else
|
|
return otherFunction();
|
|
}
|
|
|
|
int nonTrivial5() {
|
|
if (v)
|
|
return otherFunction();
|
|
else
|
|
return 9;
|
|
}
|
|
|
|
int nonTrivial6() {
|
|
if (otherFunction())
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int nonTrivial7() {
|
|
switch (v) {
|
|
case 1:
|
|
return otherFunction();
|
|
default:
|
|
return 7;
|
|
}
|
|
}
|
|
|
|
int nonTrivial8() {
|
|
switch (v) {
|
|
case 1:
|
|
return 9;
|
|
default:
|
|
return otherFunction();
|
|
}
|
|
}
|
|
|
|
int nonTrivial9() {
|
|
switch (otherFunction()) {
|
|
case 0:
|
|
return -1;
|
|
default:
|
|
return 12;
|
|
}
|
|
}
|
|
|
|
static unsigned* another();
|
|
unsigned nonTrivial10() const {
|
|
return __c11_atomic_load((volatile _Atomic(unsigned) *)another(), __ATOMIC_RELAXED);
|
|
}
|
|
|
|
void nonTrivial11() {
|
|
Number num(0.3);
|
|
}
|
|
|
|
bool nonTrivial12() {
|
|
bool val = otherFunction();
|
|
return val;
|
|
}
|
|
|
|
int nonTrivial13() { return ~otherFunction(); }
|
|
int nonTrivial14() { int r = 0xff; r |= otherFunction(); return r; }
|
|
void nonTrivial15() { ++complex; }
|
|
void nonTrivial16() { complex++; }
|
|
ComplexNumber nonTrivial17() { return complex << 2; }
|
|
ComplexNumber nonTrivial18() { return +complex; }
|
|
ComplexNumber* nonTrivial19() { return new ComplexNumber(complex); }
|
|
unsigned nonTrivial20() { return ObjectWithMutatingDestructor { 7 }.value(); }
|
|
unsigned nonTrivial21() { return Number("123").value(); }
|
|
unsigned nonTrivial22() { return ComplexNumber(123, "456").real().value(); }
|
|
unsigned nonTrivial23() { return DerivedNumber("123").value(); }
|
|
SomeType nonTrivial24() { return SomeType("123"); }
|
|
|
|
static unsigned s_v;
|
|
unsigned v { 0 };
|
|
Number* number { nullptr };
|
|
ComplexNumber complex;
|
|
Enum enumValue { Enum::Value1 };
|
|
RefCounted* children[4];
|
|
};
|
|
|
|
unsigned RefCounted::s_v = 0;
|
|
|
|
RefCounted* refCountedObj();
|
|
|
|
void test()
|
|
{
|
|
refCountedObj()->someFunction();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
}
|
|
|
|
class UnrelatedClass {
|
|
RefPtr<RefCounted> Field;
|
|
bool value;
|
|
|
|
public:
|
|
RefCounted &getFieldTrivial() { return *Field.get(); }
|
|
RefCounted *getFieldTernary() { return value ? Field.get() : nullptr; }
|
|
|
|
void test() {
|
|
getFieldTrivial().trivial1(); // no-warning
|
|
getFieldTrivial().trivial2(); // no-warning
|
|
getFieldTrivial().trivial3(); // no-warning
|
|
getFieldTrivial().trivial4(); // no-warning
|
|
getFieldTrivial().trivial5(); // no-warning
|
|
getFieldTrivial().trivial6(); // no-warning
|
|
getFieldTrivial().trivial7(); // no-warning
|
|
getFieldTrivial().trivial8(); // no-warning
|
|
getFieldTrivial().trivial9(); // no-warning
|
|
getFieldTrivial().trivial10(); // no-warning
|
|
getFieldTrivial().trivial11(1); // no-warning
|
|
getFieldTrivial().trivial12(nullptr); // no-warning
|
|
getFieldTrivial().trivial13(0); // no-warning
|
|
getFieldTrivial().trivial14(3); // no-warning
|
|
getFieldTrivial().trivial15(); // no-warning
|
|
getFieldTrivial().trivial16(); // no-warning
|
|
getFieldTrivial().trivial17(); // no-warning
|
|
getFieldTrivial().trivial18(); // no-warning
|
|
getFieldTrivial().trivial19(); // no-warning
|
|
getFieldTrivial().trivial20(); // no-warning
|
|
getFieldTrivial().trivial21(); // no-warning
|
|
getFieldTrivial().trivial22(); // no-warning
|
|
getFieldTrivial().trivial23(); // no-warning
|
|
getFieldTrivial().trivial24(); // no-warning
|
|
getFieldTrivial().trivial25(); // no-warning
|
|
getFieldTrivial().trivial26(); // no-warning
|
|
getFieldTrivial().trivial27(5); // no-warning
|
|
getFieldTrivial().trivial28(); // no-warning
|
|
getFieldTrivial().trivial29(); // no-warning
|
|
getFieldTrivial().trivial30(7); // no-warning
|
|
int a[] = {1, 2};
|
|
getFieldTrivial().trivial31(a); // no-warning
|
|
getFieldTrivial().trivial32(); // no-warning
|
|
getFieldTrivial().trivial33(); // no-warning
|
|
getFieldTrivial().trivial34<7>(); // no-warning
|
|
getFieldTrivial().trivial35(); // no-warning
|
|
getFieldTrivial().trivial36(); // no-warning
|
|
getFieldTrivial().trivial37(); // no-warning
|
|
getFieldTrivial().trivial38(); // no-warning
|
|
getFieldTrivial().trivial39(); // no-warning
|
|
getFieldTrivial().trivial40(); // no-warning
|
|
getFieldTrivial().trivial41(); // no-warning
|
|
getFieldTrivial().trivial42(); // no-warning
|
|
getFieldTrivial().trivial43(); // no-warning
|
|
getFieldTrivial().trivial44(); // no-warning
|
|
getFieldTrivial().trivial45(); // no-warning
|
|
getFieldTrivial().trivial46(); // no-warning
|
|
getFieldTrivial().trivial47(); // no-warning
|
|
getFieldTrivial().trivial48(); // no-warning
|
|
getFieldTrivial().trivial49(); // no-warning
|
|
getFieldTrivial().trivial50(); // no-warning
|
|
getFieldTrivial().trivial51(); // no-warning
|
|
getFieldTrivial().trivial52(); // no-warning
|
|
getFieldTrivial().trivial53(); // no-warning
|
|
getFieldTrivial().trivial54(); // no-warning
|
|
getFieldTrivial().trivial55(); // no-warning
|
|
getFieldTrivial().trivial56(); // no-warning
|
|
getFieldTrivial().trivial57(); // no-warning
|
|
getFieldTrivial().trivial58(); // no-warning
|
|
getFieldTrivial().trivial59(); // no-warning
|
|
getFieldTrivial().trivial60(); // no-warning
|
|
getFieldTrivial().trivial61(); // no-warning
|
|
getFieldTrivial().trivial62(); // no-warning
|
|
getFieldTrivial().trivial63(); // no-warning
|
|
getFieldTrivial().trivial64(); // no-warning
|
|
getFieldTrivial().trivial65(); // no-warning
|
|
getFieldTrivial().trivial66()->trivial6(); // no-warning
|
|
getFieldTrivial().trivial67()->trivial6(); // no-warning
|
|
|
|
RefCounted::singleton().trivial18(); // no-warning
|
|
RefCounted::singleton().someFunction(); // no-warning
|
|
RefCounted::otherSingleton().trivial18(); // no-warning
|
|
RefCounted::otherSingleton().someFunction(); // no-warning
|
|
|
|
getFieldTrivial().recursiveTrivialFunction(7); // no-warning
|
|
getFieldTrivial().recursiveComplexFunction(9);
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().mutuallyRecursiveFunction1(11); // no-warning
|
|
getFieldTrivial().mutuallyRecursiveFunction2(13); // no-warning
|
|
getFieldTrivial().mutuallyRecursiveFunction3(17);
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().mutuallyRecursiveFunction4(19);
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().recursiveFunction5(23); // no-warning
|
|
getFieldTrivial().recursiveFunction6(29); // no-warning
|
|
getFieldTrivial().recursiveFunction7(31); // no-warning
|
|
|
|
getFieldTrivial().mutuallyRecursive8();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().mutuallyRecursive9();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
|
|
getFieldTrivial().recursiveCost(); // no-warning
|
|
|
|
getFieldTrivial().someFunction();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial1();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial2();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial3();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial4();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial5();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial6();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial7();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial8();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial9();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial10();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial11();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial12();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial13();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial14();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial15();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial16();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial17();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial18();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial19();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial20();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial21();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial22();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial23();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
getFieldTrivial().nonTrivial24();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
}
|
|
|
|
void setField(RefCounted*);
|
|
};
|
|
|
|
class UnrelatedClass2 {
|
|
RefPtr<UnrelatedClass> Field;
|
|
|
|
public:
|
|
UnrelatedClass &getFieldTrivial() { return *Field.get(); }
|
|
RefCounted &getFieldTrivialRecursively() { return getFieldTrivial().getFieldTrivial(); }
|
|
RefCounted *getFieldTrivialTernary() { return Field ? Field->getFieldTernary() : nullptr; }
|
|
|
|
template<typename T, typename ... AdditionalArgs>
|
|
void callSetField(T&& item, AdditionalArgs&&... args)
|
|
{
|
|
item.setField(std::forward<AdditionalArgs>(args)...);
|
|
}
|
|
|
|
template<typename T, typename ... AdditionalArgs>
|
|
void callSetField2(T&& item, AdditionalArgs&&... args)
|
|
{
|
|
item.setField(std::move<AdditionalArgs>(args)...);
|
|
}
|
|
|
|
void test() {
|
|
getFieldTrivialRecursively().trivial1(); // no-warning
|
|
getFieldTrivialTernary()->trivial2(); // no-warning
|
|
getFieldTrivialRecursively().someFunction();
|
|
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
|
|
callSetField(getFieldTrivial(), refCountedObj()); // no-warning
|
|
}
|
|
};
|
|
|
|
RefPtr<RefCounted> object();
|
|
void someFunction(const RefCounted&);
|
|
|
|
void test2() {
|
|
someFunction(*object());
|
|
}
|
|
|
|
void system_header() {
|
|
callMethod<RefCountable>(object);
|
|
}
|