From: Douglas Gregor Date: Tue, 31 Aug 2010 17:01:39 +0000 (+0000) Subject: Implement basic support for indexing function templates in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fe72e9ceeae6cc8669cd8bb722425300190638ea;p=clang Implement basic support for indexing function templates in libclang. This includes: - Cursor kind for function templates, with visitation logic - Cursor kinds for template parameters, with visitation logic - Visitation logic for template specialization types, qualified type locations - USR generation for function templates, template specialization types, template parameter types. Also happens to fix PR7804, which I tripped across while testing. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@112604 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index e3d10f3fcd..cc00f1835b 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -982,8 +982,16 @@ enum CXCursorKind { CXCursor_Destructor = 25, /** \brief A C++ conversion function. */ CXCursor_ConversionFunction = 26, + /** \brief A C++ template type parameter. */ + CXCursor_TemplateTypeParameter = 27, + /** \brief A C++ non-type template parameter. */ + CXCursor_NonTypeTemplateParameter = 28, + /** \brief A C++ template template parameter. */ + CXCursor_TemplateTemplateParameter = 29, + /** \brief A C++ function template. */ + CXCursor_FunctionTemplate = 30, CXCursor_FirstDecl = CXCursor_UnexposedDecl, - CXCursor_LastDecl = CXCursor_ConversionFunction, + CXCursor_LastDecl = CXCursor_FunctionTemplate, /* References */ CXCursor_FirstRef = 40, /* Decl references */ diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 3861cd9a91..76d474a8cd 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -1138,6 +1138,13 @@ public: DefaultArgumentWasInherited = false; } + SourceRange getSourceRange() const { + SourceLocation End = getLocation(); + if (hasDefaultArgument() && !defaultArgumentWasInherited()) + End = getDefaultArgument().getSourceRange().getEnd(); + return SourceRange(getTemplateParameters()->getTemplateLoc(), End); + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classof(const TemplateTemplateParmDecl *D) { return true; } diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index e06d38d179..3c6ecaa53e 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -662,7 +662,8 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, // Construct the parameter object. TemplateTemplateParmDecl *Param = TemplateTemplateParmDecl::Create(Context, Context.getTranslationUnitDecl(), - TmpLoc, Depth, Position, Name, + NameLoc.isInvalid()? TmpLoc : NameLoc, + Depth, Position, Name, (TemplateParameterList*)Params); // If the template template parameter has a name, then link the identifier diff --git a/test/Index/index-templates.cpp b/test/Index/index-templates.cpp new file mode 100644 index 0000000000..90e0c352bc --- /dev/null +++ b/test/Index/index-templates.cpp @@ -0,0 +1,22 @@ +// Test is line- and column-sensitive. See run lines below. + +template class X> +void f(X x); + +// RUN: c-index-test -test-load-source all %s | FileCheck -check-prefix=CHECK-LOAD %s +// CHECK-LOAD: index-templates.cpp:4:6: FunctionTemplate=f:4:6 Extent=[3:1 - 4:22] +// CHECK-LOAD: index-templates.cpp:3:19: TemplateTypeParameter=T:3:19 (Definition) Extent=[3:19 - 3:20] +// CHECK-LOAD: index-templates.cpp:3:24: NonTypeTemplateParameter=Value:3:24 (Definition) Extent=[3:22 - 3:29] +// FIXME: Need the template type parameter here +// CHECK-LOAD: index-templates.cpp:3:66: TemplateTemplateParameter=X:3:66 (Definition) Extent=[3:31 - 3:67] +// CHECK-LOAD: index-templates.cpp:4:20: ParmDecl=x:4:20 (Definition) Extent=[4:8 - 4:21] +// FIXME: Need the template declaration here. +// FIXME: Need the template type parameter here +// CHECK-LOAD: index-templates.cpp:4:13: DeclRefExpr=Value:3:24 Extent=[4:13 - 4:18] + +// RUN: c-index-test -test-load-source-usrs all %s | FileCheck -check-prefix=CHECK-USRS %s +// CHECK-USRS: index-templates.cpp c:@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22t0.0# Extent=[3:1 - 4:22] +// CHECK-USRS: index-templates.cpp c:index-templates.cpp@79 Extent=[3:19 - 3:20] +// CHECK-USRS: index-templates.cpp c:index-templates.cpp@82 Extent=[3:22 - 3:29] +// CHECK-USRS: index-templates.cpp c:index-templates.cpp@91 Extent=[3:31 - 3:67] +// CHECK-USRS: index-templates.cpp c:index-templates.cpp@136@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22t0.0#@x Extent=[4:8 - 4:21] diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp index fc665926f2..6629f5c0ac 100644 --- a/tools/libclang/CIndex.cpp +++ b/tools/libclang/CIndex.cpp @@ -290,11 +290,13 @@ public: bool VisitTranslationUnitDecl(TranslationUnitDecl *D); bool VisitTypedefDecl(TypedefDecl *D); bool VisitTagDecl(TagDecl *D); + bool VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); bool VisitEnumConstantDecl(EnumConstantDecl *D); bool VisitDeclaratorDecl(DeclaratorDecl *DD); bool VisitFunctionDecl(FunctionDecl *ND); bool VisitFieldDecl(FieldDecl *D); bool VisitVarDecl(VarDecl *); + bool VisitFunctionTemplateDecl(FunctionTemplateDecl *D); bool VisitObjCMethodDecl(ObjCMethodDecl *ND); bool VisitObjCContainerDecl(ObjCContainerDecl *D); bool VisitObjCCategoryDecl(ObjCCategoryDecl *ND); @@ -311,17 +313,21 @@ public: bool VisitObjCClassDecl(ObjCClassDecl *D); bool VisitLinkageSpecDecl(LinkageSpecDecl *D); bool VisitNamespaceDecl(NamespaceDecl *D); - + // Name visitor bool VisitDeclarationNameInfo(DeclarationNameInfo Name); + // Template visitors + bool VisitTemplateParameters(const TemplateParameterList *Params); + bool VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL); + // Type visitors bool VisitQualifiedTypeLoc(QualifiedTypeLoc TL); bool VisitBuiltinTypeLoc(BuiltinTypeLoc TL); bool VisitTypedefTypeLoc(TypedefTypeLoc TL); bool VisitUnresolvedUsingTypeLoc(UnresolvedUsingTypeLoc TL); bool VisitTagTypeLoc(TagTypeLoc TL); - // FIXME: TemplateTypeParmTypeLoc doesn't provide any location information + bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL); bool VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL); bool VisitObjCObjectTypeLoc(ObjCObjectTypeLoc TL); bool VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc TL); @@ -332,7 +338,7 @@ public: bool VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc TL); bool VisitFunctionTypeLoc(FunctionTypeLoc TL, bool SkipResultType = false); bool VisitArrayTypeLoc(ArrayTypeLoc TL); - // FIXME: Implement for TemplateSpecializationTypeLoc + bool VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc TL); // FIXME: Implement visitors here when the unimplemented TypeLocs get // implemented bool VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL); @@ -593,6 +599,11 @@ bool CursorVisitor::VisitTagDecl(TagDecl *D) { return VisitDeclContext(D); } +bool CursorVisitor::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + // FIXME: Visit default argument + return false; +} + bool CursorVisitor::VisitEnumConstantDecl(EnumConstantDecl *D) { if (Expr *Init = D->getInitExpr()) return Visit(MakeCXCursor(Init, StmtParent, TU)); @@ -663,6 +674,15 @@ bool CursorVisitor::VisitVarDecl(VarDecl *D) { return false; } +bool CursorVisitor::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + // FIXME: Visit the "outer" template parameter lists on the FunctionDecl + // before visiting these template parameters. + if (VisitTemplateParameters(D->getTemplateParameters())) + return true; + + return VisitFunctionDecl(D->getTemplatedDecl()); +} + bool CursorVisitor::VisitObjCMethodDecl(ObjCMethodDecl *ND) { if (TypeSourceInfo *TSInfo = ND->getResultTypeSourceInfo()) if (Visit(TSInfo->getTypeLoc())) @@ -839,6 +859,54 @@ bool CursorVisitor::VisitDeclarationNameInfo(DeclarationNameInfo Name) { return false; } +bool CursorVisitor::VisitTemplateParameters( + const TemplateParameterList *Params) { + if (!Params) + return false; + + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + if (Visit(MakeCXCursor(*P, TU))) + return true; + } + + return false; +} + +bool CursorVisitor::VisitTemplateArgumentLoc(const TemplateArgumentLoc &TAL) { + switch (TAL.getArgument().getKind()) { + case TemplateArgument::Null: + case TemplateArgument::Integral: + return false; + + case TemplateArgument::Pack: + // FIXME: Implement when variadic templates come along. + return false; + + case TemplateArgument::Type: + if (TypeSourceInfo *TSInfo = TAL.getTypeSourceInfo()) + return Visit(TSInfo->getTypeLoc()); + return false; + + case TemplateArgument::Declaration: + if (Expr *E = TAL.getSourceDeclExpression()) + return Visit(MakeCXCursor(E, StmtParent, TU)); + return false; + + case TemplateArgument::Expression: + if (Expr *E = TAL.getSourceExpression()) + return Visit(MakeCXCursor(E, StmtParent, TU)); + return false; + + case TemplateArgument::Template: + // FIXME: Visit template name. + return false; + } + + return false; +} + bool CursorVisitor::VisitLinkageSpecDecl(LinkageSpecDecl *D) { return VisitDeclContext(D); } @@ -918,6 +986,13 @@ bool CursorVisitor::VisitTagTypeLoc(TagTypeLoc TL) { return Visit(MakeCursorTypeRef(TL.getDecl(), TL.getNameLoc(), TU)); } +bool CursorVisitor::VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { + // FIXME: We can't visit the template template parameter, but there's + // no context information with which we can match up the depth/index in the + // type to the appropriate + return false; +} + bool CursorVisitor::VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc TL) { if (Visit(MakeCursorObjCClassRef(TL.getIFaceDecl(), TL.getNameLoc(), TU))) return true; @@ -985,6 +1060,18 @@ bool CursorVisitor::VisitArrayTypeLoc(ArrayTypeLoc TL) { return false; } +bool CursorVisitor::VisitTemplateSpecializationTypeLoc( + TemplateSpecializationTypeLoc TL) { + // FIXME: Visit the template name. + + // Visit the template arguments. + for (unsigned I = 0, N = TL.getNumArgs(); I != N; ++I) + if (VisitTemplateArgumentLoc(TL.getArgLoc(I))) + return true; + + return false; +} + bool CursorVisitor::VisitTypeOfExprTypeLoc(TypeOfExprTypeLoc TL) { return Visit(MakeCXCursor(TL.getUnderlyingExpr(), StmtParent, TU)); } @@ -2037,6 +2124,14 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) { return createCXString("CXXDestructor"); case CXCursor_ConversionFunction: return createCXString("CXXConversion"); + case CXCursor_TemplateTypeParameter: + return createCXString("TemplateTypeParameter"); + case CXCursor_NonTypeTemplateParameter: + return createCXString("NonTypeTemplateParameter"); + case CXCursor_TemplateTemplateParameter: + return createCXString("TemplateTemplateParameter"); + case CXCursor_FunctionTemplate: + return createCXString("FunctionTemplate"); } llvm_unreachable("Unhandled CXCursorKind"); diff --git a/tools/libclang/CIndexUSRs.cpp b/tools/libclang/CIndexUSRs.cpp index 0227b2c037..6dfe9df4dd 100644 --- a/tools/libclang/CIndexUSRs.cpp +++ b/tools/libclang/CIndexUSRs.cpp @@ -13,6 +13,7 @@ #include "CIndexer.h" #include "CXCursor.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/DeclVisitor.h" #include "clang/Frontend/ASTUnit.h" #include "clang/Lex/PreprocessingRecord.h" @@ -64,6 +65,7 @@ public: void VisitFunctionDecl(FunctionDecl *D); void VisitNamedDecl(NamedDecl *D); void VisitNamespaceDecl(NamespaceDecl *D); + void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitObjCClassDecl(ObjCClassDecl *CD); void VisitObjCContainerDecl(ObjCContainerDecl *CD); void VisitObjCForwardProtocolDecl(ObjCForwardProtocolDecl *P); @@ -72,7 +74,10 @@ public: void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitTagDecl(TagDecl *D); void VisitTypedefDecl(TypedefDecl *D); + void VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); void VisitVarDecl(VarDecl *D); + void VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); + void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D) { IgnoreResults = true; return; @@ -104,7 +109,10 @@ public: void GenObjCProtocol(llvm::StringRef prot); void VisitType(QualType T); - + void VisitTemplateParameterList(const TemplateParameterList *Params); + void VisitTemplateName(TemplateName Name); + void VisitTemplateArgument(const TemplateArgument &Arg); + /// Emit a Decl's name using NamedDecl::printName() and return true if /// the decl had no name. bool EmitDeclName(const NamedDecl *D); @@ -155,7 +163,11 @@ void USRGenerator::VisitFunctionDecl(FunctionDecl *D) { return; VisitDeclContext(D->getDeclContext()); - Out << "@F@"; + if (FunctionTemplateDecl *FunTmpl = D->getDescribedFunctionTemplate()) { + Out << "@FT@"; + VisitTemplateParameterList(FunTmpl->getTemplateParameters()); + } else + Out << "@F@"; D->printName(Out); ASTContext &Ctx = AU->getASTContext(); @@ -215,6 +227,16 @@ void USRGenerator::VisitVarDecl(VarDecl *D) { Out << '@' << s; } +void USRGenerator::VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D) { + GenLoc(D); + return; +} + +void USRGenerator::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { + GenLoc(D); + return; +} + void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { if (D->isAnonymousNamespace()) { Out << "@aN"; @@ -226,6 +248,10 @@ void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) { Out << "@N@" << D->getName(); } +void USRGenerator::VisitFunctionTemplateDecl(FunctionTemplateDecl *D) { + VisitFunctionDecl(D->getTemplatedDecl()); +} + void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) { Decl *container = cast(D->getDeclContext()); @@ -366,6 +392,11 @@ void USRGenerator::VisitTypedefDecl(TypedefDecl *D) { Out << D->getName(); } +void USRGenerator::VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D) { + GenLoc(D); + return; +} + bool USRGenerator::GenLoc(const Decl *D) { if (generatedLoc) return IgnoreResults; @@ -515,13 +546,100 @@ void USRGenerator::VisitType(QualType T) { VisitTagDecl(TT->getDecl()); return; } - + if (const TemplateTypeParmType *TTP = T->getAs()) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + if (const TemplateSpecializationType *Spec + = T->getAs()) { + Out << '>'; + VisitTemplateName(Spec->getTemplateName()); + Out << Spec->getNumArgs(); + for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) + VisitTemplateArgument(Spec->getArg(I)); + return; + } + // Unhandled type. Out << ' '; break; } while (true); } +void USRGenerator::VisitTemplateParameterList( + const TemplateParameterList *Params) { + if (!Params) + return; + Out << '>' << Params->size(); + for (TemplateParameterList::const_iterator P = Params->begin(), + PEnd = Params->end(); + P != PEnd; ++P) { + Out << '#'; + if (isa(*P)) { + Out << 'T'; + continue; + } + + if (NonTypeTemplateParmDecl *NTTP = dyn_cast(*P)) { + Out << 'N'; + VisitType(NTTP->getType()); + continue; + } + + TemplateTemplateParmDecl *TTP = cast(*P); + Out << 't'; + VisitTemplateParameterList(TTP->getTemplateParameters()); + } +} + +void USRGenerator::VisitTemplateName(TemplateName Name) { + if (TemplateDecl *Template = Name.getAsTemplateDecl()) { + if (TemplateTemplateParmDecl *TTP + = dyn_cast(Template)) { + Out << 't' << TTP->getDepth() << '.' << TTP->getIndex(); + return; + } + + Visit(Template); + return; + } + + // FIXME: Visit dependent template names. +} + +void USRGenerator::VisitTemplateArgument(const TemplateArgument &Arg) { + switch (Arg.getKind()) { + case TemplateArgument::Null: + break; + + case TemplateArgument::Declaration: + Visit(Arg.getAsDecl()); + break; + + case TemplateArgument::Template: + VisitTemplateName(Arg.getAsTemplate()); + break; + + case TemplateArgument::Expression: + // FIXME: Visit expressions. + break; + + case TemplateArgument::Pack: + // FIXME: Variadic templates + break; + + case TemplateArgument::Type: + VisitType(Arg.getAsType()); + break; + + case TemplateArgument::Integral: + Out << 'V'; + VisitType(Arg.getIntegralType()); + Out << *Arg.getAsIntegral(); + break; + } +} + //===----------------------------------------------------------------------===// // General purpose USR generation methods. //===----------------------------------------------------------------------===// diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 029b3d237d..86cf83d75e 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -60,6 +60,10 @@ static CXCursorKind GetCursorKind(Decl *D) { case Decl::Typedef: return CXCursor_TypedefDecl; case Decl::Var: return CXCursor_VarDecl; case Decl::Namespace: return CXCursor_Namespace; + case Decl::TemplateTypeParm: return CXCursor_TemplateTypeParameter; + case Decl::NonTypeTemplateParm:return CXCursor_NonTypeTemplateParameter; + case Decl::TemplateTemplateParm:return CXCursor_TemplateTemplateParameter; + case Decl::FunctionTemplate: return CXCursor_FunctionTemplate; default: if (TagDecl *TD = dyn_cast(D)) { switch (TD->getTagKind()) {