-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[clangd] Update XRefs to support overriden ObjC methods #127109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
d335931
65f19b7
68fd059
e962112
4f88a70
478cd5a
13c7011
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -430,6 +430,18 @@ locateASTReferent(SourceLocation CurLoc, const syntax::Token *TouchedIdentifier, | |
continue; | ||
} | ||
} | ||
// Special case: an Objective-C method can override a parent class or | ||
// protocol. | ||
if (const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(D)) { | ||
llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides; | ||
OMD->getOverriddenMethods(Overrides); | ||
for (const auto *Override : Overrides) | ||
AddResultDecl(Override); | ||
if (!Overrides.empty()) | ||
LocateASTReferentMetric.record(1, "objc-overriden-method"); | ||
AddResultDecl(OMD); | ||
continue; | ||
} | ||
|
||
// Special case: the cursor is on an alias, prefer other results. | ||
// This targets "using ns::^Foo", where the target is more interesting. | ||
|
@@ -1283,6 +1295,17 @@ std::vector<LocatedSymbol> findImplementations(ParsedAST &AST, Position Pos, | |
} else if (const auto *RD = dyn_cast<CXXRecordDecl>(ND)) { | ||
IDs.insert(getSymbolID(RD)); | ||
QueryKind = RelationKind::BaseOf; | ||
} else if (const auto *OMD = dyn_cast<ObjCMethodDecl>(ND)) { | ||
IDs.insert(getSymbolID(OMD)); | ||
QueryKind = RelationKind::OverriddenBy; | ||
|
||
llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides; | ||
OMD->getOverriddenMethods(Overrides); | ||
for (const auto *Override : Overrides) | ||
IDs.insert(getSymbolID(Override)); | ||
DavidGoldman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} else if (const auto *ID = dyn_cast<ObjCInterfaceDecl>(ND)) { | ||
IDs.insert(getSymbolID(ID)); | ||
QueryKind = RelationKind::BaseOf; | ||
} | ||
} | ||
return findImplementors(std::move(IDs), QueryKind, Index, AST.tuPath()); | ||
|
@@ -1438,6 +1461,15 @@ ReferencesResult findReferences(ParsedAST &AST, Position Pos, uint32_t Limit, | |
getOverriddenMethods(CMD, OverriddenMethods); | ||
} | ||
} | ||
// Special case: Objective-C methods can override a parent class or | ||
// protocol, we should be sure to report references to those. | ||
if (const auto *OMD = llvm::dyn_cast<ObjCMethodDecl>(ND)) { | ||
OverriddenBy.Subjects.insert(getSymbolID(OMD)); | ||
llvm::SmallVector<const ObjCMethodDecl *, 4> Overrides; | ||
OMD->getOverriddenMethods(Overrides); | ||
for (const auto *Override : Overrides) | ||
OverriddenMethods.insert(getSymbolID(Override)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for C++ we recursively traverse up the whole virtual-method hierarchy. any reason for not doing the same here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IIUC this already does - getOverriddenMethods will return methods for the hierarchy since it itself recurses. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i am not sure if it does, e.g. https://github.com/llvm/llvm-project/blob/main/clang/lib/AST/DeclObjC.cpp#L1268-L1273 stops at the first overridden method. maybe you can add some unittests for this as well ? |
||
} | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about the interaction in the other direction? i.e. we're on the protocol declaration and try to do a go-to-definition.
moreover this is going to make go-to-defn on references to a symbol quite chatty (now you'll have both the definition in implementation and definition in protocol as an alternative). I think we want to limit this to only when user triggered the interaction on the definition of the method and not references to it (similar to c++ code path above).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking for that users can use go to implementation to find them.
And that's a good point - didn't think about that, updated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think using go-to-definition for such interactions is a more common workflow (also go-to-impl is not necessarily implemented by all editors). so I think there's merit in making sure that also works (though I won't block this patch on it, as it's not a regression. but I think it warrants at least a
FIXME
)