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.

llvm-svn: 112604
This commit is contained in:
Douglas Gregor 2010-08-31 17:01:39 +00:00
parent 04dc957260
commit 713602bb09
7 changed files with 263 additions and 8 deletions

View File

@ -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 */

View File

@ -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; }

View File

@ -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

View File

@ -0,0 +1,22 @@
// Test is line- and column-sensitive. See run lines below.
template<typename T, T Value, template<typename U, U ValU> class X>
void f(X<T, Value> 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]

View File

@ -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");

View File

@ -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<Decl>(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<TemplateTypeParmType>()) {
Out << 't' << TTP->getDepth() << '.' << TTP->getIndex();
return;
}
if (const TemplateSpecializationType *Spec
= T->getAs<TemplateSpecializationType>()) {
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<TemplateTypeParmDecl>(*P)) {
Out << 'T';
continue;
}
if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) {
Out << 'N';
VisitType(NTTP->getType());
continue;
}
TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*P);
Out << 't';
VisitTemplateParameterList(TTP->getTemplateParameters());
}
}
void USRGenerator::VisitTemplateName(TemplateName Name) {
if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
if (TemplateTemplateParmDecl *TTP
= dyn_cast<TemplateTemplateParmDecl>(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.
//===----------------------------------------------------------------------===//

View File

@ -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<TagDecl>(D)) {
switch (TD->getTagKind()) {