forked from OSchip/llvm-project
Add libclang capabilities to retriete template arguments from specializations.
Includes Python bindings. Reviewed in http://reviews.llvm.org/D5621 Patch by Rob Springer llvm-svn: 219529
This commit is contained in:
parent
f42585fd96
commit
c27a0c490c
|
@ -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),
|
||||
|
|
|
@ -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 <int kInt, typename T, bool kBool>
|
||||
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')
|
||||
|
|
|
@ -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 <typename T, int kInt, bool kBool>
|
||||
* void foo() { ... }
|
||||
*
|
||||
* template <>
|
||||
* void foo<float, -7, true>();
|
||||
*
|
||||
* 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 <typename T, int kInt, bool kBool>
|
||||
* void foo() { ... }
|
||||
*
|
||||
* template <>
|
||||
* void foo<float, -7, true>();
|
||||
*
|
||||
* 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 <typename T, int kInt, bool kBool>
|
||||
* void foo() { ... }
|
||||
*
|
||||
* template <>
|
||||
* void foo<float, -7, true>();
|
||||
*
|
||||
* 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 <typename T, int kInt, bool kBool>
|
||||
* void foo() { ... }
|
||||
*
|
||||
* template <>
|
||||
* void foo<float, -7, true>();
|
||||
*
|
||||
* 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 <typename T, int kInt, bool kBool>
|
||||
* void foo() { ... }
|
||||
*
|
||||
* template <>
|
||||
* void foo<float, 2147483649, true>();
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
|
|
|
@ -100,6 +100,16 @@ template class Pair<int, int>;
|
|||
template<typename T, typename U>
|
||||
struct SuperPair : Pair<int, int>, Pair<T, U> { };
|
||||
|
||||
enum FxnTmplEnum {
|
||||
FxnTmplEnum_A, FxnTmplEnum_B, FxnTmplEnum_C,
|
||||
};
|
||||
template <typename T, int I, FxnTmplEnum, int E>
|
||||
void foo(T Value) {}
|
||||
|
||||
static const int FxnTmpl_Var = 7;
|
||||
template <>
|
||||
void foo<float, 9, FxnTmplEnum_B, FxnTmpl_Var + 7>(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<int, int>, Pair<T, U> { };
|
|||
// 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<int, int>:98:16 [access=public isVirtual=false] Extent=[101:20 - 101:34]
|
||||
// CHECK-LOAD: index-templates.cpp:101:36: C++ base class specifier=Pair<T, U>: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]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<clang::FunctionDecl>(
|
||||
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<clang::FunctionDecl>(
|
||||
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"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue