From d7933e6f29b4c93df8263df21ff5e2e1dd0cecb8 Mon Sep 17 00:00:00 2001 From: Argyrios Kyrtzidis Date: Wed, 17 Aug 2011 00:43:03 +0000 Subject: [PATCH] [python] Add support for CXType to python bindings. Patch by Anders Waldenborg! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@137797 91177308-0d34-0410-b5e6-96231b3b80d8 --- bindings/python/clang/cindex.py | 208 +++++++++++++++++++- bindings/python/tests/cindex/test_cursor.py | 4 +- 2 files changed, 210 insertions(+), 2 deletions(-) diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index 8cadcaa7ad..2110170162 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -634,6 +634,14 @@ class Cursor(Structure): """ return Cursor_extent(self) + @property + def type(self): + """ + Retrieve the type (if any) of of the entity pointed at by the + cursor. + """ + return Cursor_type(self) + def get_children(self): """Return an iterator for accessing the children of this cursor.""" @@ -656,6 +664,165 @@ class Cursor(Structure): return None return res + +### Type Kinds ### + +class TypeKind(object): + """ + Describes the kind of type. + """ + + # The unique kind objects, indexed by id. + _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] + + @staticmethod + def from_id(id): + if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None: + raise ValueError,'Unknown cursor kind' + return TypeKind._kinds[id] + + def __repr__(self): + return 'TypeKind.%s' % (self.name,) + + + +TypeKind.INVALID = TypeKind(0) +TypeKind.UNEXPOSED = TypeKind(1) +TypeKind.VOID = TypeKind(2) +TypeKind.BOOL = TypeKind(3) +TypeKind.CHAR_U = TypeKind(4) +TypeKind.UCHAR = TypeKind(5) +TypeKind.CHAR16 = TypeKind(6) +TypeKind.CHAR32 = TypeKind(7) +TypeKind.USHORT = TypeKind(8) +TypeKind.UINT = TypeKind(9) +TypeKind.ULONG = TypeKind(10) +TypeKind.ULONGLONG = TypeKind(11) +TypeKind.UINT128 = TypeKind(12) +TypeKind.CHAR_S = TypeKind(13) +TypeKind.SCHAR = TypeKind(14) +TypeKind.WCHAR = TypeKind(15) +TypeKind.SHORT = TypeKind(16) +TypeKind.INT = TypeKind(17) +TypeKind.LONG = TypeKind(18) +TypeKind.LONGLONG = TypeKind(19) +TypeKind.INT128 = TypeKind(20) +TypeKind.FLOAT = TypeKind(21) +TypeKind.DOUBLE = TypeKind(22) +TypeKind.LONGDOUBLE = TypeKind(23) +TypeKind.NULLPTR = TypeKind(24) +TypeKind.OVERLOAD = TypeKind(25) +TypeKind.DEPENDENT = TypeKind(26) +TypeKind.OBJCID = TypeKind(27) +TypeKind.OBJCCLASS = TypeKind(28) +TypeKind.OBJCSEL = TypeKind(29) +TypeKind.COMPLEX = TypeKind(100) +TypeKind.POINTER = TypeKind(101) +TypeKind.BLOCKPOINTER = TypeKind(102) +TypeKind.LVALUEREFERENCE = TypeKind(103) +TypeKind.RVALUEREFERENCE = TypeKind(104) +TypeKind.RECORD = TypeKind(105) +TypeKind.ENUM = TypeKind(106) +TypeKind.TYPEDEF = TypeKind(107) +TypeKind.OBJCINTERFACE = TypeKind(108) +TypeKind.OBJCOBJECTPOINTER = TypeKind(109) +TypeKind.FUNCTIONNOPROTO = TypeKind(110) +TypeKind.FUNCTIONPROTO = TypeKind(111) + + +class Type(Structure): + """ + The type of an element in the abstract syntax tree. + """ + _fields_ = [("_kind_id", c_int), ("data", c_void_p * 2)] + + @property + def kind(self): + """Return the kind of this type.""" + return TypeKind.from_id(self._kind_id) + + @staticmethod + def from_result(res, fn, args): + assert isinstance(res, Type) + return res + + def get_canonical(self): + """ + Return the canonical type for a Type. + + Clang's type system explicitly models typedefs and all the + ways a specific type can be represented. The canonical type + is the underlying type with all the "sugar" removed. For + example, if 'T' is a typedef for 'int', the canonical type for + 'T' would be 'int'. + """ + return Type_get_canonical(self) + + def is_const_qualified(self): + """ + Determine whether a Type has the "const" qualifier set, + without looking through typedefs that may have added "const" + at a different level. + """ + return Type_is_const_qualified(self) + + def is_volatile_qualified(self): + """ + Determine whether a Type has the "volatile" qualifier set, + without looking through typedefs that may have added + "volatile" at a different level. + """ + return Type_is_volatile_qualified(self) + + def is_restrict_qualified(self): + """ + Determine whether a Type has the "restrict" qualifier set, + without looking through typedefs that may have added + "restrict" at a different level. + """ + return Type_is_restrict_qualified(self) + + def get_pointee(self): + """ + For pointer types, returns the type of the pointee. + """ + return Type_get_pointee(self) + + def get_declaration(self): + """ + Return the cursor for the declaration of the given type. + """ + return Type_get_declaration(self) + + def get_result(self): + """ + Retrieve the result type associated with a function type. + """ + return Type_get_result(self) + ## CIndex Objects ## # CIndex objects (derived from ClangObject) are essentially lightweight @@ -1210,11 +1377,50 @@ Cursor_ref.argtypes = [Cursor] Cursor_ref.restype = Cursor Cursor_ref.errcheck = Cursor.from_result +Cursor_type = lib.clang_getCursorType +Cursor_type.argtypes = [Cursor] +Cursor_type.restype = Type +Cursor_type.errcheck = Type.from_result + Cursor_visit_callback = CFUNCTYPE(c_int, Cursor, Cursor, py_object) Cursor_visit = lib.clang_visitChildren Cursor_visit.argtypes = [Cursor, Cursor_visit_callback, py_object] Cursor_visit.restype = c_uint +# Type Functions +Type_get_canonical = lib.clang_getCanonicalType +Type_get_canonical.argtypes = [Type] +Type_get_canonical.restype = Type +Type_get_canonical.errcheck = Type.from_result + +Type_is_const_qualified = lib.clang_isConstQualifiedType +Type_is_const_qualified.argtypes = [Type] +Type_is_const_qualified.restype = bool + +Type_is_volatile_qualified = lib.clang_isVolatileQualifiedType +Type_is_volatile_qualified.argtypes = [Type] +Type_is_volatile_qualified.restype = bool + +Type_is_restrict_qualified = lib.clang_isRestrictQualifiedType +Type_is_restrict_qualified.argtypes = [Type] +Type_is_restrict_qualified.restype = bool + +Type_get_pointee = lib.clang_getPointeeType +Type_get_pointee.argtypes = [Type] +Type_get_pointee.restype = Type +Type_get_pointee.errcheck = Type.from_result + +Type_get_declaration = lib.clang_getTypeDeclaration +Type_get_declaration.argtypes = [Type] +Type_get_declaration.restype = Cursor +Type_get_declaration.errcheck = Cursor.from_result + +Type_get_result = lib.clang_getResultType +Type_get_result.argtypes = [Type] +Type_get_result.restype = Type +Type_get_result.errcheck = Type.from_result + + # Index Functions Index_create = lib.clang_createIndex Index_create.argtypes = [c_int, c_int] @@ -1313,6 +1519,6 @@ _clang_getCompletionPriority.restype = c_int ### -__all__ = ['Index', 'TranslationUnit', 'Cursor', 'CursorKind', +__all__ = ['Index', 'TranslationUnit', 'Cursor', 'CursorKind', 'Type', 'TypeKind', 'Diagnostic', 'FixIt', 'CodeCompletionResults', 'SourceRange', 'SourceLocation', 'File'] diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py index a653ba7bf2..04e4838945 100644 --- a/bindings/python/tests/cindex/test_cursor.py +++ b/bindings/python/tests/cindex/test_cursor.py @@ -1,4 +1,4 @@ -from clang.cindex import Index, CursorKind +from clang.cindex import Index, CursorKind, TypeKind kInput = """\ // FIXME: Find nicer way to drop builtins and other cruft. @@ -47,8 +47,10 @@ def test_get_children(): assert len(s0_nodes) == 2 assert s0_nodes[0].kind == CursorKind.FIELD_DECL assert s0_nodes[0].spelling == 'a' + assert s0_nodes[0].type.kind == TypeKind.INT assert s0_nodes[1].kind == CursorKind.FIELD_DECL assert s0_nodes[1].spelling == 'b' + assert s0_nodes[1].type.kind == TypeKind.INT assert tu_nodes[1].kind == CursorKind.STRUCT_DECL assert tu_nodes[1].spelling == 's1'