@@ -372,6 +372,15 @@ void enhanceLocatedSymbolsFromIndex(llvm::MutableArrayRef<LocatedSymbol> Result,
372372 });
373373}
374374
375+ bool objcMethodIsTouched (const SourceManager &SM, const ObjCMethodDecl *OMD,
376+ SourceLocation Loc) {
377+ unsigned NumSels = OMD->getNumSelectorLocs ();
378+ for (unsigned I = 0 ; I < NumSels; ++I)
379+ if (SM.getSpellingLoc (OMD->getSelectorLoc (I)) == Loc)
380+ return true ;
381+ return false ;
382+ }
383+
375384// Decls are more complicated.
376385// The AST contains at least a declaration, maybe a definition.
377386// These are up-to-date, and so generally preferred over index results.
@@ -430,6 +439,26 @@ locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier,
430439 continue ;
431440 }
432441 }
442+ // Special case: - (void)^method {} should jump to overrides, but the decl
443+ // shouldn't, only the definition. Note that an Objective-C method can
444+ // override a parent class or protocol.
445+ //
446+ // FIXME: Support jumping from a protocol decl to overrides on go-to
447+ // definition.
448+ if (const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D)) {
449+ if (OMD->isThisDeclarationADefinition () && TouchedIdentifier &&
450+ objcMethodIsTouched (SM, OMD, TouchedIdentifier->location ())) {
451+ llvm::SmallVector<const ObjCMethodDecl *, 4 > Overrides;
452+ OMD->getOverriddenMethods (Overrides);
453+ if (!Overrides.empty ()) {
454+ for (const auto *Override : Overrides)
455+ AddResultDecl (Override);
456+ LocateASTReferentMetric.record (1 , " objc-overriden-method" );
457+ }
458+ AddResultDecl (OMD);
459+ continue ;
460+ }
461+ }
433462
434463 // Special case: the cursor is on an alias, prefer other results.
435464 // This targets "using ns::^Foo", where the target is more interesting.
@@ -1283,6 +1312,12 @@ std::vector<LocatedSymbol> findImplementations(ParsedAST &AST, Position Pos,
12831312 } else if (const auto *RD = dyn_cast<CXXRecordDecl>(ND)) {
12841313 IDs.insert (getSymbolID (RD));
12851314 QueryKind = RelationKind::BaseOf;
1315+ } else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(ND)) {
1316+ IDs.insert (getSymbolID (OMD));
1317+ QueryKind = RelationKind::OverriddenBy;
1318+ } else if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) {
1319+ IDs.insert (getSymbolID (ID));
1320+ QueryKind = RelationKind::BaseOf;
12861321 }
12871322 }
12881323 return findImplementors (std::move (IDs), QueryKind, Index, AST.tuPath ());
@@ -1302,6 +1337,21 @@ void getOverriddenMethods(const CXXMethodDecl *CMD,
13021337 }
13031338}
13041339
1340+ // Recursively finds all the overridden methods of `OMD` in complete type
1341+ // hierarchy.
1342+ void getOverriddenMethods (const ObjCMethodDecl *OMD,
1343+ llvm::DenseSet<SymbolID> &OverriddenMethods) {
1344+ if (!OMD)
1345+ return ;
1346+ llvm::SmallVector<const ObjCMethodDecl *, 4 > Overrides;
1347+ OMD->getOverriddenMethods (Overrides);
1348+ for (const ObjCMethodDecl *Base : Overrides) {
1349+ if (auto ID = getSymbolID (Base))
1350+ OverriddenMethods.insert (ID);
1351+ getOverriddenMethods (Base, OverriddenMethods);
1352+ }
1353+ }
1354+
13051355std::optional<std::string>
13061356stringifyContainerForMainFileRef (const Decl *Container) {
13071357 // FIXME We might also want to display the signature here
@@ -1438,6 +1488,12 @@ ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit,
14381488 getOverriddenMethods (CMD, OverriddenMethods);
14391489 }
14401490 }
1491+ // Special case: Objective-C methods can override a parent class or
1492+ // protocol, we should be sure to report references to those.
1493+ if (const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(ND)) {
1494+ OverriddenBy.Subjects .insert (getSymbolID (OMD));
1495+ getOverriddenMethods (OMD, OverriddenMethods);
1496+ }
14411497 }
14421498 }
14431499
0 commit comments