-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clangd] Retrieve documentation for member function instance from index #153337
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
Conversation
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clangd Author: Nathan Ridge (HighCommander4) ChangesFixes clangd/clangd#2290 Full diff: https://github.com/llvm/llvm-project/pull/153337.diff 2 Files Affected:
diff --git a/clang-tools-extra/clangd/CodeComplete.cpp b/clang-tools-extra/clangd/CodeComplete.cpp
index 9c17b4ca9b706..da51998b9eec0 100644
--- a/clang-tools-extra/clangd/CodeComplete.cpp
+++ b/clang-tools-extra/clangd/CodeComplete.cpp
@@ -1887,7 +1887,19 @@ class CodeCompleteFlow {
for (auto &Cand : C.first) {
if (Cand.SemaResult &&
Cand.SemaResult->Kind == CodeCompletionResult::RK_Declaration) {
- auto ID = clangd::getSymbolID(Cand.SemaResult->getDeclaration());
+ const NamedDecl *DeclToLookup = Cand.SemaResult->getDeclaration();
+ // For instantiations of members of class templates, the
+ // documentation will be stored at the member's original
+ // declaration.
+ // FIXME: We'd like to handle fields too but FieldDecl is missing a
+ // method equivalent to getInstantiatedFromMemberFunction().
+ if (const auto *FD = dyn_cast<FunctionDecl>(DeclToLookup)) {
+ if (const auto *InstantiatedFrom =
+ FD->getInstantiatedFromMemberFunction()) {
+ DeclToLookup = InstantiatedFrom;
+ }
+ }
+ auto ID = clangd::getSymbolID(DeclToLookup);
if (!ID)
continue;
Req.IDs.insert(ID);
diff --git a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
index 5a5d815076e2a..57eb9fcdecb21 100644
--- a/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
+++ b/clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp
@@ -1154,23 +1154,45 @@ TEST(CompletionTest, CommentsOnMembersFromHeader) {
/// This is a member function.
int delta();
};
+
+ template <typename T>
+ struct beta {
+ /// This is a member field inside a template.
+ int omega;
+
+ /// This is a member function inside a template.
+ int epsilon();
+ };
)cpp";
auto File = testPath("foo.cpp");
Annotations Test(R"cpp(
#include "foo.h"
alpha a;
-int x = a.^
+beta<int> b;
+int x = a.$p1^;
+int y = b.$p2^;
)cpp");
runAddDocument(Server, File, Test.code());
auto CompletionList =
- llvm::cantFail(runCodeComplete(Server, File, Test.point(), {}));
+ llvm::cantFail(runCodeComplete(Server, File, Test.point("p1"), {}));
EXPECT_THAT(CompletionList.Completions,
Contains(AllOf(named("gamma"), doc("This is a member field."))));
EXPECT_THAT(
CompletionList.Completions,
Contains(AllOf(named("delta"), doc("This is a member function."))));
+
+ CompletionList =
+ llvm::cantFail(runCodeComplete(Server, File, Test.point("p2"), {}));
+
+ EXPECT_THAT(CompletionList.Completions,
+ Contains(AllOf(named("omega")
+ /* FIXME: Doc retrieval does not work yet*/)));
+ EXPECT_THAT(
+ CompletionList.Completions,
+ Contains(AllOf(named("epsilon"),
+ doc("This is a member function inside a template."))));
}
TEST(CompletionTest, CommentsOnMembersFromHeaderOverloadBundling) {
|
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.
Should I be using FunctionDecl::getTemplateInstantiationPattern
instead?
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 so? getInstantiatedFromMemberFunction gives you the last pattern that this instantiation comes from, and that pattern could be a half-instantiated template declaration.
So if you're looking for the primary template, I think we should turn to getTemplateInstantiationPattern.
Also note that there are some edge cases where we lack a tracking of the pattern, e.g. a templated friend declaration
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.
Makes sense, thanks! Done.
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 found some libSema code that rolls its own equivalent for fields using a DeclContext::lookup()
call; we could consider using that approach here 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.
How about merging them into HeuristicResolver?
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 appreciate HeuristicResolver
is a convenient place to house code that needs to be shared between parser code and clang API clients like clangd, but I'd also like to limit its scope to operations that seem heuristic in nature in some way.
This one just seems like a missing link in the AST, with nothing heuristic about it (the declaration it returns should definitely be one the input decl was instantiated from). So maybe a static method on ASTContext would make sense?
Anyways, I'm going to leave addressing this FIXME to a future patch; I expect methods are the more common / important use case here.
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.
do we know why the discrepancy exists between templated-code itself vs non-templated decls (i.e. how come we get the decl with comments when we're looking at foo<int>()
)? I wonder if we should change something in sema-codecomplete to refer to "spelled" declaration in completion-result for non-templated cases (e.g. bar
in Foo<int>::bar()
) rather than working around it here.
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.
do we know why the discrepancy exists between templated-code itself vs non-templated decls (i.e. how come we get the decl with comments when we're looking at
foo<int>()
)?
I'm not sure I'm following. Is foo
is a function template here? In what context are you requesting completion?
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.
In any case, here's a reason not to have SemaCodeComplete give us the "spelled" declaration:
template <typename T>
struct vector {
void push(T);
};
int main() {
vector<int> v;
v.^ // signature shown is `push(int)`
}
Returning the instantiated declaration allows us to e.g. show the instantiated signature (push(int)
rather than push(T)
) which is more helpful to the user.
In that sense, the instantiated declaration provides strictly more information than the spelled declaration; the consumer can always query the spelled declaration (as we're doing here) if desired.
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.
sorry I think I was just testing this wrong (I had comments from AST, not from index), hence I was confused.
but that still led me to https://github.com/llvm/llvm-project/blob/main/clang/lib/AST/ASTContext.cpp#L333-L401. Can we just use that instead to unify behavior with AST-based completion-comments here?
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.
but that still led me to https://github.com/llvm/llvm-project/blob/main/clang/lib/AST/ASTContext.cpp#L333-L401. Can we just use that instead to unify behavior with AST-based completion-comments here?
Done.
I chose DeclTemplate.h
as the header to house the shared function, as it seemed like a better fit than ASTContext.h
; let me know if you have a different preference.
8f5fae9
to
e0fac46
Compare
Review ping |
1 similar comment
Review ping |
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.
sorry for taking an eternity here :/
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.
sorry I think I was just testing this wrong (I had comments from AST, not from index), hence I was confused.
but that still led me to https://github.com/llvm/llvm-project/blob/main/clang/lib/AST/ASTContext.cpp#L333-L401. Can we just use that instead to unify behavior with AST-based completion-comments here?
e0fac46
to
fc114ff
Compare
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.
thanks, LGTM!
CodeCompleteTests.cpp is failing on one of the buildbots (https://lab.llvm.org/buildbot/#/builders/25/builds/12099/steps/11/logs/stdio), which I suspect might be related to this pull request. Could you please take a look?
|
I had a look. While the failing test is in the same file as one modified by this PR, it's (1) in a different test that I don't expect to be affected by this PR, and (2) it's a timeout whose failure is more likely to indicate an unrelated intermittent issue. A subsequent build on the same buildbot is successful. I'll keep an eye on a few more builds, but I suspect the linked failure is a pre-existing intermittent and the fact that it's in the same file that's touched by this PR was coincidental. |
Thanks for checking! Sorry for the noise. |
Fixes clangd/clangd#2290