[alpha.webkit.UncountedCallArgsChecker] Avoid emitting warnings for Ref, RefPtr, and their variants. (#90153)
Skip the analysis of Ref, RefPtr, and their variant classes in UncountedCallArgsChecker since these classes are "trusted" to not do anything dangerous.
This commit is contained in:
@@ -50,6 +50,9 @@ std::optional<bool> isUncounted(const clang::CXXRecordDecl* Class);
|
||||
/// class, false if not, std::nullopt if inconclusive.
|
||||
std::optional<bool> isUncountedPtr(const clang::Type* T);
|
||||
|
||||
/// \returns true if Name is a RefPtr, Ref, or its variant, false if not.
|
||||
bool isRefType(const std::string &Name);
|
||||
|
||||
/// \returns true if \p F creates ref-countable object from uncounted parameter,
|
||||
/// false if not.
|
||||
bool isCtorOfRefCounted(const clang::FunctionDecl *F);
|
||||
|
||||
@@ -53,6 +53,12 @@ public:
|
||||
bool shouldVisitTemplateInstantiations() const { return true; }
|
||||
bool shouldVisitImplicitCode() const { return false; }
|
||||
|
||||
bool TraverseDecl(Decl *D) {
|
||||
if (isa<ClassTemplateDecl>(D) && isRefType(safeGetName(D)))
|
||||
return true;
|
||||
return RecursiveASTVisitor<LocalVisitor>::TraverseDecl(D);
|
||||
}
|
||||
|
||||
bool VisitCallExpr(const CallExpr *CE) {
|
||||
Checker->visitCallExpr(CE);
|
||||
return true;
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace ref_counted {
|
||||
void consume_ref_counted(Ref<RefCountable>) {}
|
||||
|
||||
void foo() {
|
||||
consume_refcntbl(provide_ref_counted().get());
|
||||
consume_refcntbl(provide_ref_counted().ptr());
|
||||
// no warning
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,61 @@
|
||||
#ifndef mock_types_1103988513531
|
||||
#define mock_types_1103988513531
|
||||
|
||||
template <typename T> struct Ref {
|
||||
T *t;
|
||||
template<typename T>
|
||||
struct RawPtrTraits {
|
||||
using StorageType = T*;
|
||||
|
||||
template<typename U>
|
||||
static T* exchange(StorageType& ptr, U&& newValue)
|
||||
{
|
||||
StorageType oldValue = static_cast<StorageType&&>(ptr);
|
||||
ptr = static_cast<U&&>(newValue);
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
static void swap(StorageType& a, StorageType& b)
|
||||
{
|
||||
StorageType temp = static_cast<StorageType&&>(a);
|
||||
a = static_cast<StorageType&&>(b);
|
||||
b = static_cast<StorageType&&>(temp);
|
||||
}
|
||||
static T* unwrap(const StorageType& ptr) { return ptr; }
|
||||
};
|
||||
|
||||
template<typename T> struct DefaultRefDerefTraits {
|
||||
static T* refIfNotNull(T* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
ptr->ref();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static T& ref(T& ref)
|
||||
{
|
||||
ref.ref();
|
||||
return ref;
|
||||
}
|
||||
|
||||
static void derefIfNotNull(T* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
ptr->deref();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename PtrTraits = RawPtrTraits<T>, typename RefDerefTraits = DefaultRefDerefTraits<T>> struct Ref {
|
||||
typename PtrTraits::StorageType t;
|
||||
|
||||
Ref() : t{} {};
|
||||
Ref(T &t)
|
||||
: t(t) {
|
||||
if (t)
|
||||
t->ref();
|
||||
}
|
||||
~Ref() {
|
||||
if (t)
|
||||
t->deref();
|
||||
}
|
||||
T *get() { return t; }
|
||||
T *ptr() { return t; }
|
||||
T *operator->() { return t; }
|
||||
operator const T &() const { return *t; }
|
||||
operator T &() { return *t; }
|
||||
Ref(T &t) : t(RefDerefTraits::refIfNotNull(t)) { }
|
||||
Ref(const Ref& o) : t(RefDerefTraits::refIfNotNull(PtrTraits::unwrap(o.t))) { }
|
||||
~Ref() { RefDerefTraits::derefIfNotNull(PtrTraits::exchange(t, nullptr)); }
|
||||
T &get() { return *PtrTraits::unwrap(t); }
|
||||
T *ptr() { return PtrTraits::unwrap(t); }
|
||||
T *operator->() { return PtrTraits::unwrap(t); }
|
||||
operator const T &() const { return *PtrTraits::unwrap(t); }
|
||||
operator T &() { return *PtrTraits::unwrap(t); }
|
||||
T* leakRef() { PtrTraits::exchange(t, nullptr); }
|
||||
};
|
||||
|
||||
template <typename T> struct RefPtr {
|
||||
|
||||
Reference in New Issue
Block a user