| // RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s |
| |
| #include "mock-types.h" |
| |
| RefCountable* provide() { return nullptr; } |
| void consume_refcntbl(RefCountable*) {} |
| |
| namespace simple { |
| void foo() { |
| consume_refcntbl(provide()); |
| // expected-warning@-1{{Call argument is uncounted and unsafe}} |
| } |
| } |
| |
| 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().get()); |
| // 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*) { } |
| void whatever() { |
| consume(provide()); |
| // expected-warning@-1{{Call argument is uncounted and unsafe}} |
| } |
| }; |
| } |
| |
| void foo3() { |
| struct Consumer { |
| void consume(RefCountable*) { } |
| void whatever() { |
| this->consume(provide()); |
| // expected-warning@-1{{Call argument is uncounted and unsafe}} |
| } |
| }; |
| } |
| } |
| |
| namespace casts { |
| RefCountable* downcast(RefCountable*) { return nullptr; } |
| |
| 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&) {}; |
| auto 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_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 make_ref { |
| void makeRef(RefCountable*) {} |
| void makeRefPtr(RefCountable*) {} |
| void makeWeakPtr(RefCountable*) {} |
| void makeWeakPtr(RefCountable&) {} |
| |
| void foo() { |
| makeRef(provide()); |
| makeRefPtr(provide()); |
| RefPtr<RefCountable> a(provide()); |
| Ref<RefCountable> b(provide()); |
| makeWeakPtr(provide()); |
| makeWeakPtr(*provide()); |
| } |
| } |
| |
| 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_operator_call { |
| // The hidden this-pointer argument without a corresponding parameter caused couple bugs in parameter <-> argument attribution. |
| struct Foo { |
| Foo& operator+(RefCountable* bad) { return *this; } |
| friend Foo& operator-(Foo& lhs, RefCountable* bad) { return lhs; } |
| 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}} |
| } |
| } |