From a0b1e640c5872ea7bd3f297b772f6842aabe5d4d Mon Sep 17 00:00:00 2001 From: Eli Bendersky Date: Fri, 10 Oct 2014 20:01:05 +0000 Subject: [PATCH] Add libclang capabilities to retriete template arguments from specializations. Includes Python bindings. Reviewed in http://reviews.llvm.org/D5621 Patch by Rob Springer git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@219529 91177308-0d34-0410-b5e6-96231b3b80d8 --- bindings/python/clang/cindex.py | 204 ++++++++++---------- bindings/python/tests/cindex/test_cursor.py | 44 +++++ include/clang-c/Index.h | 118 +++++++++++ test/Index/index-templates.cpp | 12 +- test/Index/preamble_macro_template.cpp | 2 +- tools/c-index-test/c-index-test.c | 31 ++- tools/libclang/CXCursor.cpp | 134 +++++++++++++ tools/libclang/libclang.exports | 5 + 8 files changed, 440 insertions(+), 110 deletions(-) diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index 68f7e48fc6..8bcf9c3bda 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -496,24 +496,28 @@ class TokenKind(object): setattr(TokenKind, name, kind) ### Cursor Kinds ### - -class CursorKind(object): - """ - A CursorKind describes the kind of entity that a cursor points to. +class BaseEnumeration(object): """ + Common base class for named enumerations held in sync with Index.h values. - # The unique kind objects, indexed by id. + Subclasses must define their own _kinds and _name_map members, as: _kinds = [] _name_map = None + These values hold the per-subclass instances and value-to-name mappings, + respectively. + + """ def __init__(self, value): - if value >= len(CursorKind._kinds): - CursorKind._kinds += [None] * (value - len(CursorKind._kinds) + 1) - if CursorKind._kinds[value] is not None: - raise ValueError,'CursorKind already loaded' + if value >= len(self.__class__._kinds): + self.__class__._kinds += [None] * (value - len(self.__class__._kinds) + 1) + if self.__class__._kinds[value] is not None: + raise ValueError,'{0} value {1} already loaded'.format( + str(self.__class__), value) self.value = value - CursorKind._kinds[value] = self - CursorKind._name_map = None + self.__class__._kinds[value] = self + self.__class__._name_map = None + def from_param(self): return self.value @@ -523,16 +527,29 @@ class CursorKind(object): """Get the enumeration name of this cursor kind.""" if self._name_map is None: self._name_map = {} - for key,value in CursorKind.__dict__.items(): - if isinstance(value,CursorKind): + for key, value in self.__class__.__dict__.items(): + if isinstance(value, self.__class__): self._name_map[value] = key return self._name_map[self] - @staticmethod - def from_id(id): - if id >= len(CursorKind._kinds) or CursorKind._kinds[id] is None: - raise ValueError,'Unknown cursor kind %d' % id - return CursorKind._kinds[id] + @classmethod + def from_id(cls, id): + if id >= len(cls._kinds) or cls._kinds[id] is None: + raise ValueError,'Unknown template argument kind %d' % id + return cls._kinds[id] + + def __repr__(self): + return '%s.%s' % (self.__class__, self.name,) + + +class CursorKind(BaseEnumeration): + """ + A CursorKind describes the kind of entity that a cursor points to. + """ + + # The required BaseEnumeration declarations. + _kinds = [] + _name_map = None @staticmethod def get_all_kinds(): @@ -578,11 +595,6 @@ class CursorKind(object): def __repr__(self): return 'CursorKind.%s' % (self.name,) -# FIXME: Is there a nicer way to expose this enumeration? We could potentially -# represent the nested structure, or even build a class hierarchy. The main -# things we want for sure are (a) simple external access to kinds, (b) a place -# to hang a description and name, (c) easy to keep in sync with Index.h. - ### # Declaration Kinds @@ -1101,6 +1113,24 @@ CursorKind.INCLUSION_DIRECTIVE = CursorKind(503) # A module import declaration. CursorKind.MODULE_IMPORT_DECL = CursorKind(600) + +### Template Argument Kinds ### +class TemplateArgumentKind(BaseEnumeration): + """ + A TemplateArgumentKind describes the kind of entity that a template argument + represents. + """ + + # The required BaseEnumeration declarations. + _kinds = [] + _name_map = None + +TemplateArgumentKind.NULL = TemplateArgumentKind(0) +TemplateArgumentKind.TYPE = TemplateArgumentKind(1) +TemplateArgumentKind.DECLARATION = TemplateArgumentKind(2) +TemplateArgumentKind.NULLPTR = TemplateArgumentKind(3) +TemplateArgumentKind.INTEGRAL = TemplateArgumentKind(4) + ### Cursors ### class Cursor(Structure): @@ -1378,6 +1408,27 @@ class Cursor(Structure): for i in range(0, num_args): yield conf.lib.clang_Cursor_getArgument(self, i) + def get_num_template_arguments(self): + """Returns the number of template args associated with this cursor.""" + return conf.lib.clang_Cursor_getNumTemplateArguments(self) + + def get_template_argument_kind(self, num): + """Returns the TemplateArgumentKind for the indicated template + argument.""" + return conf.lib.clang_Cursor_getTemplateArgumentKind(self, num) + + def get_template_argument_type(self, num): + """Returns the CXType for the indicated template argument.""" + return conf.lib.clang_Cursor_getTemplateArgumentType(self, num) + + def get_template_argument_value(self, num): + """Returns the value of the indicated arg as a signed 64b integer.""" + return conf.lib.clang_Cursor_getTemplateArgumentValue(self, num) + + def get_template_argument_unsigned_value(self, num): + """Returns the value of the indicated arg as an unsigned 64b integer.""" + return conf.lib.clang_Cursor_getTemplateArgumentUnsignedValue(self, num) + def get_children(self): """Return an iterator for accessing the children of this cursor.""" @@ -1461,7 +1512,7 @@ class Cursor(Structure): ### C++ access specifiers ### -class AccessSpecifier(object): +class AccessSpecifier(BaseEnumeration): """ Describes the access of a C++ class member """ @@ -1470,34 +1521,9 @@ class AccessSpecifier(object): _kinds = [] _name_map = None - def __init__(self, value): - if value >= len(AccessSpecifier._kinds): - AccessSpecifier._kinds += [None] * (value - len(AccessSpecifier._kinds) + 1) - if AccessSpecifier._kinds[value] is not None: - raise ValueError,'AccessSpecifier already loaded' - self.value = value - AccessSpecifier._kinds[value] = self - AccessSpecifier._name_map = None - def from_param(self): return self.value - @property - def name(self): - """Get the enumeration name of this access specifier.""" - if self._name_map is None: - self._name_map = {} - for key,value in AccessSpecifier.__dict__.items(): - if isinstance(value,AccessSpecifier): - self._name_map[value] = key - return self._name_map[self] - - @staticmethod - def from_id(id): - if id >= len(AccessSpecifier._kinds) or not AccessSpecifier._kinds[id]: - raise ValueError,'Unknown access specifier %d' % id - return AccessSpecifier._kinds[id] - def __repr__(self): return 'AccessSpecifier.%s' % (self.name,) @@ -1509,7 +1535,7 @@ AccessSpecifier.NONE = AccessSpecifier(4) ### Type Kinds ### -class TypeKind(object): +class TypeKind(BaseEnumeration): """ Describes the kind of type. """ @@ -1518,39 +1544,11 @@ class TypeKind(object): _kinds = [] _name_map = None - def __init__(self, value): - if value >= len(TypeKind._kinds): - TypeKind._kinds += [None] * (value - len(TypeKind._kinds) + 1) - if TypeKind._kinds[value] is not None: - raise ValueError,'TypeKind already loaded' - self.value = value - TypeKind._kinds[value] = self - TypeKind._name_map = None - - def from_param(self): - return self.value - - @property - def name(self): - """Get the enumeration name of this cursor kind.""" - if self._name_map is None: - self._name_map = {} - for key,value in TypeKind.__dict__.items(): - if isinstance(value,TypeKind): - self._name_map[value] = key - return self._name_map[self] - @property def spelling(self): """Retrieve the spelling of this TypeKind.""" return conf.lib.clang_getTypeKindSpelling(self.value) - @staticmethod - def from_id(id): - if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None: - raise ValueError,'Unknown type kind %d' % id - return TypeKind._kinds[id] - def __repr__(self): return 'TypeKind.%s' % (self.name,) @@ -1603,43 +1601,16 @@ TypeKind.VARIABLEARRAY = TypeKind(115) TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116) TypeKind.MEMBERPOINTER = TypeKind(117) -class RefQualifierKind(object): +class RefQualifierKind(BaseEnumeration): """Describes a specific ref-qualifier of a type.""" # The unique kind objects, indexed by id. _kinds = [] _name_map = None - def __init__(self, value): - if value >= len(RefQualifierKind._kinds): - num_kinds = value - len(RefQualifierKind._kinds) + 1 - RefQualifierKind._kinds += [None] * num_kinds - if RefQualifierKind._kinds[value] is not None: - raise ValueError, 'RefQualifierKind already loaded' - self.value = value - RefQualifierKind._kinds[value] = self - RefQualifierKind._name_map = None - def from_param(self): return self.value - @property - def name(self): - """Get the enumeration name of this kind.""" - if self._name_map is None: - self._name_map = {} - for key, value in RefQualifierKind.__dict__.items(): - if isinstance(value, RefQualifierKind): - self._name_map[value] = key - return self._name_map[self] - - @staticmethod - def from_id(id): - if (id >= len(RefQualifierKind._kinds) or - RefQualifierKind._kinds[id] is None): - raise ValueError, 'Unknown type kind %d' % id - return RefQualifierKind._kinds[id] - def __repr__(self): return 'RefQualifierKind.%s' % (self.name,) @@ -3314,6 +3285,27 @@ functionList = [ Cursor, Cursor.from_result), + ("clang_Cursor_getNumTemplateArguments", + [Cursor], + c_int), + + ("clang_Cursor_getTemplateArgumentKind", + [Cursor, c_uint], + TemplateArgumentKind.from_id), + + ("clang_Cursor_getTemplateArgumentType", + [Cursor, c_uint], + Type, + Type.from_result), + + ("clang_Cursor_getTemplateArgumentValue", + [Cursor, c_uint], + c_longlong), + + ("clang_Cursor_getTemplateArgumentUnsignedValue", + [Cursor, c_uint], + c_ulonglong), + ("clang_Cursor_isBitField", [Cursor], bool), diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py index d4ee9daa96..a5224aafab 100644 --- a/bindings/python/tests/cindex/test_cursor.py +++ b/bindings/python/tests/cindex/test_cursor.py @@ -1,6 +1,8 @@ +import ctypes import gc from clang.cindex import CursorKind +from clang.cindex import TemplateArgumentKind from clang.cindex import TranslationUnit from clang.cindex import TypeKind from .util import get_cursor @@ -244,6 +246,48 @@ def test_get_arguments(): assert arguments[0].spelling == "i" assert arguments[1].spelling == "j" +kTemplateArgTest = """\ + template + void foo(); + + template<> + void foo<-7, float, true>(); + """ + +def test_get_num_template_arguments(): + tu = get_tu(kTemplateArgTest, lang='cpp') + foos = get_cursors(tu, 'foo') + + assert foos[1].get_num_template_arguments() == 3 + +def test_get_template_argument_kind(): + tu = get_tu(kTemplateArgTest, lang='cpp') + foos = get_cursors(tu, 'foo') + + assert foos[1].get_template_argument_kind(0) == TemplateArgumentKind.INTEGRAL + assert foos[1].get_template_argument_kind(1) == TemplateArgumentKind.TYPE + assert foos[1].get_template_argument_kind(2) == TemplateArgumentKind.INTEGRAL + +def test_get_template_argument_type(): + tu = get_tu(kTemplateArgTest, lang='cpp') + foos = get_cursors(tu, 'foo') + + assert foos[1].get_template_argument_type(1).kind == TypeKind.FLOAT + +def test_get_template_argument_value(): + tu = get_tu(kTemplateArgTest, lang='cpp') + foos = get_cursors(tu, 'foo') + + assert foos[1].get_template_argument_value(0) == -7 + assert foos[1].get_template_argument_value(2) == True + +def test_get_template_argument_unsigned_value(): + tu = get_tu(kTemplateArgTest, lang='cpp') + foos = get_cursors(tu, 'foo') + + assert foos[1].get_template_argument_unsigned_value(0) == 2 ** 32 - 7 + assert foos[1].get_template_argument_unsigned_value(2) == True + def test_referenced(): tu = get_tu('void foo(); void bar() { foo(); }') foo = get_cursor(tu, 'foo') diff --git a/include/clang-c/Index.h b/include/clang-c/Index.h index 911f7cc966..3e64718edb 100644 --- a/include/clang-c/Index.h +++ b/include/clang-c/Index.h @@ -2942,6 +2942,124 @@ CINDEX_LINKAGE int clang_Cursor_getNumArguments(CXCursor C); */ CINDEX_LINKAGE CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i); +/** + * \brief Describes the kind of a template argument. + * + * See the definition of llvm::clang::TemplateArgument::ArgKind for full + * element descriptions. + */ +enum CXTemplateArgumentKind { + CXTemplateArgumentKind_Null, + CXTemplateArgumentKind_Type, + CXTemplateArgumentKind_Declaration, + CXTemplateArgumentKind_NullPtr, + CXTemplateArgumentKind_Integral, + CXTemplateArgumentKind_Template, + CXTemplateArgumentKind_TemplateExpansion, + CXTemplateArgumentKind_Expression, + CXTemplateArgumentKind_Pack, + /* Indicates an error case, preventing the kind from being deduced. */ + CXTemplateArgumentKind_Invalid +}; + +/** + *\brief Returns the number of template args of a function decl representing a + * template specialization. + * + * If the argument cursor cannot be converted into a template function + * declaration, -1 is returned. + * + * For example, for the following declaration and specialization: + * template + * void foo() { ... } + * + * template <> + * void foo(); + * + * The value 3 would be returned from this call. + */ +CINDEX_LINKAGE int clang_Cursor_getNumTemplateArguments(CXCursor C); + +/** + * \brief Retrieve the kind of the I'th template argument of the CXCursor C. + * + * If the argument CXCursor does not represent a FunctionDecl, an invalid + * template argument kind is returned. + * + * For example, for the following declaration and specialization: + * template + * void foo() { ... } + * + * template <> + * void foo(); + * + * For I = 0, 1, and 2, Type, Integral, and Integral will be returned, + * respectively. + */ +CINDEX_LINKAGE enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind( + CXCursor C, unsigned I); + +/** + * \brief Retrieve a CXType representing the type of a TemplateArgument of a + * function decl representing a template specialization. + * + * If the argument CXCursor does not represent a FunctionDecl whose I'th + * template argument has a kind of CXTemplateArgKind_Integral, an invalid type + * is returned. + * + * For example, for the following declaration and specialization: + * template + * void foo() { ... } + * + * template <> + * void foo(); + * + * If called with I = 0, "float", will be returned. + * Invalid types will be returned for I == 1 or 2. + */ +CINDEX_LINKAGE CXType clang_Cursor_getTemplateArgumentType(CXCursor C, + unsigned I); + +/** + * \brief Retrieve the value of an Integral TemplateArgument (of a function + * decl representing a template specialization) as a signed long long. + * + * It is undefined to call this function on a CXCursor that does not represent a + * FunctionDecl or whose I'th template argument is not an integral value. + * + * For example, for the following declaration and specialization: + * template + * void foo() { ... } + * + * template <> + * void foo(); + * + * If called with I = 1 or 2, -7 or true will be returned, respectively. + * For I == 0, this function's behavior is undefined. + */ +CINDEX_LINKAGE long long clang_Cursor_getTemplateArgumentValue(CXCursor C, + unsigned I); + +/** + * \brief Retrieve the value of an Integral TemplateArgument (of a function + * decl representing a template specialization) as an unsigned long long. + * + * It is undefined to call this function on a CXCursor that does not represent a + * FunctionDecl or whose I'th template argument is not an integral value. + * + * For example, for the following declaration and specialization: + * template + * void foo() { ... } + * + * template <> + * void foo(); + * + * If called with I = 1 or 2, 2147483649 or true will be returned, respectively. + * For I == 0, this function's behavior is undefined. + */ +CINDEX_LINKAGE unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue( + CXCursor C, unsigned I); + /** * \brief Determine whether two CXTypes represent the same type. * diff --git a/test/Index/index-templates.cpp b/test/Index/index-templates.cpp index 5fcb652cea..1552235fff 100644 --- a/test/Index/index-templates.cpp +++ b/test/Index/index-templates.cpp @@ -100,6 +100,16 @@ template class Pair; template struct SuperPair : Pair, Pair { }; +enum FxnTmplEnum { + FxnTmplEnum_A, FxnTmplEnum_B, FxnTmplEnum_C, +}; +template +void foo(T Value) {} + +static const int FxnTmpl_Var = 7; +template <> +void foo(float Value); + // RUN: c-index-test -test-load-source all -fno-delayed-template-parsing %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:10 - 3:20] @@ -178,7 +188,7 @@ struct SuperPair : Pair, Pair { }; // CHECK-LOAD: index-templates.cpp:100:31: TemplateTypeParameter=U:100:31 (Definition) Extent=[100:22 - 100:32] // CHECK-LOAD: index-templates.cpp:101:20: C++ base class specifier=Pair:98:16 [access=public isVirtual=false] Extent=[101:20 - 101:34] // CHECK-LOAD: index-templates.cpp:101:36: C++ base class specifier=Pair:76:8 [access=public isVirtual=false] Extent=[101:36 - 101:46] - +// CHECK-LOAD: index-templates.cpp:111:6: FunctionDecl=foo:111:6 [Specialization of foo:107:6] [Template arg 0: kind: 1, type: float] [Template arg 1: kind: 4, intval: 9] [Template arg 2: kind: 4, intval: 1] [Template arg 3: kind: 4, intval: 14] Extent=[110:1 - 111:64] // RUN: c-index-test -test-load-source-usrs all -fno-delayed-template-parsing %s | FileCheck -check-prefix=CHECK-USRS %s // CHECK-USRS: index-templates.cpp c:@FT@>3#T#Nt0.0#t>2#T#Nt1.0f#>t0.22S0_# Extent=[3:1 - 4:22] diff --git a/test/Index/preamble_macro_template.cpp b/test/Index/preamble_macro_template.cpp index 20f16b5df2..0771caba23 100644 --- a/test/Index/preamble_macro_template.cpp +++ b/test/Index/preamble_macro_template.cpp @@ -4,7 +4,7 @@ int main() { } // RUN: c-index-test -write-pch %t.pch -fno-delayed-template-parsing -x c++-header %S/Inputs/preamble_macro_template.h // RUN: env CINDEXTEST_EDITING=1 c-index-test -test-load-source-reparse 5 local -fno-delayed-template-parsing -I %S/Inputs -include %t %s 2>&1 | tee %t.check.txt | FileCheck %s -// CHECK: preamble_macro_template.h:4:6: FunctionDecl=foo:4:6 (Definition) [Specialization of foo:4:6] Extent=[4:1 - 6:2] +// CHECK: preamble_macro_template.h:4:6: FunctionDecl=foo:4:6 (Definition) [Specialization of foo:4:6] [Template arg 0: kind: 1, type: int] Extent=[4:1 - 6:2] // CHECK: preamble_macro_template.h:4:13: ParmDecl=p:4:13 (Definition) Extent=[4:10 - 4:14] // CHECK: preamble_macro_template.h:4:16: CompoundStmt= Extent=[4:16 - 6:2] // CHECK: preamble_macro_template.h:5:3: CStyleCastExpr= Extent=[5:3 - 5:27] diff --git a/tools/c-index-test/c-index-test.c b/tools/c-index-test/c-index-test.c index d7c28ddb1e..56e4101399 100644 --- a/tools/c-index-test/c-index-test.c +++ b/tools/c-index-test/c-index-test.c @@ -796,15 +796,42 @@ static void PrintCursor(CXCursor Cursor, const char *CommentSchemaFile) { printf(" [access=%s isVirtual=%s]", accessStr, isVirtual ? "true" : "false"); } - + SpecializationOf = clang_getSpecializedCursorTemplate(Cursor); if (!clang_equalCursors(SpecializationOf, clang_getNullCursor())) { CXSourceLocation Loc = clang_getCursorLocation(SpecializationOf); CXString Name = clang_getCursorSpelling(SpecializationOf); clang_getSpellingLocation(Loc, 0, &line, &column, 0); - printf(" [Specialization of %s:%d:%d]", + printf(" [Specialization of %s:%d:%d]", clang_getCString(Name), line, column); clang_disposeString(Name); + + if (Cursor.kind == CXCursor_FunctionDecl) { + /* Collect the template parameter kinds from the base template. */ + unsigned NumTemplateArgs = clang_Cursor_getNumTemplateArguments(Cursor); + unsigned I; + for (I = 0; I < NumTemplateArgs; I++) { + enum CXTemplateArgumentKind TAK = + clang_Cursor_getTemplateArgumentKind(Cursor, I); + switch(TAK) { + case CXTemplateArgumentKind_Type: + { + CXType T = clang_Cursor_getTemplateArgumentType(Cursor, I); + CXString S = clang_getTypeSpelling(T); + printf(" [Template arg %d: kind: %d, type: %s]", + I, TAK, clang_getCString(S)); + clang_disposeString(S); + } + break; + case CXTemplateArgumentKind_Integral: + printf(" [Template arg %d: kind: %d, intval: %lld]", + I, TAK, clang_Cursor_getTemplateArgumentValue(Cursor, I)); + break; + default: + printf(" [Template arg %d: kind: %d]\n", I, TAK); + } + } + } } clang_getOverriddenCursors(Cursor, &overridden, &num_overridden); diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 782f05e1e8..6590b158e5 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -1074,6 +1074,140 @@ CXCursor clang_Cursor_getArgument(CXCursor C, unsigned i) { return clang_getNullCursor(); } +int clang_Cursor_getNumTemplateArguments(CXCursor C) { + if (clang_getCursorKind(C) != CXCursor_FunctionDecl) { + return -1; + } + + const FunctionDecl *FD = llvm::dyn_cast_or_null( + getCursorDecl(C)); + if (!FD) { + return -1; + } + + const FunctionTemplateSpecializationInfo* SpecInfo = + FD->getTemplateSpecializationInfo(); + if (!SpecInfo) { + return -1; + } + + return SpecInfo->TemplateArguments->size(); +} + +enum CXGetTemplateArgumentStatus { + /** \brief The operation completed successfully */ + CXGetTemplateArgumentStatus_Success = 0, + + /** \brief The specified cursor did not represent a FunctionDecl. */ + CXGetTemplateArgumentStatus_CursorNotFunctionDecl = -1, + + /** \brief The specified cursor was not castable to a FunctionDecl. */ + CXGetTemplateArgumentStatus_BadFunctionDeclCast = -2, + + /** \brief A NULL FunctionTemplateSpecializationInfo was retrieved. */ + CXGetTemplateArgumentStatus_NullTemplSpecInfo = -3, + + /** \brief An invalid (OOB) argument index was specified */ + CXGetTemplateArgumentStatus_InvalidIndex = -4 +}; + +static int clang_Cursor_getTemplateArgument( + CXCursor C, unsigned I, TemplateArgument *TA) { + if (clang_getCursorKind(C) != CXCursor_FunctionDecl) { + return CXGetTemplateArgumentStatus_CursorNotFunctionDecl; + } + + const FunctionDecl *FD = llvm::dyn_cast_or_null( + getCursorDecl(C)); + if (!FD) { + return CXGetTemplateArgumentStatus_BadFunctionDeclCast; + } + + const FunctionTemplateSpecializationInfo* SpecInfo = + FD->getTemplateSpecializationInfo(); + if (!SpecInfo) { + return CXGetTemplateArgumentStatus_NullTemplSpecInfo; + } + + if (I >= SpecInfo->TemplateArguments->size()) { + return CXGetTemplateArgumentStatus_InvalidIndex; + } + + *TA = SpecInfo->TemplateArguments->get(I); + return 0; +} + +enum CXTemplateArgumentKind clang_Cursor_getTemplateArgumentKind(CXCursor C, + unsigned I) { + TemplateArgument TA; + if (clang_Cursor_getTemplateArgument(C, I, &TA)) { + return CXTemplateArgumentKind_Invalid; + } + + switch (TA.getKind()) { + case TemplateArgument::Null: return CXTemplateArgumentKind_Null; + case TemplateArgument::Type: return CXTemplateArgumentKind_Type; + case TemplateArgument::Declaration: + return CXTemplateArgumentKind_Declaration; + case TemplateArgument::NullPtr: return CXTemplateArgumentKind_NullPtr; + case TemplateArgument::Integral: return CXTemplateArgumentKind_Integral; + case TemplateArgument::Template: return CXTemplateArgumentKind_Template; + case TemplateArgument::TemplateExpansion: + return CXTemplateArgumentKind_TemplateExpansion; + case TemplateArgument::Expression: return CXTemplateArgumentKind_Expression; + case TemplateArgument::Pack: return CXTemplateArgumentKind_Pack; + } + + return CXTemplateArgumentKind_Invalid; +} + +CXType clang_Cursor_getTemplateArgumentType(CXCursor C, unsigned I) { + TemplateArgument TA; + if (clang_Cursor_getTemplateArgument(C, I, &TA) != + CXGetTemplateArgumentStatus_Success) { + return cxtype::MakeCXType(QualType(), getCursorTU(C)); + } + + if (TA.getKind() != TemplateArgument::Type) { + return cxtype::MakeCXType(QualType(), getCursorTU(C)); + } + + return cxtype::MakeCXType(TA.getAsType(), getCursorTU(C)); +} + +long long clang_Cursor_getTemplateArgumentValue(CXCursor C, unsigned I) { + TemplateArgument TA; + if (clang_Cursor_getTemplateArgument(C, I, &TA) != + CXGetTemplateArgumentStatus_Success) { + assert(0 && "Unable to retrieve TemplateArgument"); + return 0; + } + + if (TA.getKind() != TemplateArgument::Integral) { + assert(0 && "Passed template argument is not Integral"); + return 0; + } + + return TA.getAsIntegral().getSExtValue(); +} + +unsigned long long clang_Cursor_getTemplateArgumentUnsignedValue(CXCursor C, + unsigned I) { + TemplateArgument TA; + if (clang_Cursor_getTemplateArgument(C, I, &TA) != + CXGetTemplateArgumentStatus_Success) { + assert(0 && "Unable to retrieve TemplateArgument"); + return 0; + } + + if (TA.getKind() != TemplateArgument::Integral) { + assert(0 && "Passed template argument is not Integral"); + return 0; + } + + return TA.getAsIntegral().getZExtValue(); +} + } // end: extern "C" //===----------------------------------------------------------------------===// diff --git a/tools/libclang/libclang.exports b/tools/libclang/libclang.exports index 5a029f7e4f..d7701ad975 100644 --- a/tools/libclang/libclang.exports +++ b/tools/libclang/libclang.exports @@ -7,6 +7,11 @@ clang_CXXMethod_isPureVirtual clang_CXXMethod_isStatic clang_CXXMethod_isVirtual clang_Cursor_getArgument +clang_Cursor_getNumTemplateArguments +clang_Cursor_getTemplateArgumentKind +clang_Cursor_getTemplateArgumentType +clang_Cursor_getTemplateArgumentValue +clang_Cursor_getTemplateArgumentUnsignedValue clang_Cursor_getBriefCommentText clang_Cursor_getCommentRange clang_Cursor_getMangling -- 2.40.0