================
@@ -460,29 +460,80 @@ class ASTWalker : public RecursiveASTVisitor<ASTWalker> {
     return true;
   }
 
-  bool VisitObjCMessageExpr(ObjCMessageExpr *E) {
-    auto StartLoc = E->getSelectorStartLoc();
-    // Identify the selector and the method declaration
-    if (auto *Method = E->getMethodDecl()) {
-      // Report the method as a used symbol
-      report(StartLoc, Method);
+  /// Determines whether a protocol is already covered by the receiver's type,
+  /// either through adopted protocol qualifiers (e.g. `id<Proto>` or an
+  /// inheriting sub-protocol) or through class conformance on the receiver
+  /// interface (e.g. `MyClass <Proto>`).
+  bool IsProtocolCoveredByReceiver(ObjCProtocolDecl *Proto,
+                                   const ObjCObjectPointerType *ObjCPtr,
+                                   ObjCInterfaceDecl *IFace) {
+    if (ObjCPtr) {
+      ASTContext &Ctx = Proto->getASTContext();
+      for (auto *ReceiverProto : ObjCPtr->quals())
+        if (Ctx.ProtocolCompatibleWithProtocol(Proto, ReceiverProto))
+          return true;
     }
+    return IFace && IFace->ClassImplementsProtocol(Proto, true);
+  }
 
-    // If it's a class message, report the interface/class as used
-    if (E->getReceiverKind() == ObjCMessageExpr::Class) {
-      if (auto *Interface = E->getReceiverInterface()) {
-        report(E->getReceiverRange().getBegin(), Interface);
-      }
-      return true;
-    }
-    if (auto *Interface = E->getReceiverInterface()) {
-      report(StartLoc, Interface, RefType::Implicit);
+  void ReportMemberDecl(SourceLocation Loc, NamedDecl *Member,
+                        const ObjCObjectPointerType *ObjCPtr,
+                        ObjCInterfaceDecl *ReceiverIFace, bool IsSuperReceiver,
+                        bool IsClassReceiver) {
+    if (!Member)
+      return;
+    auto *DC = Member->getDeclContext();
+    if (auto *Cat = dyn_cast<ObjCCategoryDecl>(DC)) {
+      // Category members (methods, properties, accessors) must be reported so
+      // the category's header is included.
+      report(Loc, Cat);
+    } else if (auto *Proto = dyn_cast<ObjCProtocolDecl>(DC)) {
+      // Report the protocol member unless the receiver's type already covers
+      // conformance to this protocol.
+      if (IsSuperReceiver ||
+          !IsProtocolCoveredByReceiver(Proto, ObjCPtr, ReceiverIFace))
+        report(Loc, Member);
+    } else if (auto *IFace = dyn_cast<ObjCInterfaceDecl>(DC)) {
+      // If the member is declared on the receiver's interface or an inherited
+      // superclass, the receiver's header already provides it.
+      // Report the member explicitly only if there is no receiver interface,
+      // the interface is not an ancestor, it is a class receiver, or super is
+      // used.
+      if (!ReceiverIFace ||
+          (ReceiverIFace != IFace && !IFace->isSuperClassOf(ReceiverIFace)) ||
+          (IsClassReceiver && ReceiverIFace == IFace) || IsSuperReceiver)
----------------
nico wrote:

Do you need `(IsClassReceiver && ReceiverIFace == IFace)` here? This method has 
a single caller, and it has an explicit

```
case ObjCMessageExpr::Class:
      report(E->getReceiverRange().getBegin(), ReceiverIFace);
```

further down, which I think reports the same thing a 2nd time for this case. 
One of the two should be enough.

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

Reply via email to