Index: test/Index/keep-going.cpp =================================================================== --- test/Index/keep-going.cpp +++ test/Index/keep-going.cpp @@ -19,10 +19,10 @@ // CHECK: FieldDecl=a:4:13 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] // CHECK: TypeRef=T:3:16 [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] // CHECK: ClassDecl=B:6:7 (Definition) [type=B] [typekind=Record] [isPOD=0] -// CHECK: C++ base class specifier=A:4:7 [access=public isVirtual=false] [type=A] [typekind=Unexposed] [canonicaltype=A] [canonicaltypekind=Record] [templateargs/1= [type=int] [typekind=Int]] [isPOD=0] [nbFields=1] +// CHECK: C++ base class specifier=A:4:7 [access=public isVirtual=false] [type=A] [typekind=Unexposed] [templateargs/1= [type=int] [typekind=Int]] [canonicaltype=A] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=int] [typekind=Int]] [isPOD=0] [nbFields=1] // CHECK: TemplateRef=A:4:7 [type=] [typekind=Invalid] [isPOD=0] // CHECK: ClassDecl=C:10:7 (Definition) [type=C] [typekind=Record] [isPOD=0] -// CHECK: C++ base class specifier=A:4:7 [access=public isVirtual=false] [type=A] [typekind=Unexposed] [canonicaltype=A] [canonicaltypekind=Record] [templateargs/1= [type=float] [typekind=Float]] [isPOD=0] [nbFields=1] +// CHECK: C++ base class specifier=A:4:7 [access=public isVirtual=false] [type=A] [typekind=Unexposed] [templateargs/1= [type=float] [typekind=Float]] [canonicaltype=A] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=float] [typekind=Float]] [isPOD=0] [nbFields=1] // CHECK: TemplateRef=A:4:7 [type=] [typekind=Invalid] [isPOD=0] // CHECK-DIAG: keep-going.cpp:1:10: error: 'missing1.h' file not found Index: test/Index/print-type.cpp =================================================================== --- test/Index/print-type.cpp +++ test/Index/print-type.cpp @@ -61,6 +61,15 @@ struct TypeAliasUser { TypeAlias foo; }; +template +struct Specialization {}; + +template<> +struct Specialization; + +Specialization& > templRefParam; +auto autoTemplRefParam = templRefParam; + // RUN: c-index-test -test-print-type %s -std=c++14 | FileCheck %s // CHECK: Namespace=outer:1:11 (Definition) [type=] [typekind=Invalid] [isPOD=0] // CHECK: ClassTemplate=Foo:4:8 (Definition) [type=] [typekind=Invalid] [isPOD=0] @@ -100,11 +109,11 @@ // CHECK: TypedefDecl=OtherType:25:18 (Definition) [type=OtherType] [typekind=Typedef] [canonicaltype=double] [canonicaltypekind=Double] [isPOD=1] // CHECK: TypedefDecl=ArrayType:26:15 (Definition) [type=ArrayType] [typekind=Typedef] [canonicaltype=int [5]] [canonicaltypekind=ConstantArray] [isPOD=1] // CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] -// CHECK: FieldDecl=baz:27:20 (Definition) [type=Baz] [typekind=Unexposed] [canonicaltype=outer::Baz] [canonicaltypekind=Record] [templateargs/3= [type=int] [typekind=Int]] [isPOD=1] +// CHECK: FieldDecl=baz:27:20 (Definition) [type=Baz] [typekind=Unexposed] [templateargs/3= [type=int] [typekind=Int]] [canonicaltype=outer::Baz] [canonicaltypekind=Record] [canonicaltemplateargs/3= [type=int] [typekind=Int]] [isPOD=1] // CHECK: TemplateRef=Baz:9:8 [type=] [typekind=Invalid] [isPOD=0] // CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] // CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0] -// CHECK: FieldDecl=qux:28:29 (Definition) [type=Qux >] [typekind=Unexposed] [canonicaltype=outer::Qux >] [canonicaltypekind=Record] [templateargs/3= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=Foo] [typekind=Unexposed]] [isPOD=1] +// CHECK: FieldDecl=qux:28:29 (Definition) [type=Qux >] [typekind=Unexposed] [templateargs/3= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=Foo] [typekind=Unexposed]] [canonicaltype=outer::Qux >] [canonicaltypekind=Record] [canonicaltemplateargs/3= [type=int] [typekind=Int] [type=char *] [typekind=Pointer] [type=outer::Foo] [typekind=Record]] [isPOD=1] // CHECK: TemplateRef=Qux:12:8 [type=] [typekind=Invalid] [isPOD=0] // CHECK: TemplateRef=Foo:4:8 [type=] [typekind=Invalid] [isPOD=0] // CHECK: FunctionTemplate=tbar:35:3 [type=T (int)] [typekind=FunctionProto] [canonicaltype=type-parameter-0-0 (int)] [canonicaltypekind=FunctionProto] [resulttype=T] [resulttypekind=Unexposed] [isPOD=0] @@ -155,5 +164,14 @@ // CHECK: IntegerLiteral= [type=int] [typekind=Int] [isPOD=1] // CHECK: TypeAliasTemplateDecl=TypeAlias:60:1 (Definition) [type=] [typekind=Invalid] [isPOD=0] // CHECK: TemplateTypeParameter=T:59:20 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] -// CHECK: FieldDecl=foo:62:39 (Definition) [type=TypeAlias] [typekind=Unexposed] [canonicaltype=outer::Qux] [canonicaltypekind=Record] [templateargs/1= [type=int] [typekind=Int]] [isPOD=1] +// CHECK: FieldDecl=foo:62:39 (Definition) [type=TypeAlias] [typekind=Unexposed] [templateargs/1= [type=int] [typekind=Int]] [canonicaltype=outer::Qux] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=int] [typekind=Int]] [isPOD=1] // CHECK: TemplateRef=TypeAlias:60:1 [type=] [typekind=Invalid] [isPOD=0] +// CHECK: ClassTemplate=Specialization:65:8 (Definition) [type=] [typekind=Invalid] [isPOD=0] +// CHECK: TemplateTypeParameter=T:64:19 (Definition) [type=T] [typekind=Unexposed] [canonicaltype=type-parameter-0-0] [canonicaltypekind=Unexposed] [isPOD=0] +// CHECK: StructDecl=Specialization:68:8 [Specialization of Specialization:65:8] [type=Specialization] [typekind=Record] [templateargs/1= [type=int] [typekind=Int]] [isPOD=0] +// CHECK: VarDecl=templRefParam:70:40 (Definition) [type=Specialization &>] [typekind=Unexposed] [templateargs/1= [type=Specialization &] [typekind=LValueReference]] [canonicaltype=Specialization &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization &] [typekind=LValueReference]] [isPOD=1] +// CHECK: TemplateRef=Specialization:65:8 [type=] [typekind=Invalid] [isPOD=0] +// CHECK: CallExpr=Specialization:65:8 [type=Specialization &>] [typekind=Unexposed] [templateargs/1= [type=Specialization &] [typekind=LValueReference]] [canonicaltype=Specialization &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization &] [typekind=LValueReference]] [isPOD=1] +// CHECK: VarDecl=autoTemplRefParam:71:6 (Definition) [type=Specialization &>] [typekind=Auto] [templateargs/1= [type=Specialization &] [typekind=LValueReference]] [canonicaltype=Specialization &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization &] [typekind=LValueReference]] [isPOD=1] +// CHECK: UnexposedExpr=templRefParam:70:40 [type=const Specialization &>] [typekind=Unexposed] const [templateargs/1= [type=Specialization &] [typekind=LValueReference]] [canonicaltype=const Specialization &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization &] [typekind=LValueReference]] [isPOD=1] +// CHECK: DeclRefExpr=templRefParam:70:40 [type=Specialization &>] [typekind=Unexposed] [templateargs/1= [type=Specialization &] [typekind=LValueReference]] [canonicaltype=Specialization &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization &] [typekind=LValueReference]] [isPOD=1] Index: tools/c-index-test/c-index-test.c =================================================================== --- tools/c-index-test/c-index-test.c +++ tools/c-index-test/c-index-test.c @@ -1316,6 +1316,25 @@ return CXVisit_Continue; } +static void PrintTypeTemplateArgs(CXType T, const char *Format) { + int NumTArgs = clang_Type_getNumTemplateArguments(T); + if (NumTArgs != -1 && NumTArgs != 0) { + int i; + CXType TArg; + printf(Format, NumTArgs); + for (i = 0; i < NumTArgs; ++i) { + TArg = clang_Type_getTemplateArgumentAsType(T, i); + if (TArg.kind != CXType_Invalid) { + PrintTypeAndTypeKind(TArg, " [type=%s] [typekind=%s]"); + } + } + /* Ensure that the returned type is invalid when indexing off-by-one. */ + TArg = clang_Type_getTemplateArgumentAsType(T, i); + assert(TArg.kind == CXType_Invalid); + printf("]"); + } +} + static enum CXChildVisitResult PrintType(CXCursor cursor, CXCursor p, CXClientData d) { if (!clang_isInvalid(clang_getCursorKind(cursor))) { @@ -1333,11 +1352,14 @@ printf(" lvalue-ref-qualifier"); if (RQ == CXRefQualifier_RValue) printf(" rvalue-ref-qualifier"); + /* Print the template argument types if they exist. */ + PrintTypeTemplateArgs(T, " [templateargs/%d="); /* Print the canonical type if it is different. */ { CXType CT = clang_getCanonicalType(T); if (!clang_equalTypes(T, CT)) { PrintTypeAndTypeKind(CT, " [canonicaltype=%s] [canonicaltypekind=%s]"); + PrintTypeTemplateArgs(CT, " [canonicaltemplateargs/%d="); } } /* Print the return type if it exists. */ @@ -1362,21 +1384,6 @@ printf("]"); } } - /* Print the template argument types if they exist. */ - { - int NumTArgs = clang_Type_getNumTemplateArguments(T); - if (NumTArgs != -1 && NumTArgs != 0) { - int i; - printf(" [templateargs/%d=", NumTArgs); - for (i = 0; i < NumTArgs; ++i) { - CXType TArg = clang_Type_getTemplateArgumentAsType(T, i); - if (TArg.kind != CXType_Invalid) { - PrintTypeAndTypeKind(TArg, " [type=%s] [typekind=%s]"); - } - } - printf("]"); - } - } /* Print if this is a non-POD type. */ printf(" [isPOD=%d]", clang_isPODType(T)); /* Print the pointee type. */ Index: tools/libclang/CXType.cpp =================================================================== --- tools/libclang/CXType.cpp +++ tools/libclang/CXType.cpp @@ -920,33 +920,76 @@ return cxstring::createDup(encoding); } +static Optional> +GetTemplateArguments(QualType Type) { + assert(!Type.isNull()); + if (const auto *Specialization = Type->getAs()) + return Specialization->template_arguments(); + + if (const auto *RecordDecl = Type->getAsCXXRecordDecl()) { + const auto *TemplateDecl = + dyn_cast(RecordDecl); + if (TemplateDecl) + return TemplateDecl->getTemplateArgs().asArray(); + } + + return None; +} + +static unsigned GetTemplateArgumentArraySize(ArrayRef TA) { + unsigned size = TA.size(); + for (const auto &Arg : TA) + if (Arg.getKind() == TemplateArgument::Pack) + size += Arg.pack_size() - 1; + return size; +} + int clang_Type_getNumTemplateArguments(CXType CT) { QualType T = GetQualType(CT); if (T.isNull()) return -1; - const TemplateSpecializationType *Specialization = - T->getAs(); - if (!Specialization) + + auto TA = GetTemplateArguments(T); + if (!TA) return -1; - return Specialization->template_arguments().size(); + + return GetTemplateArgumentArraySize(TA.getValue()); } -CXType clang_Type_getTemplateArgumentAsType(CXType CT, unsigned i) { +static Optional TemplateArgumentToQualType(const TemplateArgument &A) { + if (A.getKind() == TemplateArgument::Type) + return A.getAsType(); + return None; +} + +static Optional +FindTemplateArgumentTypeAt(ArrayRef TA, unsigned index) { + unsigned current = 0; + for (const auto &A : TA) { + if (A.getKind() == TemplateArgument::Pack) { + if (index < current + A.pack_size()) + return TemplateArgumentToQualType(A.getPackAsArray()[index - current]); + current += A.pack_size(); + continue; + } + if (current == index) + return TemplateArgumentToQualType(A); + current++; + } + return None; +} + +CXType clang_Type_getTemplateArgumentAsType(CXType CT, unsigned index) { QualType T = GetQualType(CT); if (T.isNull()) return MakeCXType(QualType(), GetTU(CT)); - const TemplateSpecializationType *Specialization = - T->getAs(); - if (!Specialization) - return MakeCXType(QualType(), GetTU(CT)); - auto TA = Specialization->template_arguments(); - if (TA.size() <= i) + auto TA = GetTemplateArguments(T); + if (!TA) return MakeCXType(QualType(), GetTU(CT)); - const TemplateArgument &A = TA[i]; - if (A.getKind() != TemplateArgument::Type) - return MakeCXType(QualType(), GetTU(CT)); - return MakeCXType(A.getAsType(), GetTU(CT)); + + Optional QT = FindTemplateArgumentTypeAt(TA.getValue(), index); + return MakeCXType(QT.getValueOr(QualType()), GetTU(CT)); } unsigned clang_Type_visitFields(CXType PT,