llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Ryosuke Niwa (rniwa)

<details>
<summary>Changes</summary>

Emit a warning for a member variable which is a raw pointer or raw reference to 
a smart pointer as such a variable is not memory safe as the underlying smart 
pointer might get free'ed elsewhere.

Also add a support for [[clang::annotate_type("webkit.unsafeptr")]], which 
explicitly annotate and allow such a member variable in container classes such 
as Vector and HashTable.

---

Patch is 35.57 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/200599.diff


8 Files Affected:

- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
(+26-6) 
- (modified) clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h (+10) 
- (modified) 
clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp (+76-36) 
- (modified) clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp (+24-4) 
- (modified) clang/test/Analysis/Checkers/WebKit/uncounted-members-objc.mm 
(+24) 
- (modified) clang/test/Analysis/Checkers/WebKit/uncounted-members.cpp (+25-2) 
- (modified) clang/test/Analysis/Checkers/WebKit/unretained-members-arc.mm 
(+41-1) 
- (modified) clang/test/Analysis/Checkers/WebKit/unretained-members.mm (+62-1) 


``````````diff
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
index 2ca34ff0587e1..0565c7540f845 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.cpp
@@ -225,6 +225,14 @@ static bool isPtrOfType(const clang::QualType T, Predicate 
Pred) {
   return false;
 }
 
+bool isRefPtrType(const clang::QualType T) {
+  return isPtrOfType(T, [](auto Name) { return isRefType(Name); });
+}
+
+bool isCheckedPtrType(const clang::QualType T) {
+  return isPtrOfType(T, [](auto Name) { return isCheckedPtr(Name); });
+}
+
 bool isRefOrCheckedPtrType(const clang::QualType T) {
   return isPtrOfType(
       T, [](auto Name) { return isRefType(Name) || isCheckedPtr(Name); });
@@ -427,14 +435,15 @@ enum class WebKitAnnotation : uint8_t {
   None,
   PointerConversion,
   NoDelete,
+  UnsafePtr,
 };
 
-static WebKitAnnotation typeAnnotationForReturnType(const FunctionDecl *FD) {
-  auto RetType = FD->getReturnType();
-  auto *Type = RetType.getTypePtrOrNull();
-  if (auto *MacroQualified = dyn_cast_or_null<MacroQualifiedType>(Type))
-    Type = MacroQualified->desugar().getTypePtrOrNull();
-  auto *Attr = dyn_cast_or_null<AttributedType>(Type);
+static WebKitAnnotation typeAnnotation(const Type *T) {
+  if (!T)
+    return WebKitAnnotation::None;
+  if (auto *MacroQualified = dyn_cast_or_null<MacroQualifiedType>(T))
+    T = MacroQualified->desugar().getTypePtrOrNull();
+  auto *Attr = dyn_cast_or_null<AttributedType>(T);
   if (!Attr)
     return WebKitAnnotation::None;
   auto *AnnotateType = dyn_cast_or_null<AnnotateTypeAttr>(Attr->getAttr());
@@ -445,9 +454,16 @@ static WebKitAnnotation typeAnnotationForReturnType(const 
FunctionDecl *FD) {
     return WebKitAnnotation::PointerConversion;
   if (Annotation == "webkit.nodelete")
     return WebKitAnnotation::NoDelete;
+  if (Annotation == "webkit.unsafeptr")
+    return WebKitAnnotation::UnsafePtr;
   return WebKitAnnotation::None;
 }
 
+static WebKitAnnotation typeAnnotationForReturnType(const FunctionDecl *FD) {
+  auto RetType = FD->getReturnType();
+  return typeAnnotation(RetType.getTypePtrOrNull());
+}
+
 bool isPtrConversion(const FunctionDecl *F) {
   assert(F);
   if (isCtorOfRefCounted(F))
@@ -494,6 +510,10 @@ bool isNoDeleteFunction(const FunctionDecl *F) {
   return false;
 }
 
+bool isExplicitlyAllowedUnsafePtr(const Type *T) {
+  return typeAnnotation(T) == WebKitAnnotation::UnsafePtr;
+}
+
 bool isTrivialBuiltinFunction(const FunctionDecl *F) {
   if (!F || !F->getDeclName().isIdentifier())
     return false;
diff --git a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
index a2fd12656d391..13e78e0beb0ae 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/PtrTypesSemantics.h
@@ -109,6 +109,12 @@ std::optional<bool> isUncountedPtr(const clang::QualType 
T);
 /// class, false if not, std::nullopt if inconclusive.
 std::optional<bool> isUncheckedPtr(const clang::QualType T);
 
+/// \returns true if \p T is a RefPtr or Ref or its variant, false if not.
+bool isRefPtrType(const clang::QualType T);
+
+/// \returns true if \p T is a RefPtr or Ref or its variant, false if not.
+bool isCheckedPtrType(const clang::QualType T);
+
 /// \returns true if \p T is a RefPtr, Ref, CheckedPtr, CheckedRef, or its
 /// variant, false if not.
 bool isRefOrCheckedPtrType(const clang::QualType T);
@@ -162,6 +168,10 @@ bool isPtrConversion(const FunctionDecl *F);
 /// [[clang::annotate_type("webkit.nodelete")]].
 bool isNoDeleteFunction(const FunctionDecl *F);
 
+/// \returns true if \p T is annotated with
+/// [[clang::annotate_type("webkit.unsafeptr")]].
+bool isExplicitlyAllowedUnsafePtr(const Type *T);
+
 /// \returns true if \p F is a builtin function which is considered trivial.
 bool isTrivialBuiltinFunction(const FunctionDecl *F);
 
diff --git 
a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp 
b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
index 0e23ae34ea212..1f0bbb09da61b 100644
--- a/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
+++ b/clang/lib/StaticAnalyzer/Checkers/WebKit/RawPtrRefMemberChecker.cpp
@@ -39,6 +39,7 @@ class RawPtrRefMemberChecker
 
   virtual std::optional<bool> isUnsafePtr(QualType,
                                           bool ignoreARC = false) const = 0;
+  virtual bool isSafePtr(QualType) const = 0;
   virtual const char *typeName() const = 0;
   virtual const char *invariant() const = 0;
 
@@ -90,26 +91,39 @@ class RawPtrRefMemberChecker
   }
 
   void visitMember(const FieldDecl *Member, const RecordDecl *RD) const {
+    visitMemberDecl(Member, RD);
+  }
+
+  template <typename DeclType, typename ParentDeclType>
+  bool visitMemberDecl(DeclType *Member, const ParentDeclType *D) const {
     auto QT = Member->getType();
     const Type *MemberType = QT.getTypePtrOrNull();
 
+    bool IsPtrToSafePtr = false;
     while (MemberType) {
       auto IsUnsafePtr = isUnsafePtr(QT);
       if (IsUnsafePtr && *IsUnsafePtr)
         break;
-      if (!MemberType->isPointerType())
-        return;
+      if (!MemberType->isPointerType() && !MemberType->isReferenceType())
+        return false;
       QT = MemberType->getPointeeType();
+      if (isSafePtr(QT) && !isExplicitlyAllowedUnsafePtr(MemberType)) {
+        IsPtrToSafePtr = true;
+        break;
+      }
       MemberType = QT.getTypePtrOrNull();
     }
 
     if (!MemberType)
-      return;
+      return false;
 
     if (auto *MemberCXXRD = MemberType->getPointeeCXXRecordDecl())
-      reportBug(Member, MemberType, MemberCXXRD, RD);
+      reportBug(Member, MemberType, MemberCXXRD, D, IsPtrToSafePtr);
     else if (auto *ObjCDecl = getObjCDecl(MemberType))
-      reportBug(Member, MemberType, ObjCDecl, RD);
+      reportBug(Member, MemberType, ObjCDecl, D, IsPtrToSafePtr);
+    else
+      return false;
+    return true;
   }
 
   ObjCInterfaceDecl *getObjCDecl(const Type *TypePtr) const {
@@ -156,21 +170,8 @@ class RawPtrRefMemberChecker
     if (IvarDeclsToIgnore.contains(Ivar))
       return;
 
-    auto QT = Ivar->getType();
-    const Type *IvarType = QT.getTypePtrOrNull();
-    if (!IvarType)
-      return;
-
-    auto IsUnsafePtr = isUnsafePtr(QT);
-    if (!IsUnsafePtr || !*IsUnsafePtr)
-      return;
-
-    IvarDeclsToIgnore.insert(Ivar);
-
-    if (auto *MemberCXXRD = IvarType->getPointeeCXXRecordDecl())
-      reportBug(Ivar, IvarType, MemberCXXRD, CD);
-    else if (auto *ObjCDecl = getObjCDecl(IvarType))
-      reportBug(Ivar, IvarType, ObjCDecl, CD);
+    if (visitMemberDecl(Ivar, CD))
+      IvarDeclsToIgnore.insert(Ivar);
   }
 
   void visitObjCPropertyDecl(const ObjCContainerDecl *CD,
@@ -184,14 +185,14 @@ class RawPtrRefMemberChecker
         return;
     }
 
-    auto [IsUnsafe, PropType] = isPropImplUnsafePtr(PD);
+    auto [IsUnsafe, PropType, IsPtrToSafePtr] = isPropImplUnsafePtr(PD);
     if (!IsUnsafe)
       return;
 
     if (auto *MemberCXXRD = PropType->getPointeeCXXRecordDecl())
-      reportBug(PD, PropType, MemberCXXRD, CD);
+      reportBug(PD, PropType, MemberCXXRD, CD, IsPtrToSafePtr);
     else if (auto *ObjCDecl = getObjCDecl(PropType))
-      reportBug(PD, PropType, ObjCDecl, CD);
+      reportBug(PD, PropType, ObjCDecl, CD, IsPtrToSafePtr);
   }
 
   void visitPropImpl(const ObjCContainerDecl *CD,
@@ -208,25 +209,25 @@ class RawPtrRefMemberChecker
         return;
       IvarDeclsToIgnore.insert(IvarDecl);
     }
-    auto [IsUnsafe, PropType] = isPropImplUnsafePtr(PropDecl);
+    auto [IsUnsafe, PropType, IsPtrToSafePtr] = isPropImplUnsafePtr(PropDecl);
     if (!IsUnsafe)
       return;
 
     if (auto *MemberCXXRD = PropType->getPointeeCXXRecordDecl())
-      reportBug(PropDecl, PropType, MemberCXXRD, CD);
+      reportBug(PropDecl, PropType, MemberCXXRD, CD, IsPtrToSafePtr);
     else if (auto *ObjCDecl = getObjCDecl(PropType))
-      reportBug(PropDecl, PropType, ObjCDecl, CD);
+      reportBug(PropDecl, PropType, ObjCDecl, CD, IsPtrToSafePtr);
   }
 
-  std::pair<bool, const Type *>
+  std::tuple<bool, const Type *, bool>
   isPropImplUnsafePtr(const ObjCPropertyDecl *PD) const {
     if (!PD)
-      return {false, nullptr};
+      return {false, nullptr, false};
 
     auto QT = PD->getType();
     const Type *PropType = QT.getTypePtrOrNull();
     if (!PropType)
-      return {false, nullptr};
+      return {false, nullptr, false};
 
     // "assign" property doesn't retain even under ARC so treat it as unsafe.
     bool ignoreARC =
@@ -235,7 +236,22 @@ class RawPtrRefMemberChecker
         PD->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak;
     bool HasSafeAttr = PD->isRetaining() || IsWeak;
     auto IsUnsafePtr = isUnsafePtr(QT, ignoreARC);
-    return {IsUnsafePtr && *IsUnsafePtr && !HasSafeAttr, PropType};
+    if (IsUnsafePtr && *IsUnsafePtr)
+      return {!HasSafeAttr, PropType, false};
+
+    while (PropType->isPointerType() || PropType->isReferenceType()) {
+      auto PointeeQT = PropType->getPointeeType();
+      if (isSafePtr(PointeeQT))
+        return {true, PropType, true};
+      PropType = PointeeQT.getTypePtrOrNull();
+      if (!PropType)
+        break;
+      auto IsUnsafePtr = isUnsafePtr(PointeeQT);
+      if (IsUnsafePtr && *IsUnsafePtr)
+        return {true, PropType, false};
+    }
+
+    return {false, nullptr, false};
   }
 
   bool shouldSkipDecl(const RecordDecl *RD) const {
@@ -275,7 +291,8 @@ class RawPtrRefMemberChecker
   template <typename DeclType, typename PointeeType, typename ParentDeclType>
   void reportBug(const DeclType *Member, const Type *MemberType,
                  const PointeeType *Pointee,
-                 const ParentDeclType *ClassCXXRD) const {
+                 const ParentDeclType *ClassCXXRD,
+                 bool IsPtrToSafe = false) const {
     assert(Member);
     assert(MemberType);
     assert(Pointee);
@@ -297,7 +314,7 @@ class RawPtrRefMemberChecker
       Os << " is a ";
     else
       Os << " contains a ";
-    if (printPointer(Os, MemberType) == PrintDeclKind::Pointer) {
+    if (printPointer(Os, MemberType, IsPtrToSafe) == PrintDeclKind::Pointer) {
       auto Typedef = MemberType->getAs<TypedefType>();
       assert(Typedef);
       printQuotedQualifiedName(Os, Typedef->getDecl());
@@ -314,12 +331,22 @@ class RawPtrRefMemberChecker
 
   enum class PrintDeclKind { Pointee, Pointer };
   virtual PrintDeclKind printPointer(llvm::raw_svector_ostream &Os,
-                                     const Type *T) const {
+                                     const Type *T, bool IsPtrToSafe) const {
     T = T->getUnqualifiedDesugaredType();
     bool IsPtr = isa<PointerType>(T) || isa<ObjCObjectPointerType>(T);
-    Os << (IsPtr ? "raw pointer" : "reference") << " to " << typeName() << " ";
+    Os << "raw " << (IsPtr ? "pointer" : "reference") << " to ";
+    if (!IsPtrToSafe)
+      Os << typeName() << " ";
     return PrintDeclKind::Pointee;
   }
+
+  void printTypeName(llvm::raw_ostream &Os, const Type *T) const {
+    if (auto *RD = T->getAsRecordDecl())
+      RD->getNameForDiagnostic(Os, RD->getASTContext().getPrintingPolicy(),
+                               /*Qualified=*/true);
+    else
+      Os << typeName();
+  }
 };
 
 class NoUncountedMemberChecker final : public RawPtrRefMemberChecker {
@@ -332,6 +359,10 @@ class NoUncountedMemberChecker final : public 
RawPtrRefMemberChecker {
     return isUncountedPtr(QT.getCanonicalType());
   }
 
+  bool isSafePtr(QualType QT) const final {
+    return isRefPtrType(QT);
+  }
+
   const char *typeName() const final { return "ref-countable type"; }
 
   const char *invariant() const final {
@@ -349,6 +380,10 @@ class NoUncheckedPtrMemberChecker final : public 
RawPtrRefMemberChecker {
     return isUncheckedPtr(QT.getCanonicalType());
   }
 
+  bool isSafePtr(QualType QT) const final {
+    return isCheckedPtrType(QT);
+  }
+
   const char *typeName() const final { return "CheckedPtr capable type"; }
 
   const char *invariant() const final {
@@ -371,6 +406,10 @@ class NoUnretainedMemberChecker final : public 
RawPtrRefMemberChecker {
     return RTC->isUnretained(QT, ignoreARC);
   }
 
+  bool isSafePtr(QualType QT) const final {
+    return isRetainPtrOrOSPtrType(QT);
+  }
+
   const char *typeName() const final { return "retainable type"; }
 
   const char *invariant() const final {
@@ -378,12 +417,13 @@ class NoUnretainedMemberChecker final : public 
RawPtrRefMemberChecker {
   }
 
   PrintDeclKind printPointer(llvm::raw_svector_ostream &Os,
-                             const Type *T) const final {
+                             const Type *T, bool IsPtrToSafe) const final {
+    // FIXME: Support IsPtrToSafe.
     if (!isa<ObjCObjectPointerType>(T) && T->getAs<TypedefType>()) {
       Os << typeName() << " ";
       return PrintDeclKind::Pointer;
     }
-    return RawPtrRefMemberChecker::printPointer(Os, T);
+    return RawPtrRefMemberChecker::printPointer(Os, T, IsPtrToSafe);
   }
 };
 
diff --git a/clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp 
b/clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp
index 3fe15d88ff312..57ca3f98a14da 100644
--- a/clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/unchecked-members.cpp
@@ -9,7 +9,7 @@ namespace members {
     CheckedObj* a = nullptr;
 // expected-warning@-1{{Member variable 'a' in 'members::Foo' is a raw pointer 
to CheckedPtr capable type 'CheckedObj'}}
     CheckedObj& b;
-// expected-warning@-1{{Member variable 'b' in 'members::Foo' is a reference 
to CheckedPtr capable type 'CheckedObj'}}
+// expected-warning@-1{{Member variable 'b' in 'members::Foo' is a raw 
reference to CheckedPtr capable type 'CheckedObj'}}
 
     [[clang::suppress]]
     CheckedObj* a_suppressed = nullptr;
@@ -19,6 +19,14 @@ namespace members {
 
     CheckedPtr<CheckedObj> c;
     CheckedRef<CheckedObj> d;
+    CheckedRef<RefCountable>* e;
+// expected-warning@-1{{Member variable 'e' in 'members::Foo' is a raw pointer 
to 'CheckedRef<RefCountable>'}}
+    CheckedRef<RefCountable>& f;
+// expected-warning@-1{{Member variable 'f' in 'members::Foo' is a raw 
reference to 'CheckedRef<RefCountable>'}}
+    CheckedRef<RefCountable>** g;
+// expected-warning@-1{{Member variable 'g' in 'members::Foo' contains a raw 
pointer to 'CheckedRef<RefCountable>'}}
+    CheckedRef<RefCountable>* h;
+// expected-warning@-1{{Member variable 'h' in 'members::Foo' is a raw pointer 
to 'CheckedRef<RefCountable>'}}
 
   public:
     Foo();
@@ -39,8 +47,12 @@ namespace unions {
   union Foo {
     CheckedObj* a;
     // expected-warning@-1{{Member variable 'a' in 'unions::Foo' is a raw 
pointer to CheckedPtr capable type 'CheckedObj'}}
-    CheckedPtr<CheckedObj> c;
-    CheckedRef<CheckedObj> d;
+    CheckedPtr<CheckedObj> b;
+    CheckedRef<CheckedObj> c;
+    CheckedObj** d;
+    // expected-warning@-1{{Member variable 'd' in 'unions::Foo' contains a 
raw pointer to CheckedPtr capable type 'CheckedObj'}}
+    CheckedPtr<CheckedObj>* e;
+    // expected-warning@-1{{Member variable 'e' in 'unions::Foo' is a raw 
pointer to 'CheckedPtr<CheckedObj>'}}
   };
 
   template<class T>
@@ -76,8 +88,16 @@ namespace ptr_to_ptr_to_checked_ptr_capable {
   };
   TemplateList<CheckedObj> list;
 
-  struct SafeList {
+  struct FormerlySafeList {
     CheckedPtr<CheckedObj>* elements;
+    // expected-warning@-1{{Member variable 'elements' in 
'ptr_to_ptr_to_checked_ptr_capable::FormerlySafeList' is a raw pointer to 
'CheckedPtr<CheckedObj>'}}
+  };
+
+  struct Container {
+    CheckedPtr<CheckedObj>* [[clang::annotate_type("webkit.unsafeptr")]] 
elements1;
+    CheckedPtr<CheckedObj>** [[clang::annotate_type("webkit.unsafeptr")]] 
elements2;
+    // expected-warning@-1{{Member variable 'elements2' in 
'ptr_to_ptr_to_checked_ptr_capable::Container' contains a raw pointer to 
'CheckedPtr<CheckedObj>'}}
+    CheckedRef<CheckedObj>* [[clang::annotate_type("webkit.unsafeptr")]]* 
[[clang::annotate_type("webkit.unsafeptr")]] elements3;
   };
 
 } // namespace ptr_to_ptr_to_checked_ptr_capable
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-members-objc.mm 
b/clang/test/Analysis/Checkers/WebKit/uncounted-members-objc.mm
index 83b08a6841d26..dcbc6e74eee9b 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-members-objc.mm
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-members-objc.mm
@@ -17,7 +17,25 @@ @interface SomeObjC : NSObject {
 // expected-warning@-1{{Instance variable '_uncounted1' in 'SomeObjC' is a raw 
pointer to ref-countable type 'RefCountable'}}  
   RefPtr<RefCountable> _counted1;
   [[clang::suppress]] RefCountable* _uncounted2;
+  RefCountable** _ptr_to_ptr_to_uncounted;
+// expected-warning@-1{{Instance variable '_ptr_to_ptr_to_uncounted' in 
'SomeObjC' contains a raw pointer to ref-countable type 'RefCountable'}}  
+  RefPtr<RefCountable>* ptr_to_refptr1;
+// expected-warning@-1{{Instance variable 'ptr_to_refptr1' in 'SomeObjC' is a 
raw pointer to 'RefPtr<RefCountable>'}}
+  RefPtr<RefCountable>* [[clang::annotate_type("webkit.unsafeptr")]] 
_ptr_to_refptr2;
+  RefPtr<RefCountable>** _ptr_to_refptr3;
+// expected-warning@-1{{Instance variable '_ptr_to_refptr3' in 'SomeObjC' 
contains a raw pointer to 'RefPtr<RefCountable>'}}
+  Ref<RefCountable>* [[clang::annotate_type("webkit.unsafeptr")]] _ptr_to_ref1;
+  Ref<RefCountable>** _ptr_to_ref2;
+// expected-warning@-1{{Instance variable '_ptr_to_ref2' in 'SomeObjC' 
contains a raw pointer to 'Ref<RefCountable>'}}
 }
+@property (nonatomic) RefCountable **obj1;
+// expected-warning@-1{{Property 'obj1' in 'SomeObjC' contains a raw pointer 
to ref-countable type 'RefCountable'}}
+@property (nonatomic) RefPtr<RefCountable> *obj2;
+// expected-warning@-1{{Property 'obj2' in 'SomeObjC' is a raw pointer to 
'RefPtr<RefCountable>'}}
+@property (nonatomic) RefPtr<RefCountable> **obj3;
+// expected-warning@-1{{Property 'obj3' in 'SomeObjC' contains a raw pointer 
to 'RefPtr<RefCountable>'}}
+@property(nonatomic, readonly) Ref<RefCountable> *syn_prop;
+// expected-warning@-1{{Property 'syn_prop' in 'SomeObjC' is a raw pointer to 
'Ref<RefCountable>'}}
 - (void)doWork;
 @end
 
@@ -26,8 +44,14 @@ @implementation SomeObjC {
 // expected-warning@-1{{Instance variable '_uncounted3' in 'SomeObjC' is a raw 
pointer to ref-countable type 'RefCountable'}}
   RefPtr<RefCountable> _counted2;
   [[clang::suppress]] RefCountable* _uncounted4;
+  RefCountable** _uncounted5;
+// expected-warning@-1{{Instance variable '_uncounted5' in 'SomeObjC' contains 
a raw pointer to ref-countable type 'RefCountable'}}  
+  RefPtr<RefCountable>* _ptr_to_refptr1;
+// expected-warning@-1{{Instance variable '_ptr_to_refptr1' in 'SomeObjC' is a 
raw pointer to 'RefPtr<RefCountable>'}}
 }
 
+@synthesize syn_prop;
+
 - (void)doWork {
   doSomeWork();
 }
diff --git a/clang/test/Analysis/Checkers/WebKit/uncounted-members.cpp 
b/clang/test/Analysis/Checkers/WebKit/uncounted-members.cpp
index b8c443cda4f8e..37464d0ddb0ac 100644
--- a/clang/test/Analysis/Checkers/WebKit/uncounted-members.cpp
+++ b/clang/test/Analysis/Checkers/WebKit/uncounted-members.cpp
@@ -16,10 +16,20 @@ namespace members {
     RefPtr<RefCountable> b;
 
   public:
+    Foo();
+
     RefCountable silenceWarningAboutInit;
     RefCountable& c = silenceWarningAboutInit;
-// expected-warning@-1{{Member variable 'c' in 'members::Foo' is a reference 
to ref-countable type 'RefCountable'}}
+// expected-warning@-1{{Member variable 'c' in 'members::Foo' is a raw 
reference to ref-countable type 'RefCountable'}}
     Ref<RefCountable> d;
+    Ref<RefCountable>* e;
+// expected-warning@-1{{Member variable 'e' in 'members::Foo' is a raw pointer 
to 'Ref<RefCountable>'}}
+    Ref<RefCountable>& f;
+// expected-warning@-1{{Member variable 'f' in 'members::Foo' is a raw 
reference to 'Ref<RefCountable>'}}
+    Ref<RefCountable>** g;
+// expected-warning@-1{{Member variable 'g' in 'members::Foo' contains a raw 
pointer to 'Ref<RefCountable>'}}
+    RefPtr<RefCountable>* h;
+// expected-warning@-1{{Member variable 'h' in 'members::Foo' is a raw pointer 
to 'RefPtr<RefCountable>'}}
   };
 
   template<class T>
@@ -34,6 +44,7 @@ namespace members {
   private:
     RefCountable* a = nullptr;
   };
+
 } // members
 
 namespace unions {...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/200599
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to