diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp index a7891d2da07c1..defd83ec8e179 100644 --- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp @@ -103,15 +103,18 @@ std::optional isRefCountable(const CXXRecordDecl* R) return hasRef && hasDeref; } +bool isRefType(const std::string &Name) { + return Name == "Ref" || Name == "RefAllowingPartiallyDestroyed" || + Name == "RefPtr" || Name == "RefPtrAllowingPartiallyDestroyed"; +} + bool isCtorOfRefCounted(const clang::FunctionDecl *F) { assert(F); - const auto &FunctionName = safeGetName(F); - - return FunctionName == "Ref" || FunctionName == "makeRef" - - || FunctionName == "RefPtr" || FunctionName == "makeRefPtr" + const std::string &FunctionName = safeGetName(F); - || FunctionName == "UniqueRef" || FunctionName == "makeUniqueRef" || + return isRefType(FunctionName) || FunctionName == "makeRef" || + FunctionName == "makeRefPtr" || FunctionName == "UniqueRef" || + FunctionName == "makeUniqueRef" || FunctionName == "makeUniqueRefWithoutFastMallocCheck" || FunctionName == "String" || FunctionName == "AtomString" || @@ -131,7 +134,7 @@ bool isReturnValueRefCounted(const clang::FunctionDecl *F) { if (auto *specialT = type->getAs()) { if (auto *decl = specialT->getTemplateName().getAsTemplateDecl()) { auto name = decl->getNameAsString(); - return name == "Ref" || name == "RefPtr"; + return isRefType(name); } return false; } @@ -172,20 +175,18 @@ std::optional isGetterOfRefCounted(const CXXMethodDecl* M) if (isa(M)) { const CXXRecordDecl *calleeMethodsClass = M->getParent(); auto className = safeGetName(calleeMethodsClass); - auto methodName = safeGetName(M); + auto method = safeGetName(M); - if (((className == "Ref" || className == "RefPtr") && - methodName == "get") || - (className == "Ref" && methodName == "ptr") || + if ((isRefType(className) && (method == "get" || method == "ptr")) || ((className == "String" || className == "AtomString" || className == "AtomStringImpl" || className == "UniqueString" || className == "UniqueStringImpl" || className == "Identifier") && - methodName == "impl")) + method == "impl")) return true; // Ref -> T conversion // FIXME: Currently allowing any Ref -> whatever cast. - if (className == "Ref" || className == "RefPtr") { + if (isRefType(className)) { if (auto *maybeRefToRawOperator = dyn_cast(M)) { if (auto *targetConversionType = maybeRefToRawOperator->getConversionType().getTypePtrOrNull()) { @@ -202,7 +203,7 @@ bool isRefCounted(const CXXRecordDecl *R) { if (auto *TmplR = R->getTemplateInstantiationPattern()) { // FIXME: String/AtomString/UniqueString const auto &ClassName = safeGetName(TmplR); - return ClassName == "RefPtr" || ClassName == "Ref"; + return isRefType(ClassName); } return false; } diff --git a/clang/test/Analysis/Checkers/WebKit/mock-types.h b/clang/test/Analysis/Checkers/WebKit/mock-types.h index 82db67bb031dd..e2b3401d40739 100644 --- a/clang/test/Analysis/Checkers/WebKit/mock-types.h +++ b/clang/test/Analysis/Checkers/WebKit/mock-types.h @@ -16,6 +16,7 @@ template struct Ref { } T *get() { return t; } T *ptr() { return t; } + T *operator->() { return t; } operator const T &() const { return *t; } operator T &() { return *t; } }; diff --git a/clang/test/Analysis/Checkers/WebKit/ref-allowing-partially-destroyed.cpp b/clang/test/Analysis/Checkers/WebKit/ref-allowing-partially-destroyed.cpp new file mode 100644 index 0000000000000..6d96c14102a90 --- /dev/null +++ b/clang/test/Analysis/Checkers/WebKit/ref-allowing-partially-destroyed.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.webkit.UncountedCallArgsChecker -verify %s +// expected-no-diagnostics + +#include "mock-types.h" + +template struct RefAllowingPartiallyDestroyed { + T *t; + + RefAllowingPartiallyDestroyed() : t{} {}; + RefAllowingPartiallyDestroyed(T &) {} + T *get() { return t; } + T *ptr() { return t; } + T *operator->() { return t; } + operator const T &() const { return *t; } + operator T &() { return *t; } +}; + +template struct RefPtrAllowingPartiallyDestroyed { + T *t; + + RefPtrAllowingPartiallyDestroyed() : t(new T) {} + RefPtrAllowingPartiallyDestroyed(T *t) : t(t) {} + T *get() { return t; } + T *operator->() { return t; } + const T *operator->() const { return t; } + T &operator*() { return *t; } + RefPtrAllowingPartiallyDestroyed &operator=(T *) { return *this; } + operator bool() { return t; } +}; + +class RefCounted { +public: + void ref() const; + void deref() const; + void someFunction(); +}; + +RefAllowingPartiallyDestroyed object1(); +RefPtrAllowingPartiallyDestroyed object2(); + +void testFunction() { + object1()->someFunction(); + object2()->someFunction(); +}