From bb9e92bad55f65f2de58bf29548bdfd3dea2d7ab Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 19 Feb 2020 12:27:12 +0100 Subject: [PATCH] [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 --- clang-tools-extra/clangd/unittests/XRefsTests.cpp | 6 ++++ clang/lib/Index/IndexingContext.cpp | 11 ++++++- .../test/Index/Core/index-instantiated-source.cpp | 34 ++++++++++++++++++++++ clang/test/Index/Core/index-source.cpp | 6 ++-- 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/clang-tools-extra/clangd/unittests/XRefsTests.cpp b/clang-tools-extra/clangd/unittests/XRefsTests.cpp index b75c218..31c9650 100644 --- a/clang-tools-extra/clangd/unittests/XRefsTests.cpp +++ b/clang-tools-extra/clangd/unittests/XRefsTests.cpp @@ -948,6 +948,12 @@ TEST(FindReferences, WithinAST) { int [[v^ar]] = 0; void foo(int s = [[var]]); )cpp", + + R"cpp( + template + class [[Fo^o]] {}; + void func([[Foo]]); + )cpp", }; for (const char *Test : Tests) { Annotations T(Test); diff --git a/clang/lib/Index/IndexingContext.cpp b/clang/lib/Index/IndexingContext.cpp index a7c37e8..784a600 100644 --- a/clang/lib/Index/IndexingContext.cpp +++ b/clang/lib/Index/IndexingContext.cpp @@ -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(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(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(D)) { return FD->getTemplateInstantiationPattern(); } else if (auto *VD = dyn_cast(D)) { diff --git a/clang/test/Index/Core/index-instantiated-source.cpp b/clang/test/Index/Core/index-instantiated-source.cpp index 7a810fb..2a67a3a 100644 --- a/clang/test/Index/Core/index-instantiated-source.cpp +++ b/clang/test/Index/Core/index-instantiated-source.cpp @@ -86,3 +86,37 @@ void canonicalizeInstaniationReferences(TemplateClass &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 +class Foo {}; + +// if there are no explicit template specializations provided, report the +// primary templates. +Foo *t1; // incomplete instantiation. +// CHECK: [[@LINE-1]]:1 | class(Gen)/C++ | Foo | c:@N@index_specialization@ST>1#T@Foo | | Ref,RelCont | rel: 1 + +Foo t2; +// CHECK: [[@LINE-1]]:1 | class(Gen)/C++ | Foo | c:@N@index_specialization@ST>1#T@Foo | | Ref,RelCont | rel: 1 + +// explicit instantiations. +template class Foo; +Foo t3; +// CHECK: [[@LINE-1]]:1 | class(Gen)/C++ | Foo | c:@N@index_specialization@ST>1#T@Foo | | Ref,RelCont | rel: 1 + + +template +class Bar {}; + +// explicit template specialization definition! +template <>class Bar {}; +// report the explicit template specialization if it exists. +Bar *b1; +// CHECK: [[@LINE-1]]:1 | class(Gen,TS)/C++ | Bar | c:@N@index_specialization@S@Bar>#I | | Ref,RelCont | rel: 1 + +// explicit template declaration, not a definition! +template <> class Bar ; +Bar *b2; +// CHECK: [[@LINE-1]]:1 | class(Gen,TS)/C++ | Bar | c:@N@index_specialization@S@Bar>#f | | Ref,RelCont | rel: 1 + +} // namespace index_specialization diff --git a/clang/test/Index/Core/index-source.cpp b/clang/test/Index/Core/index-source.cpp index f159b1c..371265b 100644 --- a/clang/test/Index/Core/index-source.cpp +++ b/clang/test/Index/Core/index-source.cpp @@ -321,7 +321,7 @@ template<> void functionSp, 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 | | Ref,RelCont | rel: 1 +// CHECK: [[@LINE-3]]:17 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | | Ref,RelCont | rel: 1 // CHECK: [[@LINE-4]]:36 | class/C++ | Cls | c:@S@Cls | | 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 | | Ref,RelCont | rel: 1 @@ -332,7 +332,7 @@ class ClassWithCorrectSpecialization { }; template<> class ClassWithCorrectSpecialization, Record::C> { }; -// CHECK: [[@LINE-1]]:38 | class(Gen,TS)/C++ | SpecializationDecl | c:@S@SpecializationDecl>#$@S@Cls | | Ref | rel: 0 +// CHECK: [[@LINE-1]]:38 | class(Gen)/C++ | SpecializationDecl | c:@ST>1#T@SpecializationDecl | | Ref | rel: 0 // CHECK: [[@LINE-2]]:57 | class/C++ | Cls | c:@S@Cls | | 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 | | 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 | | Def,RelChild | rel: 1 // CHECK-NEXT: RelChild | Guided | c:@ST>1#T@Guided Guided(double) -> Guided; -// CHECK: [[@LINE-1]]:19 | struct(Gen,TS)/C++ | Guided | c:@S@Guided>#f | | Ref | rel: 0 +// CHECK: [[@LINE-1]]:19 | struct(Gen)/C++ | Guided | c:@ST>1#T@Guided | | Ref | rel: 0 // CHECK-NEXT: [[@LINE-2]]:1 | struct(Gen)/C++ | Guided | c:@ST>1#T@Guided | | Ref | rel: 0 auto guided = Guided{1.0}; // CHECK: [[@LINE-1]]:6 | variable/C | guided | c:@guided | _guided | Def | rel: 0 -- 2.7.4