[PATCH] D83501: [clangd][ObjC] Improve xrefs for protocols and classes

David Goldman via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Jul 10 07:06:25 PDT 2020


dgoldman updated this revision to Diff 277026.
dgoldman added a comment.

Fixes for getDefinition/getCanonicalDecl for ObjC


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83501/new/

https://reviews.llvm.org/D83501

Files:
  clang-tools-extra/clangd/XRefs.cpp
  clang-tools-extra/clangd/unittests/XRefsTests.cpp


Index: clang-tools-extra/clangd/unittests/XRefsTests.cpp
===================================================================
--- clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -688,7 +688,14 @@
 
       R"objc(//objc
         @class $decl[[Foo]];
-        @interface $def[[Foo]]
+        Fo^o * getFoo() {
+          return 0;
+        }
+      )objc",
+
+      R"objc(//objc
+        @class Foo;
+        @interface $decl[[Foo]]
         @end
         Fo^o * getFoo() {
           return 0;
@@ -696,8 +703,8 @@
       )objc",
 
       R"objc(//objc
-        @class $decl[[Foo]];
-        @interface Foo
+        @class Foo;
+        @interface $decl[[Foo]]
         @end
         @implementation $def[[Foo]]
         @end
Index: clang-tools-extra/clangd/XRefs.cpp
===================================================================
--- clang-tools-extra/clangd/XRefs.cpp
+++ clang-tools-extra/clangd/XRefs.cpp
@@ -80,16 +80,8 @@
     return FD->getDefinition();
   if (const auto *PD = dyn_cast<ObjCProtocolDecl>(D))
     return PD->getDefinition();
-  // Objective-C classes can have three types of declarations:
-  //
-  // - forward declaration: @class MyClass;
-  // - definition declaration: @interface MyClass ... @end
-  // - implementation: @implementation MyClass ... @end
-  if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D)) {
-    if (const auto *IMD = ID->getImplementation())
-      return IMD;
-    return ID->getDefinition();
-  }
+  if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
+    return ID->getImplementation();
   // Only a single declaration is allowed.
   if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
       isa<TemplateTemplateParmDecl>(D)) // except cases above
@@ -235,6 +227,30 @@
   return llvm::None;
 }
 
+// A wrapper around `Decl::getCanonicalDecl` to support cases where Clang's
+// definition of a canonical declaration doesn't match up to what a programmer
+// would expect. For example, Objective-C classes can have three types of
+// declarations:
+//
+// - forward declaration(s): @class MyClass;
+// - definition declaration: @interface MyClass ... @end
+// - implementation: @implementation MyClass ... @end
+//
+// Clang will consider the forward declaration to be the canonical declaration
+// because it is first, but we actually want the class definition if it is
+// available since that is what a programmer would consider the real definition
+// to be.
+const NamedDecl *getNonStandardCanonicalDecl(const NamedDecl *D) {
+  D = llvm::cast<NamedDecl>(D->getCanonicalDecl());
+
+  // Prefer Objective-C class definitions over the forward declaration.
+  if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
+    if (const auto *DefinitionID = ID->getDefinition())
+      return DefinitionID;
+
+  return D;
+}
+
 // Decls are more complicated.
 // The AST contains at least a declaration, maybe a definition.
 // These are up-to-date, and so generally preferred over index results.
@@ -250,7 +266,7 @@
   llvm::DenseMap<SymbolID, size_t> ResultIndex;
 
   auto AddResultDecl = [&](const NamedDecl *D) {
-    D = llvm::cast<NamedDecl>(D->getCanonicalDecl());
+    D = getNonStandardCanonicalDecl(D);
     auto Loc =
         makeLocation(AST.getASTContext(), nameLocation(*D, SM), MainFilePath);
     if (!Loc)


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D83501.277026.patch
Type: text/x-patch
Size: 3338 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200710/ce05f1b1/attachment.bin>


More information about the cfe-commits mailing list