[clang][Index] Fix the incomplete instantiations in libindex.

Summary:
libindex will canonicalize references to template instantiations:
- 1) reference to an explicit template specialization, report the specializatiion
- 2) otherwise, report the primary template

but 2) is not true for incomplete instantiations, this patch fixes this.

Fixes https://github.com/clangd/clangd/issues/287

Reviewers: kadircet

Subscribers: ilya-biryukov, jkorous, arphaman, usaxena95, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D74830
This commit is contained in:
Haojian Wu 2020-02-19 12:27:12 +01:00
parent 2f215cf36a
commit bb9e92bad5
4 changed files with 53 additions and 4 deletions

View File

@ -948,6 +948,12 @@ TEST(FindReferences, WithinAST) {
int [[v^ar]] = 0;
void foo(int s = [[var]]);
)cpp",
R"cpp(
template <typename T>
class [[Fo^o]] {};
void func([[Foo]]<int>);
)cpp",
};
for (const char *Test : Tests) {
Annotations T(Test);

View File

@ -169,6 +169,10 @@ bool IndexingContext::isTemplateImplicitInstantiation(const Decl *D) {
}
switch (TKind) {
case TSK_Undeclared:
// Instantiation maybe not happen yet when we see a SpecializationDecl,
// e.g. when the type doesn't need to be complete, we still treat it as an
// instantiation as we'd like to keep the canonicalized result consistent.
return isa<ClassTemplateSpecializationDecl>(D);
case TSK_ExplicitSpecialization:
return false;
case TSK_ImplicitInstantiation:
@ -206,7 +210,12 @@ getDeclContextForTemplateInstationPattern(const Decl *D) {
static const Decl *adjustTemplateImplicitInstantiation(const Decl *D) {
if (const ClassTemplateSpecializationDecl *
SD = dyn_cast<ClassTemplateSpecializationDecl>(D)) {
return SD->getTemplateInstantiationPattern();
const auto *Template = SD->getTemplateInstantiationPattern();
if (Template)
return Template;
// Fallback to primary template if no instantiation is available yet (e.g.
// the type doesn't need to be complete).
return SD->getSpecializedTemplate()->getTemplatedDecl();
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
return FD->getTemplateInstantiationPattern();
} else if (auto *VD = dyn_cast<VarDecl>(D)) {

View File

@ -86,3 +86,37 @@ void canonicalizeInstaniationReferences(TemplateClass<int, float> &object) {
(void)TT::NestedType::Enum::EnumCase;
// CHECK: [[@LINE-1]]:31 | enumerator/C | EnumCase | c:@ST>2#T#T@TemplateClass@S@NestedType@E@Enum@EnumCase |
}
namespace index_specialization {
template <typename T>
class Foo {};
// if there are no explicit template specializations provided, report the
// primary templates.
Foo<int> *t1; // incomplete instantiation.
// CHECK: [[@LINE-1]]:1 | class(Gen)/C++ | Foo | c:@N@index_specialization@ST>1#T@Foo | <no-cgname> | Ref,RelCont | rel: 1
Foo<double> t2;
// CHECK: [[@LINE-1]]:1 | class(Gen)/C++ | Foo | c:@N@index_specialization@ST>1#T@Foo | <no-cgname> | Ref,RelCont | rel: 1
// explicit instantiations.
template class Foo<float>;
Foo<float> t3;
// CHECK: [[@LINE-1]]:1 | class(Gen)/C++ | Foo | c:@N@index_specialization@ST>1#T@Foo | <no-cgname> | Ref,RelCont | rel: 1
template <typename T>
class Bar {};
// explicit template specialization definition!
template <>class Bar<int> {};
// report the explicit template specialization if it exists.
Bar<int> *b1;
// CHECK: [[@LINE-1]]:1 | class(Gen,TS)/C++ | Bar | c:@N@index_specialization@S@Bar>#I | <no-cgname> | Ref,RelCont | rel: 1
// explicit template declaration, not a definition!
template <> class Bar <float>;
Bar<float> *b2;
// CHECK: [[@LINE-1]]:1 | class(Gen,TS)/C++ | Bar | c:@N@index_specialization@S@Bar>#f | <no-cgname> | Ref,RelCont | rel: 1
} // namespace index_specialization

View File

@ -321,7 +321,7 @@ template<>
void functionSp<SpecializationDecl<Cls>, Record::C>() {
// CHECK: [[@LINE-1]]:6 | function(Gen,TS)/C++ | functionSp | c:@F@functionSp<#$@S@SpecializationDecl>#$@S@Cls#VI2># | __Z10functionSpI18SpecializationDeclI3ClsELi2EEvv | Def,RelSpecialization | rel: 1
// CHECK: RelSpecialization | functionSp | c:@FT@>2#T#NIfunctionSp#v#
// CHECK: [[@LINE-3]]:17 | class(Gen,TS)/C++ | SpecializationDecl | c:@S@SpecializationDecl>#$@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
// CHECK: [[@LINE-3]]:17 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | <no-cgname> | Ref,RelCont | rel: 1
// CHECK: [[@LINE-4]]:36 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref,RelCont | rel: 1
// CHECK: [[@LINE-5]]:50 | static-property/C++ | C | c:@S@Record@C | __ZN6Record1CE | Ref,RelCont | rel: 1
// CHECK: [[@LINE-6]]:42 | struct/C++ | Record | c:@S@Record | <no-cgname> | Ref,RelCont | rel: 1
@ -332,7 +332,7 @@ class ClassWithCorrectSpecialization { };
template<>
class ClassWithCorrectSpecialization<SpecializationDecl<Cls>, Record::C> { };
// CHECK: [[@LINE-1]]:38 | class(Gen,TS)/C++ | SpecializationDecl | c:@S@SpecializationDecl>#$@S@Cls | <no-cgname> | Ref | rel: 0
// CHECK: [[@LINE-1]]:38 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | <no-cgname> | Ref | rel: 0
// CHECK: [[@LINE-2]]:57 | class/C++ | Cls | c:@S@Cls | <no-cgname> | Ref | rel: 0
// CHECK: [[@LINE-3]]:71 | static-property/C++ | C | c:@S@Record@C | __ZN6Record1CE | Ref,Read | rel: 0
// CHECK: [[@LINE-4]]:63 | struct/C++ | Record | c:@S@Record | <no-cgname> | Ref | rel: 0
@ -505,7 +505,7 @@ struct Guided { T t; };
// CHECK-NEXT: [[@LINE-2]]:19 | field/C++ | t | c:@ST>1#T@Guided@FI@t | <no-cgname> | Def,RelChild | rel: 1
// CHECK-NEXT: RelChild | Guided | c:@ST>1#T@Guided
Guided(double) -> Guided<float>;
// CHECK: [[@LINE-1]]:19 | struct(Gen,TS)/C++ | Guided | c:@S@Guided>#f | <no-cgname> | Ref | rel: 0
// CHECK: [[@LINE-1]]:19 | struct(Gen)/C++ | Guided | c:@ST>1#T@Guided | <no-cgname> | Ref | rel: 0
// CHECK-NEXT: [[@LINE-2]]:1 | struct(Gen)/C++ | Guided | c:@ST>1#T@Guided | <no-cgname> | Ref | rel: 0
auto guided = Guided{1.0};
// CHECK: [[@LINE-1]]:6 | variable/C | guided | c:@guided | _guided | Def | rel: 0