summaryrefslogtreecommitdiff
path: root/bindings/python
diff options
context:
space:
mode:
Diffstat (limited to 'bindings/python')
-rw-r--r--bindings/python/clang/cindex.py375
-rw-r--r--bindings/python/tests/cindex/test_cursor.py37
-rw-r--r--bindings/python/tests/cindex/test_cursor_kind.py9
-rw-r--r--bindings/python/tests/cindex/test_diagnostics.py39
-rw-r--r--bindings/python/tests/cindex/test_file.py9
-rw-r--r--bindings/python/tests/cindex/test_location.py100
-rw-r--r--bindings/python/tests/cindex/test_type.py294
-rw-r--r--bindings/python/tests/cindex/util.py65
8 files changed, 794 insertions, 134 deletions
diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py
index 7cc9ddaf76467..b4563eb0c6240 100644
--- a/bindings/python/clang/cindex.py
+++ b/bindings/python/clang/cindex.py
@@ -63,6 +63,7 @@ call is efficient.
# o implement additional SourceLocation, SourceRange, and File methods.
from ctypes import *
+import collections
def get_cindex_library():
# FIXME: It's probably not the case that the library is actually found in
@@ -111,10 +112,21 @@ class SourceLocation(Structure):
if self._data is None:
f, l, c, o = c_object_p(), c_uint(), c_uint(), c_uint()
SourceLocation_loc(self, byref(f), byref(l), byref(c), byref(o))
- f = File(f) if f else None
+ if f:
+ f = File(f)
+ else:
+ f = None
self._data = (f, int(l.value), int(c.value), int(o.value))
return self._data
+ @staticmethod
+ def from_position(tu, file, line, column):
+ """
+ Retrieve the source location associated with a given file/line/column in
+ a particular translation unit.
+ """
+ return SourceLocation_getLocation(tu, file, line, column)
+
@property
def file(self):
"""Get the file represented by this source location."""
@@ -135,9 +147,19 @@ class SourceLocation(Structure):
"""Get the file offset represented by this source location."""
return self._get_instantiation()[3]
+ def __eq__(self, other):
+ return SourceLocation_equalLocations(self, other)
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
def __repr__(self):
+ if self.file:
+ filename = self.file.name
+ else:
+ filename = None
return "<SourceLocation file %r, line %r, column %r>" % (
- self.file.name if self.file else None, self.line, self.column)
+ filename, self.line, self.column)
class SourceRange(Structure):
"""
@@ -171,6 +193,12 @@ class SourceRange(Structure):
"""
return SourceRange_end(self)
+ def __eq__(self, other):
+ return SourceRange_equalRanges(self, other)
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
def __repr__(self):
return "<SourceRange start %r, end %r>" % (self.start, self.end)
@@ -215,8 +243,8 @@ class Diagnostic(object):
return int(_clang_getDiagnosticNumRanges(self.diag))
def __getitem__(self, key):
- if (key >= len(self)):
- raise IndexError
+ if (key >= len(self)):
+ raise IndexError
return _clang_getDiagnosticRange(self.diag, key)
return RangeIterator(self)
@@ -240,6 +268,29 @@ class Diagnostic(object):
return FixItIterator(self)
+ @property
+ def category_number(self):
+ """The category number for this diagnostic."""
+ return _clang_getDiagnosticCategory(self)
+
+ @property
+ def category_name(self):
+ """The string name of the category for this diagnostic."""
+ return _clang_getDiagnosticCategoryName(self.category_number)
+
+ @property
+ def option(self):
+ """The command-line option that enables this diagnostic."""
+ return _clang_getDiagnosticOption(self, None)
+
+ @property
+ def disable_option(self):
+ """The command-line option that disables this diagnostic."""
+ disable = _CXString()
+ _clang_getDiagnosticOption(self, byref(disable))
+
+ return _CXString_getCString(disable)
+
def __repr__(self):
return "<Diagnostic severity %r, location %r, spelling %r>" % (
self.severity, self.location, self.spelling)
@@ -329,6 +380,18 @@ class CursorKind(object):
"""Test if this is an invalid kind."""
return CursorKind_is_inv(self)
+ def is_translation_unit(self):
+ """Test if this is a translation unit kind."""
+ return CursorKind_is_translation_unit(self)
+
+ def is_preprocessing(self):
+ """Test if this is a preprocessing kind."""
+ return CursorKind_is_preprocessing(self)
+
+ def is_unexposed(self):
+ """Test if this is an unexposed kind."""
+ return CursorKind_is_unexposed(self)
+
def __repr__(self):
return 'CursorKind.%s' % (self.name,)
@@ -592,7 +655,7 @@ CursorKind.ADDR_LABEL_EXPR = CursorKind(120)
# This is the GNU Statement Expression extension: ({int X=4; X;})
CursorKind.StmtExpr = CursorKind(121)
-# Represents a C1X generic selection.
+# Represents a C11 generic selection.
CursorKind.GENERIC_SELECTION_EXPR = CursorKind(122)
# Implements the GNU __null extension, which is a name for a null
@@ -801,6 +864,11 @@ CursorKind.IB_ACTION_ATTR = CursorKind(401)
CursorKind.IB_OUTLET_ATTR = CursorKind(402)
CursorKind.IB_OUTLET_COLLECTION_ATTR = CursorKind(403)
+CursorKind.CXX_FINAL_ATTR = CursorKind(404)
+CursorKind.CXX_OVERRIDE_ATTR = CursorKind(405)
+CursorKind.ANNOTATE_ATTR = CursorKind(406)
+CursorKind.ASM_LABEL_ATTR = CursorKind(407)
+
###
# Preprocessing
CursorKind.PREPROCESSING_DIRECTIVE = CursorKind(500)
@@ -817,11 +885,15 @@ class Cursor(Structure):
"""
_fields_ = [("_kind_id", c_int), ("xdata", c_int), ("data", c_void_p * 3)]
+ @staticmethod
+ def from_location(tu, location):
+ return Cursor_get(tu, location)
+
def __eq__(self, other):
return Cursor_eq(self, other)
def __ne__(self, other):
- return not Cursor_eq(self, other)
+ return not self.__eq__(other)
def is_definition(self):
"""
@@ -903,13 +975,54 @@ class Cursor(Structure):
@property
def type(self):
"""
- Retrieve the type (if any) of of the entity pointed at by the
- cursor.
+ Retrieve the Type (if any) of the entity pointed at by the cursor.
"""
if not hasattr(self, '_type'):
self._type = Cursor_type(self)
return self._type
+ @property
+ def underlying_typedef_type(self):
+ """Return the underlying type of a typedef declaration.
+
+ Returns a Type for the typedef this cursor is a declaration for. If
+ the current cursor is not a typedef, this raises.
+ """
+ if not hasattr(self, '_underlying_type'):
+ assert self.kind.is_declaration()
+ self._underlying_type = Cursor_underlying_type(self)
+
+ return self._underlying_type
+
+ @property
+ def enum_type(self):
+ """Return the integer type of an enum declaration.
+
+ Returns a Type corresponding to an integer. If the cursor is not for an
+ enum, this raises.
+ """
+ if not hasattr(self, '_enum_type'):
+ assert self.kind == CursorKind.ENUM_DECL
+ self._enum_type = Cursor_enum_type(self)
+
+ return self._enum_type
+
+ @property
+ def objc_type_encoding(self):
+ """Return the Objective-C type encoding as a str."""
+ if not hasattr(self, '_objc_type_encoding'):
+ self._objc_type_encoding = Cursor_objc_type_encoding(self)
+
+ return self._objc_type_encoding
+
+ @property
+ def hash(self):
+ """Returns a hash of the cursor as an int."""
+ if not hasattr(self, '_hash'):
+ self._hash = Cursor_hash(self)
+
+ return self._hash
+
def get_children(self):
"""Return an iterator for accessing the children of this cursor."""
@@ -969,7 +1082,7 @@ class TypeKind(object):
@staticmethod
def from_id(id):
if id >= len(TypeKind._kinds) or TypeKind._kinds[id] is None:
- raise ValueError,'Unknown cursor kind'
+ raise ValueError,'Unknown type kind %d' % id
return TypeKind._kinds[id]
def __repr__(self):
@@ -1020,6 +1133,7 @@ TypeKind.OBJCOBJECTPOINTER = TypeKind(109)
TypeKind.FUNCTIONNOPROTO = TypeKind(110)
TypeKind.FUNCTIONPROTO = TypeKind(111)
TypeKind.CONSTANTARRAY = TypeKind(112)
+TypeKind.VECTOR = TypeKind(113)
class Type(Structure):
"""
@@ -1032,6 +1146,71 @@ class Type(Structure):
"""Return the kind of this type."""
return TypeKind.from_id(self._kind_id)
+ def argument_types(self):
+ """Retrieve a container for the non-variadic arguments for this type.
+
+ The returned object is iterable and indexable. Each item in the
+ container is a Type instance.
+ """
+ class ArgumentsIterator(collections.Sequence):
+ def __init__(self, parent):
+ self.parent = parent
+ self.length = None
+
+ def __len__(self):
+ if self.length is None:
+ self.length = Type_get_num_arg_types(self.parent)
+
+ return self.length
+
+ def __getitem__(self, key):
+ # FIXME Support slice objects.
+ if not isinstance(key, int):
+ raise TypeError("Must supply a non-negative int.")
+
+ if key < 0:
+ raise IndexError("Only non-negative indexes are accepted.")
+
+ if key >= len(self):
+ raise IndexError("Index greater than container length: "
+ "%d > %d" % ( key, len(self) ))
+
+ result = Type_get_arg_type(self.parent, key)
+ if result.kind == TypeKind.INVALID:
+ raise IndexError("Argument could not be retrieved.")
+
+ return result
+
+ assert self.kind == TypeKind.FUNCTIONPROTO
+ return ArgumentsIterator(self)
+
+ @property
+ def element_type(self):
+ """Retrieve the Type of elements within this Type.
+
+ If accessed on a type that is not an array, complex, or vector type, an
+ exception will be raised.
+ """
+ result = Type_get_element_type(self)
+ if result.kind == TypeKind.INVALID:
+ raise Exception('Element type not available on this type.')
+
+ return result
+
+ @property
+ def element_count(self):
+ """Retrieve the number of elements in this type.
+
+ Returns an int.
+
+ If the Type is not an array or vector, this raises.
+ """
+ result = Type_get_num_elements(self)
+ if result < 0:
+ raise Exception('Type does not have elements.')
+
+ return result
+
@staticmethod
def from_result(res, fn, args):
assert isinstance(res, Type)
@@ -1050,29 +1229,39 @@ class Type(Structure):
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"
+ """Determine whether a Type has the "const" qualifier set.
+
+ This does not look 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.
+ """Determine whether a Type has the "volatile" qualifier set.
+
+ This does not look 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.
+ """Determine whether a Type has the "restrict" qualifier set.
+
+ This does not look through typedefs that may have added "restrict" at
+ a different level.
"""
return Type_is_restrict_qualified(self)
+ def is_function_variadic(self):
+ """Determine whether this function Type is a variadic function type."""
+ assert self.kind == TypeKind.FUNCTIONPROTO
+
+ return Type_is_variadic(self)
+
+ def is_pod(self):
+ """Determine whether this Type represents plain old data (POD)."""
+ return Type_is_pod(self)
+
def get_pointee(self):
"""
For pointer types, returns the type of the pointee.
@@ -1091,6 +1280,27 @@ class Type(Structure):
"""
return Type_get_result(self)
+ def get_array_element_type(self):
+ """
+ Retrieve the type of the elements of the array type.
+ """
+ return Type_get_array_element(self)
+
+ def get_array_size(self):
+ """
+ Retrieve the size of the constant array.
+ """
+ return Type_get_array_size(self)
+
+ def __eq__(self, other):
+ if type(other) != type(self):
+ return False
+
+ return Type_equal(self, other)
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
## CIndex Objects ##
# CIndex objects (derived from ClangObject) are essentially lightweight
@@ -1157,6 +1367,20 @@ _clang_getDiagnosticFixIt.argtypes = [Diagnostic, c_uint, POINTER(SourceRange)]
_clang_getDiagnosticFixIt.restype = _CXString
_clang_getDiagnosticFixIt.errcheck = _CXString.from_result
+_clang_getDiagnosticCategory = lib.clang_getDiagnosticCategory
+_clang_getDiagnosticCategory.argtypes = [Diagnostic]
+_clang_getDiagnosticCategory.restype = c_uint
+
+_clang_getDiagnosticCategoryName = lib.clang_getDiagnosticCategoryName
+_clang_getDiagnosticCategoryName.argtypes = [c_uint]
+_clang_getDiagnosticCategoryName.restype = _CXString
+_clang_getDiagnosticCategoryName.errcheck = _CXString.from_result
+
+_clang_getDiagnosticOption = lib.clang_getDiagnosticOption
+_clang_getDiagnosticOption.argtypes = [Diagnostic, POINTER(_CXString)]
+_clang_getDiagnosticOption.restype = _CXString
+_clang_getDiagnosticOption.errcheck = _CXString.from_result
+
###
class CompletionChunk:
@@ -1350,7 +1574,9 @@ class Index(ClangObject):
def read(self, path):
"""Load the translation unit from the given AST file."""
ptr = TranslationUnit_read(self, path)
- return TranslationUnit(ptr) if ptr else None
+ if ptr:
+ return TranslationUnit(ptr)
+ return None
def parse(self, path, args = [], unsaved_files = [], options = 0):
"""
@@ -1383,7 +1609,9 @@ class Index(ClangObject):
ptr = TranslationUnit_parse(self, path, arg_array, len(args),
unsaved_files_array, len(unsaved_files),
options)
- return TranslationUnit(ptr) if ptr else None
+ if ptr:
+ return TranslationUnit(ptr)
+ return None
class TranslationUnit(ClangObject):
@@ -1502,8 +1730,9 @@ class TranslationUnit(ClangObject):
unsaved_files_array,
len(unsaved_files),
options)
- return CodeCompletionResults(ptr) if ptr else None
-
+ if ptr:
+ return CodeCompletionResults(ptr)
+ return None
class File(ClangObject):
"""
@@ -1511,6 +1740,11 @@ class File(ClangObject):
translation unit.
"""
+ @staticmethod
+ def from_name(translation_unit, file_name):
+ """Retrieve a file handle within the given translation unit."""
+ return File(File_getFile(translation_unit, file_name))
+
@property
def name(self):
"""Return the complete file and path name of the file."""
@@ -1521,6 +1755,12 @@ class File(ClangObject):
"""Return the last modification time of the file."""
return File_time(self)
+ def __str__(self):
+ return self.name
+
+ def __repr__(self):
+ return "<File: %s>" % (self.name)
+
class FileInclusion(object):
"""
The FileInclusion class represents the inclusion of one source file by
@@ -1557,6 +1797,14 @@ SourceLocation_loc.argtypes = [SourceLocation, POINTER(c_object_p),
POINTER(c_uint), POINTER(c_uint),
POINTER(c_uint)]
+SourceLocation_getLocation = lib.clang_getLocation
+SourceLocation_getLocation.argtypes = [TranslationUnit, File, c_uint, c_uint]
+SourceLocation_getLocation.restype = SourceLocation
+
+SourceLocation_equalLocations = lib.clang_equalLocations
+SourceLocation_equalLocations.argtypes = [SourceLocation, SourceLocation]
+SourceLocation_equalLocations.restype = bool
+
# Source Range Functions
SourceRange_getRange = lib.clang_getRange
SourceRange_getRange.argtypes = [SourceLocation, SourceLocation]
@@ -1570,6 +1818,10 @@ SourceRange_end = lib.clang_getRangeEnd
SourceRange_end.argtypes = [SourceRange]
SourceRange_end.restype = SourceLocation
+SourceRange_equalRanges = lib.clang_equalRanges
+SourceRange_equalRanges.argtypes = [SourceRange, SourceRange]
+SourceRange_equalRanges.restype = bool
+
# CursorKind Functions
CursorKind_is_decl = lib.clang_isDeclaration
CursorKind_is_decl.argtypes = [CursorKind]
@@ -1595,6 +1847,18 @@ CursorKind_is_inv = lib.clang_isInvalid
CursorKind_is_inv.argtypes = [CursorKind]
CursorKind_is_inv.restype = bool
+CursorKind_is_translation_unit = lib.clang_isTranslationUnit
+CursorKind_is_translation_unit.argtypes = [CursorKind]
+CursorKind_is_translation_unit.restype = bool
+
+CursorKind_is_preprocessing = lib.clang_isPreprocessing
+CursorKind_is_preprocessing.argtypes = [CursorKind]
+CursorKind_is_preprocessing.restype = bool
+
+CursorKind_is_unexposed = lib.clang_isUnexposed
+CursorKind_is_unexposed.argtypes = [CursorKind]
+CursorKind_is_unexposed.restype = bool
+
# Cursor Functions
# TODO: Implement this function
Cursor_get = lib.clang_getCursor
@@ -1620,7 +1884,11 @@ Cursor_def.errcheck = Cursor.from_result
Cursor_eq = lib.clang_equalCursors
Cursor_eq.argtypes = [Cursor, Cursor]
-Cursor_eq.restype = c_uint
+Cursor_eq.restype = bool
+
+Cursor_hash = lib.clang_hashCursor
+Cursor_hash.argtypes = [Cursor]
+Cursor_hash.restype = c_uint
Cursor_spelling = lib.clang_getCursorSpelling
Cursor_spelling.argtypes = [Cursor]
@@ -1650,6 +1918,21 @@ Cursor_type.argtypes = [Cursor]
Cursor_type.restype = Type
Cursor_type.errcheck = Type.from_result
+Cursor_underlying_type = lib.clang_getTypedefDeclUnderlyingType
+Cursor_underlying_type.argtypes = [Cursor]
+Cursor_underlying_type.restype = Type
+Cursor_underlying_type.errcheck = Type.from_result
+
+Cursor_enum_type = lib.clang_getEnumDeclIntegerType
+Cursor_enum_type.argtypes = [Cursor]
+Cursor_enum_type.restype = Type
+Cursor_enum_type.errcheck = Type.from_result
+
+Cursor_objc_type_encoding = lib.clang_getDeclObjCTypeEncoding
+Cursor_objc_type_encoding.argtypes = [Cursor]
+Cursor_objc_type_encoding.restype = _CXString
+Cursor_objc_type_encoding.errcheck = _CXString.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]
@@ -1673,6 +1956,14 @@ Type_is_restrict_qualified = lib.clang_isRestrictQualifiedType
Type_is_restrict_qualified.argtypes = [Type]
Type_is_restrict_qualified.restype = bool
+Type_is_pod = lib.clang_isPODType
+Type_is_pod.argtypes = [Type]
+Type_is_pod.restype = bool
+
+Type_is_variadic = lib.clang_isFunctionTypeVariadic
+Type_is_variadic.argtypes = [Type]
+Type_is_variadic.restype = bool
+
Type_get_pointee = lib.clang_getPointeeType
Type_get_pointee.argtypes = [Type]
Type_get_pointee.restype = Type
@@ -1688,6 +1979,36 @@ Type_get_result.argtypes = [Type]
Type_get_result.restype = Type
Type_get_result.errcheck = Type.from_result
+Type_get_num_arg_types = lib.clang_getNumArgTypes
+Type_get_num_arg_types.argtypes = [Type]
+Type_get_num_arg_types.restype = c_uint
+
+Type_get_arg_type = lib.clang_getArgType
+Type_get_arg_type.argtypes = [Type, c_uint]
+Type_get_arg_type.restype = Type
+Type_get_arg_type.errcheck = Type.from_result
+Type_get_element_type = lib.clang_getElementType
+
+Type_get_element_type.argtypes = [Type]
+Type_get_element_type.restype = Type
+Type_get_element_type.errcheck = Type.from_result
+
+Type_get_num_elements = lib.clang_getNumElements
+Type_get_num_elements.argtypes = [Type]
+Type_get_num_elements.restype = c_longlong
+
+Type_get_array_element = lib.clang_getArrayElementType
+Type_get_array_element.argtypes = [Type]
+Type_get_array_element.restype = Type
+Type_get_array_element.errcheck = Type.from_result
+
+Type_get_array_size = lib.clang_getArraySize
+Type_get_array_size.argtype = [Type]
+Type_get_array_size.restype = c_longlong
+
+Type_equal = lib.clang_equalTypes
+Type_equal.argtypes = [Type, Type]
+Type_equal.restype = bool
# Index Functions
Index_create = lib.clang_createIndex
@@ -1739,6 +2060,10 @@ TranslationUnit_includes.argtypes = [TranslationUnit,
py_object]
# File Functions
+File_getFile = lib.clang_getFile
+File_getFile.argtypes = [TranslationUnit, c_char_p]
+File_getFile.restype = c_object_p
+
File_name = lib.clang_getFileName
File_name.argtypes = [File]
File_name.restype = _CXString
diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py
index 3dde891a9c264..9f02bb2a76863 100644
--- a/bindings/python/tests/cindex/test_cursor.py
+++ b/bindings/python/tests/cindex/test_cursor.py
@@ -1,4 +1,7 @@
-from clang.cindex import Index, CursorKind, TypeKind
+from clang.cindex import CursorKind
+from clang.cindex import TypeKind
+from .util import get_cursor
+from .util import get_tu
kInput = """\
// FIXME: Find nicer way to drop builtins and other cruft.
@@ -24,9 +27,8 @@ void f0(int a0, int a1) {
"""
def test_get_children():
- index = Index.create()
- tu = index.parse('t.c', unsaved_files = [('t.c',kInput)])
-
+ tu = get_tu(kInput)
+
# Skip until past start_decl.
it = tu.cursor.get_children()
while it.next().spelling != 'start_decl':
@@ -36,12 +38,14 @@ def test_get_children():
assert len(tu_nodes) == 3
+ assert tu_nodes[0] != tu_nodes[1]
assert tu_nodes[0].kind == CursorKind.STRUCT_DECL
assert tu_nodes[0].spelling == 's0'
assert tu_nodes[0].is_definition() == True
assert tu_nodes[0].location.file.name == 't.c'
assert tu_nodes[0].location.line == 4
assert tu_nodes[0].location.column == 8
+ assert tu_nodes[0].hash > 0
s0_nodes = list(tu_nodes[0].get_children())
assert len(s0_nodes) == 2
@@ -61,3 +65,28 @@ def test_get_children():
assert tu_nodes[2].spelling == 'f0'
assert tu_nodes[2].displayname == 'f0(int, int)'
assert tu_nodes[2].is_definition() == True
+
+def test_underlying_type():
+ tu = get_tu('typedef int foo;')
+ typedef = get_cursor(tu, 'foo')
+ assert typedef is not None
+
+ assert typedef.kind.is_declaration()
+ underlying = typedef.underlying_typedef_type
+ assert underlying.kind == TypeKind.INT
+
+def test_enum_type():
+ tu = get_tu('enum TEST { FOO=1, BAR=2 };')
+ enum = get_cursor(tu, 'TEST')
+ assert enum is not None
+
+ assert enum.kind == CursorKind.ENUM_DECL
+ enum_type = enum.enum_type
+ assert enum_type.kind == TypeKind.UINT
+
+def test_objc_type_encoding():
+ tu = get_tu('int i;', lang='objc')
+ i = get_cursor(tu, 'i')
+
+ assert i is not None
+ assert i.objc_type_encoding == 'i'
diff --git a/bindings/python/tests/cindex/test_cursor_kind.py b/bindings/python/tests/cindex/test_cursor_kind.py
index d7a1cfad8f946..f8466e5e0d1d6 100644
--- a/bindings/python/tests/cindex/test_cursor_kind.py
+++ b/bindings/python/tests/cindex/test_cursor_kind.py
@@ -16,6 +16,15 @@ def test_kind_groups():
assert CursorKind.UNEXPOSED_STMT.is_statement()
assert CursorKind.INVALID_FILE.is_invalid()
+ assert CursorKind.TRANSLATION_UNIT.is_translation_unit()
+ assert not CursorKind.TYPE_REF.is_translation_unit()
+
+ assert CursorKind.PREPROCESSING_DIRECTIVE.is_preprocessing()
+ assert not CursorKind.TYPE_REF.is_preprocessing()
+
+ assert CursorKind.UNEXPOSED_DECL.is_unexposed()
+ assert not CursorKind.TYPE_REF.is_unexposed()
+
for k in CursorKind.get_all_kinds():
group = [n for n in ('is_declaration', 'is_reference', 'is_expression',
'is_statement', 'is_invalid', 'is_attribute')
diff --git a/bindings/python/tests/cindex/test_diagnostics.py b/bindings/python/tests/cindex/test_diagnostics.py
index 98f97d3bd3b13..48ab6176fd1df 100644
--- a/bindings/python/tests/cindex/test_diagnostics.py
+++ b/bindings/python/tests/cindex/test_diagnostics.py
@@ -1,14 +1,10 @@
from clang.cindex import *
-
-def tu_from_source(source):
- index = Index.create()
- tu = index.parse('INPUT.c', unsaved_files = [('INPUT.c', source)])
- return tu
+from .util import get_tu
# FIXME: We need support for invalid translation units to test better.
def test_diagnostic_warning():
- tu = tu_from_source("""int f0() {}\n""")
+ tu = get_tu('int f0() {}\n')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 1
@@ -18,8 +14,7 @@ def test_diagnostic_warning():
def test_diagnostic_note():
# FIXME: We aren't getting notes here for some reason.
- index = Index.create()
- tu = tu_from_source("""#define A x\nvoid *A = 1;\n""")
+ tu = get_tu('#define A x\nvoid *A = 1;\n')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 2
@@ -31,8 +26,7 @@ def test_diagnostic_note():
# assert tu.diagnostics[1].spelling == 'instantiated from'
def test_diagnostic_fixit():
- index = Index.create()
- tu = tu_from_source("""struct { int f0; } x = { f0 : 1 };""")
+ tu = get_tu('struct { int f0; } x = { f0 : 1 };')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 1
@@ -46,8 +40,7 @@ def test_diagnostic_fixit():
assert tu.diagnostics[0].fixits[0].value == '.f0 = '
def test_diagnostic_range():
- index = Index.create()
- tu = tu_from_source("""void f() { int i = "a" + 1; }""")
+ tu = get_tu('void f() { int i = "a" + 1; }')
assert len(tu.diagnostics) == 1
assert tu.diagnostics[0].severity == Diagnostic.Warning
assert tu.diagnostics[0].location.line == 1
@@ -65,5 +58,25 @@ def test_diagnostic_range():
assert True
else:
assert False
-
+def test_diagnostic_category():
+ """Ensure that category properties work."""
+ tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
+ assert len(tu.diagnostics) == 1
+ d = tu.diagnostics[0]
+
+ assert d.severity == Diagnostic.Warning
+ assert d.location.line == 1
+ assert d.location.column == 11
+
+ assert d.category_number == 2
+ assert d.category_name == 'Semantic Issue'
+
+def test_diagnostic_option():
+ """Ensure that category option properties work."""
+ tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
+ assert len(tu.diagnostics) == 1
+ d = tu.diagnostics[0]
+
+ assert d.option == '-Wunused-parameter'
+ assert d.disable_option == '-Wno-unused-parameter'
diff --git a/bindings/python/tests/cindex/test_file.py b/bindings/python/tests/cindex/test_file.py
new file mode 100644
index 0000000000000..146e8c5705287
--- /dev/null
+++ b/bindings/python/tests/cindex/test_file.py
@@ -0,0 +1,9 @@
+from clang.cindex import Index, File
+
+def test_file():
+ index = Index.create()
+ tu = index.parse('t.c', unsaved_files = [('t.c', "")])
+ file = File.from_name(tu, "t.c")
+ assert str(file) == "t.c"
+ assert file.name == "t.c"
+ assert repr(file) == "<File: t.c>"
diff --git a/bindings/python/tests/cindex/test_location.py b/bindings/python/tests/cindex/test_location.py
index 47c1c6021f554..528676ef14b57 100644
--- a/bindings/python/tests/cindex/test_location.py
+++ b/bindings/python/tests/cindex/test_location.py
@@ -1,4 +1,9 @@
-from clang.cindex import Index
+from clang.cindex import Cursor
+from clang.cindex import File
+from clang.cindex import SourceLocation
+from clang.cindex import SourceRange
+from .util import get_cursor
+from .util import get_tu
baseInput="int one;\nint two;\n"
@@ -8,43 +13,74 @@ def assert_location(loc, line, column, offset):
assert loc.offset == offset
def test_location():
- index = Index.create()
- tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
+ tu = get_tu(baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
- for n in tu.cursor.get_children():
- if n.spelling == 'one':
- assert_location(n.location,line=1,column=5,offset=4)
- if n.spelling == 'two':
- assert_location(n.location,line=2,column=5,offset=13)
+ assert one is not None
+ assert two is not None
+
+ assert_location(one.location,line=1,column=5,offset=4)
+ assert_location(two.location,line=2,column=5,offset=13)
# adding a linebreak at top should keep columns same
- tu = index.parse('t.c', unsaved_files = [('t.c',"\n"+baseInput)])
+ tu = get_tu('\n' + baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ assert one is not None
+ assert two is not None
- for n in tu.cursor.get_children():
- if n.spelling == 'one':
- assert_location(n.location,line=2,column=5,offset=5)
- if n.spelling == 'two':
- assert_location(n.location,line=3,column=5,offset=14)
+ assert_location(one.location,line=2,column=5,offset=5)
+ assert_location(two.location,line=3,column=5,offset=14)
# adding a space should affect column on first line only
- tu = index.parse('t.c', unsaved_files = [('t.c'," "+baseInput)])
+ tu = get_tu(' ' + baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ assert_location(one.location,line=1,column=6,offset=5)
+ assert_location(two.location,line=2,column=5,offset=14)
+
+ # define the expected location ourselves and see if it matches
+ # the returned location
+ tu = get_tu(baseInput)
+
+ file = File.from_name(tu, 't.c')
+ location = SourceLocation.from_position(tu, file, 1, 5)
+ cursor = Cursor.from_location(tu, location)
+
+ one = get_cursor(tu, 'one')
+ assert one is not None
+ assert one == cursor
- for n in tu.cursor.get_children():
- if n.spelling == 'one':
- assert_location(n.location,line=1,column=6,offset=5)
- if n.spelling == 'two':
- assert_location(n.location,line=2,column=5,offset=14)
+ # Ensure locations referring to the same entity are equivalent.
+ location2 = SourceLocation.from_position(tu, file, 1, 5)
+ assert location == location2
+ location3 = SourceLocation.from_position(tu, file, 1, 4)
+ assert location2 != location3
def test_extent():
- index = Index.create()
- tu = index.parse('t.c', unsaved_files = [('t.c',baseInput)])
-
- for n in tu.cursor.get_children():
- if n.spelling == 'one':
- assert_location(n.extent.start,line=1,column=1,offset=0)
- assert_location(n.extent.end,line=1,column=8,offset=7)
- assert baseInput[n.extent.start.offset:n.extent.end.offset] == "int one"
- if n.spelling == 'two':
- assert_location(n.extent.start,line=2,column=1,offset=9)
- assert_location(n.extent.end,line=2,column=8,offset=16)
- assert baseInput[n.extent.start.offset:n.extent.end.offset] == "int two"
+ tu = get_tu(baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ assert_location(one.extent.start,line=1,column=1,offset=0)
+ assert_location(one.extent.end,line=1,column=8,offset=7)
+ assert baseInput[one.extent.start.offset:one.extent.end.offset] == "int one"
+
+ assert_location(two.extent.start,line=2,column=1,offset=9)
+ assert_location(two.extent.end,line=2,column=8,offset=16)
+ assert baseInput[two.extent.start.offset:two.extent.end.offset] == "int two"
+
+ file = File.from_name(tu, 't.c')
+ location1 = SourceLocation.from_position(tu, file, 1, 1)
+ location2 = SourceLocation.from_position(tu, file, 1, 8)
+
+ range1 = SourceRange.from_locations(location1, location2)
+ range2 = SourceRange.from_locations(location1, location2)
+ assert range1 == range2
+
+ location3 = SourceLocation.from_position(tu, file, 1, 6)
+ range3 = SourceRange.from_locations(location1, location3)
+ assert range1 != range3
diff --git a/bindings/python/tests/cindex/test_type.py b/bindings/python/tests/cindex/test_type.py
index 35c7bbbfa2fa7..ed852103b94ae 100644
--- a/bindings/python/tests/cindex/test_type.py
+++ b/bindings/python/tests/cindex/test_type.py
@@ -1,4 +1,9 @@
-from clang.cindex import Index, CursorKind, TypeKind
+from clang.cindex import CursorKind
+from clang.cindex import Index
+from clang.cindex import TypeKind
+from nose.tools import raises
+from .util import get_cursor
+from .util import get_tu
kInput = """\
@@ -18,63 +23,55 @@ struct teststruct {
"""
def test_a_struct():
- index = Index.create()
- tu = index.parse('t.c', unsaved_files = [('t.c',kInput)])
+ tu = get_tu(kInput)
- for n in tu.cursor.get_children():
- if n.spelling == 'teststruct':
- fields = list(n.get_children())
+ teststruct = get_cursor(tu, 'teststruct')
+ assert teststruct is not None, "Could not find teststruct."
+ fields = list(teststruct.get_children())
+ assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
- assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
+ assert fields[0].spelling == 'a'
+ assert not fields[0].type.is_const_qualified()
+ assert fields[0].type.kind == TypeKind.INT
+ assert fields[0].type.get_canonical().kind == TypeKind.INT
- assert fields[0].spelling == 'a'
- assert not fields[0].type.is_const_qualified()
- assert fields[0].type.kind == TypeKind.INT
- assert fields[0].type.get_canonical().kind == TypeKind.INT
+ assert fields[1].spelling == 'b'
+ assert not fields[1].type.is_const_qualified()
+ assert fields[1].type.kind == TypeKind.TYPEDEF
+ assert fields[1].type.get_canonical().kind == TypeKind.INT
+ assert fields[1].type.get_declaration().spelling == 'I'
- assert fields[1].spelling == 'b'
- assert not fields[1].type.is_const_qualified()
- assert fields[1].type.kind == TypeKind.TYPEDEF
- assert fields[1].type.get_canonical().kind == TypeKind.INT
- assert fields[1].type.get_declaration().spelling == 'I'
+ assert fields[2].spelling == 'c'
+ assert not fields[2].type.is_const_qualified()
+ assert fields[2].type.kind == TypeKind.LONG
+ assert fields[2].type.get_canonical().kind == TypeKind.LONG
- assert fields[2].spelling == 'c'
- assert not fields[2].type.is_const_qualified()
- assert fields[2].type.kind == TypeKind.LONG
- assert fields[2].type.get_canonical().kind == TypeKind.LONG
+ assert fields[3].spelling == 'd'
+ assert not fields[3].type.is_const_qualified()
+ assert fields[3].type.kind == TypeKind.ULONG
+ assert fields[3].type.get_canonical().kind == TypeKind.ULONG
- assert fields[3].spelling == 'd'
- assert not fields[3].type.is_const_qualified()
- assert fields[3].type.kind == TypeKind.ULONG
- assert fields[3].type.get_canonical().kind == TypeKind.ULONG
+ assert fields[4].spelling == 'e'
+ assert not fields[4].type.is_const_qualified()
+ assert fields[4].type.kind == TypeKind.LONG
+ assert fields[4].type.get_canonical().kind == TypeKind.LONG
- assert fields[4].spelling == 'e'
- assert not fields[4].type.is_const_qualified()
- assert fields[4].type.kind == TypeKind.LONG
- assert fields[4].type.get_canonical().kind == TypeKind.LONG
+ assert fields[5].spelling == 'f'
+ assert fields[5].type.is_const_qualified()
+ assert fields[5].type.kind == TypeKind.INT
+ assert fields[5].type.get_canonical().kind == TypeKind.INT
- assert fields[5].spelling == 'f'
- assert fields[5].type.is_const_qualified()
- assert fields[5].type.kind == TypeKind.INT
- assert fields[5].type.get_canonical().kind == TypeKind.INT
-
- assert fields[6].spelling == 'g'
- assert not fields[6].type.is_const_qualified()
- assert fields[6].type.kind == TypeKind.POINTER
- assert fields[6].type.get_pointee().kind == TypeKind.INT
-
- assert fields[7].spelling == 'h'
- assert not fields[7].type.is_const_qualified()
- assert fields[7].type.kind == TypeKind.POINTER
- assert fields[7].type.get_pointee().kind == TypeKind.POINTER
- assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
- assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
-
- break
-
- else:
- assert False, "Didn't find teststruct??"
+ assert fields[6].spelling == 'g'
+ assert not fields[6].type.is_const_qualified()
+ assert fields[6].type.kind == TypeKind.POINTER
+ assert fields[6].type.get_pointee().kind == TypeKind.INT
+ assert fields[7].spelling == 'h'
+ assert not fields[7].type.is_const_qualified()
+ assert fields[7].type.kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
+ assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
constarrayInput="""
struct teststruct {
@@ -82,14 +79,191 @@ struct teststruct {
};
"""
def testConstantArray():
- index = Index.create()
- tu = index.parse('t.c', unsaved_files = [('t.c',constarrayInput)])
-
- for n in tu.cursor.get_children():
- if n.spelling == 'teststruct':
- fields = list(n.get_children())
- assert fields[0].spelling == 'A'
- assert fields[0].type.kind == TypeKind.CONSTANTARRAY
- break
- else:
- assert False, "Didn't find teststruct??"
+ tu = get_tu(constarrayInput)
+
+ teststruct = get_cursor(tu, 'teststruct')
+ assert teststruct is not None, "Didn't find teststruct??"
+ fields = list(teststruct.get_children())
+ assert fields[0].spelling == 'A'
+ assert fields[0].type.kind == TypeKind.CONSTANTARRAY
+ assert fields[0].type.get_array_element_type() is not None
+ assert fields[0].type.get_array_element_type().kind == TypeKind.POINTER
+ assert fields[0].type.get_array_size() == 2
+
+def test_equal():
+ """Ensure equivalence operators work on Type."""
+ source = 'int a; int b; void *v;'
+ tu = get_tu(source)
+
+ a = get_cursor(tu, 'a')
+ b = get_cursor(tu, 'b')
+ v = get_cursor(tu, 'v')
+
+ assert a is not None
+ assert b is not None
+ assert v is not None
+
+ assert a.type == b.type
+ assert a.type != v.type
+
+ assert a.type != None
+ assert a.type != 'foo'
+
+def test_function_argument_types():
+ """Ensure that Type.argument_types() works as expected."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ assert f is not None
+
+ args = f.type.argument_types()
+ assert args is not None
+ assert len(args) == 2
+
+ t0 = args[0]
+ assert t0 is not None
+ assert t0.kind == TypeKind.INT
+
+ t1 = args[1]
+ assert t1 is not None
+ assert t1.kind == TypeKind.INT
+
+ args2 = list(args)
+ assert len(args2) == 2
+ assert t0 == args2[0]
+ assert t1 == args2[1]
+
+@raises(TypeError)
+def test_argument_types_string_key():
+ """Ensure that non-int keys raise a TypeError."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ assert f is not None
+
+ args = f.type.argument_types()
+ assert len(args) == 2
+
+ args['foo']
+
+@raises(IndexError)
+def test_argument_types_negative_index():
+ """Ensure that negative indexes on argument_types Raises an IndexError."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ args = f.type.argument_types()
+
+ args[-1]
+
+@raises(IndexError)
+def test_argument_types_overflow_index():
+ """Ensure that indexes beyond the length of Type.argument_types() raise."""
+ tu = get_tu('void f(int, int);')
+ f = get_cursor(tu, 'f')
+ args = f.type.argument_types()
+
+ args[2]
+
+@raises(Exception)
+def test_argument_types_invalid_type():
+ """Ensure that obtaining argument_types on a Type without them raises."""
+ tu = get_tu('int i;')
+ i = get_cursor(tu, 'i')
+ assert i is not None
+
+ i.type.argument_types()
+
+def test_is_pod():
+ """Ensure Type.is_pod() works."""
+ tu = get_tu('int i; void f();')
+ i = get_cursor(tu, 'i')
+ f = get_cursor(tu, 'f')
+
+ assert i is not None
+ assert f is not None
+
+ assert i.type.is_pod()
+ assert not f.type.is_pod()
+
+def test_function_variadic():
+ """Ensure Type.is_function_variadic works."""
+
+ source ="""
+#include <stdarg.h>
+
+void foo(int a, ...);
+void bar(int a, int b);
+"""
+
+ tu = get_tu(source)
+ foo = get_cursor(tu, 'foo')
+ bar = get_cursor(tu, 'bar')
+
+ assert foo is not None
+ assert bar is not None
+
+ assert isinstance(foo.type.is_function_variadic(), bool)
+ assert foo.type.is_function_variadic()
+ assert not bar.type.is_function_variadic()
+
+def test_element_type():
+ """Ensure Type.element_type works."""
+ tu = get_tu('int i[5];')
+ i = get_cursor(tu, 'i')
+ assert i is not None
+
+ assert i.type.kind == TypeKind.CONSTANTARRAY
+ assert i.type.element_type.kind == TypeKind.INT
+
+@raises(Exception)
+def test_invalid_element_type():
+ """Ensure Type.element_type raises if type doesn't have elements."""
+ tu = get_tu('int i;')
+ i = get_cursor(tu, 'i')
+ assert i is not None
+ i.element_type
+
+def test_element_count():
+ """Ensure Type.element_count works."""
+ tu = get_tu('int i[5]; int j;')
+ i = get_cursor(tu, 'i')
+ j = get_cursor(tu, 'j')
+
+ assert i is not None
+ assert j is not None
+
+ assert i.type.element_count == 5
+
+ try:
+ j.type.element_count
+ assert False
+ except:
+ assert True
+
+def test_is_volatile_qualified():
+ """Ensure Type.is_volatile_qualified works."""
+
+ tu = get_tu('volatile int i = 4; int j = 2;')
+
+ i = get_cursor(tu, 'i')
+ j = get_cursor(tu, 'j')
+
+ assert i is not None
+ assert j is not None
+
+ assert isinstance(i.type.is_volatile_qualified(), bool)
+ assert i.type.is_volatile_qualified()
+ assert not j.type.is_volatile_qualified()
+
+def test_is_restrict_qualified():
+ """Ensure Type.is_restrict_qualified works."""
+
+ tu = get_tu('struct s { void * restrict i; void * j };')
+
+ i = get_cursor(tu, 'i')
+ j = get_cursor(tu, 'j')
+
+ assert i is not None
+ assert j is not None
+
+ assert isinstance(i.type.is_restrict_qualified(), bool)
+ assert i.type.is_restrict_qualified()
+ assert not j.type.is_restrict_qualified()
diff --git a/bindings/python/tests/cindex/util.py b/bindings/python/tests/cindex/util.py
new file mode 100644
index 0000000000000..388b269489982
--- /dev/null
+++ b/bindings/python/tests/cindex/util.py
@@ -0,0 +1,65 @@
+# This file provides common utility functions for the test suite.
+
+from clang.cindex import Cursor
+from clang.cindex import Index
+
+def get_tu(source, lang='c', all_warnings=False):
+ """Obtain a translation unit from source and language.
+
+ By default, the translation unit is created from source file "t.<ext>"
+ where <ext> is the default file extension for the specified language. By
+ default it is C, so "t.c" is the default file name.
+
+ Supported languages are {c, cpp, objc}.
+
+ all_warnings is a convenience argument to enable all compiler warnings.
+ """
+ name = 't.c'
+ if lang == 'cpp':
+ name = 't.cpp'
+ elif lang == 'objc':
+ name = 't.m'
+ elif lang != 'c':
+ raise Exception('Unknown language: %s' % lang)
+
+ args = []
+ if all_warnings:
+ args = ['-Wall', '-Wextra']
+
+ index = Index.create()
+ tu = index.parse(name, args=args, unsaved_files=[(name, source)])
+ assert tu is not None
+ return tu
+
+def get_cursor(source, spelling):
+ """Obtain a cursor from a source object.
+
+ This provides a convenient search mechanism to find a cursor with specific
+ spelling within a source. The first argument can be either a
+ TranslationUnit or Cursor instance.
+
+ If the cursor is not found, None is returned.
+ """
+ children = []
+ if isinstance(source, Cursor):
+ children = source.get_children()
+ else:
+ # Assume TU
+ children = source.cursor.get_children()
+
+ for cursor in children:
+ if cursor.spelling == spelling:
+ return cursor
+
+ # Recurse into children.
+ result = get_cursor(cursor, spelling)
+ if result is not None:
+ return result
+
+ return None
+
+
+__all__ = [
+ 'get_cursor',
+ 'get_tu',
+]