forked from OSchip/llvm-project
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:
parent
04dc957260
commit
713602bb09
|
@ -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 */
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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()) {
|
||||
|
|
Loading…
Reference in New Issue