// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s
#include "mock-types.h"
RefCountable* provide();
void consume_refcntbl(RefCountable*);
void some_function();
namespace simple {
void foo() {
consume_refcntbl(provide());
// expected-warning@-1{{Call argument is uncounted and unsafe}}
}
// Test that the checker works with [[clang::suppress]].
void foo_suppressed() {
[[clang::suppress]]
consume_refcntbl(provide()); // no-warning
}
}
namespace multi_arg {
void consume_refcntbl(int, RefCountable* foo, bool);
void foo() {
consume_refcntbl(42, provide(), true);
// expected-warning@-1{{Call argument for parameter 'foo' is uncounted and unsafe}}
}
}
namespace ref_counted {
Ref<RefCountable> provide_ref_counted() { return Ref<RefCountable>{}; }
void consume_ref_counted(Ref<RefCountable>) {}
void foo() {
consume_refcntbl(provide_ref_counted().ptr());
// no warning
}
}
namespace methods {
struct Consumer {
void consume_ptr(RefCountable* ptr);
void consume_ref(const RefCountable& ref);
};
void foo() {
Consumer c;
c.consume_ptr(provide());
// expected-warning@-1{{Call argument for parameter 'ptr' is uncounted and unsafe}}
c.consume_ref(*provide());
// expected-warning@-1{{Call argument for parameter 'ref' is uncounted and unsafe}}
}
void foo2() {
struct Consumer {
void consume(RefCountable*) { some_function(); }
void whatever() {
consume(provide());
// expected-warning@-1{{Call argument is uncounted and unsafe}}
}
};
}
void foo3() {
struct Consumer {
void consume(RefCountable*) { some_function(); }
void whatever() {
this->consume(provide());
// expected-warning@-1{{Call argument is uncounted and unsafe}}
}
};
}
}
namespace casts {
RefCountable* downcast(RefCountable*);
void foo() {
consume_refcntbl(provide());
// expected-warning@-1{{Call argument is uncounted and unsafe}}
consume_refcntbl(static_cast<RefCountable*>(provide()));
// expected-warning@-1{{Call argument is uncounted and unsafe}}
consume_refcntbl(dynamic_cast<RefCountable*>(provide()));
// expected-warning@-1{{Call argument is uncounted and unsafe}}
consume_refcntbl(const_cast<RefCountable*>(provide()));
// expected-warning@-1{{Call argument is uncounted and unsafe}}
consume_refcntbl(reinterpret_cast<RefCountable*>(provide()));
// expected-warning@-1{{Call argument is uncounted and unsafe}}
consume_refcntbl(downcast(provide()));
// expected-warning@-1{{Call argument is uncounted and unsafe}}
consume_refcntbl(
static_cast<RefCountable*>(
downcast(
static_cast<RefCountable*>(
provide()
)
)
)
);
// expected-warning@-8{{Call argument is uncounted and unsafe}}
}
}
namespace null_ptr {
void foo_ref() {
consume_refcntbl(nullptr);
consume_refcntbl(0);
}
}
namespace ref_counted_lookalike {
struct Decoy {
RefCountable* get() { return nullptr; }
};
void foo() {
Decoy D;
consume_refcntbl(D.get());
// expected-warning@-1{{Call argument is uncounted and unsafe}}
}
}
namespace Ref_to_reference_conversion_operator {
template<typename T> struct Ref {
Ref() = default;
Ref(T*) { }
T* get() { return nullptr; }
operator T& () { return t; }
T t;
};
void consume_ref(RefCountable&) {}
void foo() {
Ref<RefCountable> bar;
consume_ref(bar);
}
}
namespace param_formarding_function {
void consume_ref_countable_ref(RefCountable&);
void consume_ref_countable_ptr(RefCountable*);
namespace ptr {
void foo(RefCountable* param) {
consume_ref_countable_ptr(param);
}
}
namespace ref {
void foo(RefCountable& param) {
consume_ref_countable_ref(param);
}
}
namespace ref_deref_operators {
void foo_ref(RefCountable& param) {
consume_ref_countable_ptr(¶m);
}
void foo_ptr(RefCountable* param) {
consume_ref_countable_ref(*param);
}
}
namespace casts {
RefCountable* downcast(RefCountable*) { return nullptr; }
template<class T>
T* bitwise_cast(T*) { return nullptr; }
void foo(RefCountable* param) {
consume_ref_countable_ptr(downcast(param));
consume_ref_countable_ptr(bitwise_cast(param));
}
}
}
namespace param_formarding_lambda {
auto consume_ref_countable_ref = [](RefCountable&) { some_function(); };
auto consume_ref_countable_ptr = [](RefCountable*) { some_function(); };
namespace ptr {
void foo(RefCountable* param) {
consume_ref_countable_ptr(param);
}
}
namespace ref {
void foo(RefCountable& param) {
consume_ref_countable_ref(param);
}
}
namespace ref_deref_operators {
void foo_ref(RefCountable& param) {
consume_ref_countable_ptr(¶m);
}
void foo_ptr(RefCountable* param) {
consume_ref_countable_ref(*param);
}
}
namespace casts {
RefCountable* downcast(RefCountable*) { return nullptr; }
template<class T>
T* bitwise_cast(T*) { return nullptr; }
void foo(RefCountable* param) {
consume_ref_countable_ptr(downcast(param));
consume_ref_countable_ptr(bitwise_cast(param));
}
}
}
namespace param_forwarding_method {
struct methodclass {
void consume_ref_countable_ref(RefCountable&) {};
static void consume_ref_countable_ptr(RefCountable*) {};
};
namespace ptr {
void foo(RefCountable* param) {
methodclass::consume_ref_countable_ptr(param);
}
}
namespace ref {
void foo(RefCountable& param) {
methodclass mc;
mc.consume_ref_countable_ref(param);
}
}
namespace ref_deref_operators {
void foo_ref(RefCountable& param) {
methodclass::consume_ref_countable_ptr(¶m);
}
void foo_ptr(RefCountable* param) {
methodclass mc;
mc.consume_ref_countable_ref(*param);
}
}
namespace casts {
RefCountable* downcast(RefCountable*) { return nullptr; }
template<class T>
T* bitwise_cast(T*) { return nullptr; }
void foo(RefCountable* param) {
methodclass::consume_ref_countable_ptr(downcast(param));
methodclass::consume_ref_countable_ptr(bitwise_cast(param));
}
}
}
namespace downcast {
void consume_ref_countable(RefCountable*) {}
RefCountable* downcast(RefCountable*) { return nullptr; }
void foo() {
RefPtr<RefCountable> bar;
consume_ref_countable( downcast(bar.get()) );
}
}
namespace string_impl {
struct String {
RefCountable* impl() { return nullptr; }
};
struct AtomString {
RefCountable rc;
RefCountable& impl() { return rc; }
};
void consume_ptr(RefCountable*) {}
void consume_ref(RefCountable&) {}
namespace simple {
void foo() {
String s;
AtomString as;
consume_ptr(s.impl());
consume_ref(as.impl());
}
}
}
namespace default_arg {
RefCountable* global;
void function_with_default_arg(RefCountable* param = global);
// expected-warning@-1{{Call argument for parameter 'param' is uncounted and unsafe}}
void foo() {
function_with_default_arg();
}
}
namespace cxx_member_func {
Ref<RefCountable> provideProtected();
void foo() {
provide()->trivial();
provide()->method();
// expected-warning@-1{{Call argument for 'this' parameter is uncounted and unsafe}}
provideProtected()->method();
(provideProtected())->method();
};
}
namespace cxx_member_operator_call {
// The hidden this-pointer argument without a corresponding parameter caused couple bugs in parameter <-> argument attribution.
struct Foo {
Foo& operator+(RefCountable* bad);
friend Foo& operator-(Foo& lhs, RefCountable* bad);
void operator()(RefCountable* bad);
};
RefCountable* global;
void foo() {
Foo f;
f + global;
// expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
f - global;
// expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
f(global);
// expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
}
}
namespace call_with_ptr_on_ref {
Ref<RefCountable> provideProtected();
void bar(RefCountable* bad);
bool baz();
void foo(bool v) {
bar(v ? nullptr : provideProtected().ptr());
bar(baz() ? provideProtected().ptr() : nullptr);
bar(v ? provide() : provideProtected().ptr());
// expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
bar(v ? provideProtected().ptr() : provide());
// expected-warning@-1{{Call argument for parameter 'bad' is uncounted and unsafe}}
}
}
namespace call_with_explicit_temporary_obj {
void foo() {
Ref { *provide() }->method();
RefPtr { provide() }->method();
}
}