[clang-tools-extra] 88a2ac6 - [clangd] Improve XRefs support for ObjCMethodDecl
David Goldman via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 26 09:11:36 PDT 2022
Author: David Goldman
Date: 2022-07-26T12:11:26-04:00
New Revision: 88a2ac6ad623cd7519070f6b0bf2de2793bb90dd
URL: https://github.com/llvm/llvm-project/commit/88a2ac6ad623cd7519070f6b0bf2de2793bb90dd
DIFF: https://github.com/llvm/llvm-project/commit/88a2ac6ad623cd7519070f6b0bf2de2793bb90dd.diff
LOG: [clangd] Improve XRefs support for ObjCMethodDecl
- Correct nameLocation to point to the first selector fragment instead
of the - or +
- getDefinition now searches through the proper impl decls to find
the definition of the ObjCMethodDecl if one exists
Differential Revision: https://reviews.llvm.org/D130095
Added:
Modified:
clang-tools-extra/clangd/AST.cpp
clang-tools-extra/clangd/AST.h
clang-tools-extra/clangd/XRefs.cpp
clang-tools-extra/clangd/unittests/XRefsTests.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clangd/AST.cpp b/clang-tools-extra/clangd/AST.cpp
index f7d526fab0963..4ddfca328eaed 100644
--- a/clang-tools-extra/clangd/AST.cpp
+++ b/clang-tools-extra/clangd/AST.cpp
@@ -171,6 +171,9 @@ bool isImplementationDetail(const Decl *D) {
SourceLocation nameLocation(const clang::Decl &D, const SourceManager &SM) {
auto L = D.getLocation();
+ // For `- (void)foo` we want `foo` not the `-`.
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(&D))
+ L = MD->getSelectorStartLoc();
if (isSpelledInSource(L, SM))
return SM.getSpellingLoc(L);
return SM.getExpansionLoc(L);
@@ -356,6 +359,20 @@ SymbolID getSymbolID(const llvm::StringRef MacroName, const MacroInfo *MI,
return SymbolID(USR);
}
+const ObjCImplDecl *getCorrespondingObjCImpl(const ObjCContainerDecl *D) {
+ if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
+ return ID->getImplementation();
+ if (const auto *CD = dyn_cast<ObjCCategoryDecl>(D)) {
+ if (CD->IsClassExtension()) {
+ if (const auto *ID = CD->getClassInterface())
+ return ID->getImplementation();
+ return nullptr;
+ }
+ return CD->getImplementation();
+ }
+ return nullptr;
+}
+
std::string printType(const QualType QT, const DeclContext &CurContext,
const llvm::StringRef Placeholder) {
std::string Result;
diff --git a/clang-tools-extra/clangd/AST.h b/clang-tools-extra/clangd/AST.h
index e0024c27aca3a..f313161b6c608 100644
--- a/clang-tools-extra/clangd/AST.h
+++ b/clang-tools-extra/clangd/AST.h
@@ -93,6 +93,30 @@ SymbolID getSymbolID(const Decl *D);
SymbolID getSymbolID(const llvm::StringRef MacroName, const MacroInfo *MI,
const SourceManager &SM);
+/// Return the corresponding implementation/definition for the given ObjC
+/// container if it has one, otherwise, return nullptr.
+///
+/// Objective-C classes can have three types of declarations:
+///
+/// - forward declaration: @class MyClass;
+/// - true declaration (interface definition): @interface MyClass ... @end
+/// - true definition (implementation): @implementation MyClass ... @end
+///
+/// Objective-C categories are extensions on classes:
+///
+/// - declaration: @interface MyClass (Ext) ... @end
+/// - definition: @implementation MyClass (Ext) ... @end
+///
+/// With one special case, a class extension, which is normally used to keep
+/// some declarations internal to a file without exposing them in a header.
+///
+/// - class extension declaration: @interface MyClass () ... @end
+/// - which really links to class definition: @implementation MyClass ... @end
+///
+/// For Objective-C protocols, e.g. @protocol MyProtocol ... @end this will
+/// return nullptr as protocols don't have an implementation.
+const ObjCImplDecl *getCorrespondingObjCImpl(const ObjCContainerDecl *D);
+
/// Returns a QualType as string. The result doesn't contain unwritten scopes
/// like anonymous/inline namespace.
std::string printType(const QualType QT, const DeclContext &CurContext,
diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp
index c620b3897f6de..46827433e136d 100644
--- a/clang-tools-extra/clangd/XRefs.cpp
+++ b/clang-tools-extra/clangd/XRefs.cpp
@@ -83,32 +83,20 @@ const NamedDecl *getDefinition(const NamedDecl *D) {
if (const auto *CTD = dyn_cast<ClassTemplateDecl>(D))
if (const auto *RD = CTD->getTemplatedDecl())
return RD->getDefinition();
- // Objective-C classes can have three types of declarations:
- //
- // - forward declaration: @class MyClass;
- // - true declaration (interface definition): @interface MyClass ... @end
- // - true definition (implementation): @implementation MyClass ... @end
- //
- // Objective-C categories are extensions are on classes:
- //
- // - declaration: @interface MyClass (Ext) ... @end
- // - definition: @implementation MyClass (Ext) ... @end
- //
- // With one special case, a class extension, which is normally used to keep
- // some declarations internal to a file without exposing them in a header.
- //
- // - class extension declaration: @interface MyClass () ... @end
- // - which really links to class definition: @implementation MyClass ... @end
- if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(D))
- return ID->getImplementation();
- if (const auto *CD = dyn_cast<ObjCCategoryDecl>(D)) {
- if (CD->IsClassExtension()) {
- if (const auto *ID = CD->getClassInterface())
- return ID->getImplementation();
+ if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
+ if (MD->isThisDeclarationADefinition())
+ return MD;
+ // Look for the method definition inside the implementation decl.
+ auto *DeclCtx = cast<Decl>(MD->getDeclContext());
+ if (DeclCtx->isInvalidDecl())
return nullptr;
- }
- return CD->getImplementation();
+
+ if (const auto *CD = dyn_cast<ObjCContainerDecl>(DeclCtx))
+ if (const auto *Impl = getCorrespondingObjCImpl(CD))
+ return Impl->getMethod(MD->getSelector(), MD->isInstanceMethod());
}
+ if (const auto *CD = dyn_cast<ObjCContainerDecl>(D))
+ return getCorrespondingObjCImpl(CD);
// Only a single declaration is allowed.
if (isa<ValueDecl>(D) || isa<TemplateTypeParmDecl>(D) ||
isa<TemplateTemplateParmDecl>(D)) // except cases above
diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
index 9294aee0396c2..0f3a12b7398ef 100644
--- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp
+++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp
@@ -957,6 +957,46 @@ TEST(LocateSymbol, All) {
Fo^o * getFoo() {
return 0;
}
+ )objc",
+
+ R"objc(// Method decl and definition for ObjC class.
+ @interface Cat
+ - (void)$decl[[meow]];
+ @end
+ @implementation Cat
+ - (void)$def[[meow]] {}
+ @end
+ void makeNoise(Cat *kitty) {
+ [kitty me^ow];
+ }
+ )objc",
+
+ R"objc(// Method decl and definition for ObjC category.
+ @interface Dog
+ @end
+ @interface Dog (Play)
+ - (void)$decl[[runAround]];
+ @end
+ @implementation Dog (Play)
+ - (void)$def[[runAround]] {}
+ @end
+ void play(Dog *dog) {
+ [dog run^Around];
+ }
+ )objc",
+
+ R"objc(// Method decl and definition for ObjC class extension.
+ @interface Dog
+ @end
+ @interface Dog ()
+ - (void)$decl[[howl]];
+ @end
+ @implementation Dog
+ - (void)$def[[howl]] {}
+ @end
+ void play(Dog *dog) {
+ [dog ho^wl];
+ }
)objc"};
for (const char *Test : Tests) {
Annotations T(Test);
More information about the cfe-commits
mailing list