Open 16bit-ykiko opened 3 weeks ago
@llvm/issue-subscribers-clangd
Author: ykiko (16bit-ykiko)
@llvm/issue-subscribers-clang-frontend
Author: ykiko (16bit-ykiko)
Sorry to bother, but ping @mizvekov. Do you have any thoughts on this issue? Or any suggestions on how to fix it? I might give it a try. :)
The instantiated declaration is the result of substitution of the template arguments on the template pattern, and that has no relationship with the point of instantiation, so changing the lexical context would break that model, and would be ambiguous with friend declarations.
The issue @HighCommander4 linked (https://github.com/clangd/clangd/issues/358) is most helpful here, the right solution would be to create an AST node which models explicit instantiations.
The issue @HighCommander4 linked (clangd/clangd#358) is most helpful here, the right solution would be to create an AST node which models explicit instantiations.
What about variable template? It seems that it already has a corresponding AST node -- VarTemplateSpecializationDecl
, but still get wrong or incomplete source information:
namespace test {
template <typename T>
int foo = 2;
}
template <>
int test::foo<int> = 3;
template int test::foo<char>;
Using following code to dump source information:
bool VisitVarTemplateSpecializationDecl(clang::VarTemplateSpecializationDecl* decl) {
llvm::outs() << "----------------------------------------------\n";
decl->getLocation().dump(srcMgr);
decl->getTypeSourceInfo()->getTypeLoc().getSourceRange().dump(srcMgr);
decl->getQualifierLoc().getBeginLoc().dump(srcMgr);
if(auto args = decl->getTemplateArgsAsWritten()) {
for(auto arg: args->arguments()) {
arg.getLocation().dump(srcMgr);
}
}
return true;
}
The output is
---------------------------------------------- explicit instantiation
test.cpp:3:5
<test.cpp:3:1>
<invalid loc>
test.cpp:9:24
---------------------------------------------- explicit specialization
test.cpp:7:11
<test.cpp:7:1>
test.cpp:7:5
test.cpp:7:15
For explicit specialization, everything is correct. But for explicit instantiation, only template argument information is correct.
Currently in clang only information about explicit instantiation of class template is recorded correctly.
The VarTemplateSpecializationDecl
is in the same situation as the ClassTemplateSpecializationDecl
, it's meant to model the specialization per se, not the explicit instantiation as it appears in source code.
The fact it carries source locations just for the specialization arguments is a little weird, and even that doesn't model the fact that explicit instantiations can appear multiple times. It's something we could certainly rethink once we make progress into the new AST nodes.
Oh I understand it. So we need to create a new node to store source location information.
I think we can create something like ExplicitInstantiationDecl
to store the location of qualifier, name, template arguments and angles. And it is just a wrapper to current specialization decl.
In this way, we keep compatible with the old implementation.
Yep, that sounds right, the ExplicitInstantiation node should just link to the *SpecializationDecl
, and it should probably be redeclarable as well, so that we can easily iterate all explicit instantiations of a given template.
If you are interested in pursuing that, I'd encourage you to seek @hokein and @sam-mccall, as they would have more insights into clangd's needs in this area.
In fact, I am writing a new language server for C++. I have been diving into clangd for months, so I am very familiar with it now. I found this problem when I was testing my new indexer, so I will try to fix it to make my indexer work better. :)
Currently, if trigger go-to-definition at the location of
^
, clangd will give no response. And the tokens in the explicit instantiation are also not highlighted. After some investigation, I found that the underlying cause is that the Clang frontend doesn't store the information about explicit instantiation of function templates.Dump the AST of above code
As you can see, the decl from explicit instantiation is only added to its semantic context but not to its lexical context.
If use a visitor to further explore:
The output is
Only instantiation point is recorded correctly, all other information is from primary template.
But for explicit specializations, the information is recorded properly.
The output is
Explicit instantiation of variable template has the same problem.
And I unexpectedly discovered that the location of
TypeAliasTemplate
incorrectly uses the position of theusing
keyword instead of the position of the identifier."