diff options
author | David L. Jones <dlj@google.com> | 2017-11-10 01:07:01 +0000 |
---|---|---|
committer | David L. Jones <dlj@google.com> | 2017-11-10 01:07:01 +0000 |
commit | 41af1698c520ea38edf83e7c91f1e519d34f20c1 (patch) | |
tree | 05c516cb7514d80a5e8deccb07cd0f7c228b70d4 /bindings | |
parent | cd1b175aa96d9d675c09fc54dfd96ba41e3f2279 (diff) | |
parent | 4d085086c74a8fbce197f61548f488a63f300933 (diff) |
Creating branches/google/testing and tags/google/testing/ from r317203
git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/google/testing@317856 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'bindings')
-rw-r--r-- | bindings/python/clang/__init__.py | 8 | ||||
-rw-r--r-- | bindings/python/clang/cindex.py | 318 | ||||
-rw-r--r-- | bindings/python/tests/cindex/test_cursor.py | 83 | ||||
-rw-r--r-- | bindings/python/tests/cindex/test_diagnostics.py | 8 | ||||
-rw-r--r-- | bindings/python/tests/cindex/test_exception_specification_kind.py | 27 | ||||
-rw-r--r-- | bindings/python/tests/cindex/test_index.py | 2 | ||||
-rw-r--r-- | bindings/python/tests/cindex/test_linkage.py | 30 | ||||
-rw-r--r-- | bindings/python/tests/cindex/test_tls_kind.py | 37 | ||||
-rw-r--r-- | bindings/python/tests/cindex/test_translation_unit.py | 7 | ||||
-rw-r--r-- | bindings/python/tests/cindex/test_type.py | 17 |
10 files changed, 496 insertions, 41 deletions
diff --git a/bindings/python/clang/__init__.py b/bindings/python/clang/__init__.py index fba49e38c9..88f3081238 100644 --- a/bindings/python/clang/__init__.py +++ b/bindings/python/clang/__init__.py @@ -20,13 +20,5 @@ The available modules are: Bindings for the Clang indexing library. """ - -# Python 3 uses unicode for strings. The bindings, in particular the interaction -# with ctypes, need modifying to handle conversions between unicode and -# c-strings. -import sys -if sys.version_info[0] != 2: - raise Exception("Only Python 2 is supported.") - __all__ = ['cindex'] diff --git a/bindings/python/clang/cindex.py b/bindings/python/clang/cindex.py index 48fc8b13a2..d72dd14ef9 100644 --- a/bindings/python/clang/cindex.py +++ b/bindings/python/clang/cindex.py @@ -67,6 +67,63 @@ import collections import clang.enumerations +import sys +if sys.version_info[0] == 3: + # Python 3 strings are unicode, translate them to/from utf8 for C-interop. + class c_interop_string(c_char_p): + + def __init__(self, p=None): + if p is None: + p = "" + if isinstance(p, str): + p = p.encode("utf8") + super(c_char_p, self).__init__(p) + + def __str__(self): + return self.value + + @property + def value(self): + if super(c_char_p, self).value is None: + return None + return super(c_char_p, self).value.decode("utf8") + + @classmethod + def from_param(cls, param): + if isinstance(param, str): + return cls(param) + if isinstance(param, bytes): + return cls(param) + if param is None: + # Support passing null to C functions expecting char arrays + return None + raise TypeError("Cannot convert '{}' to '{}'".format(type(param).__name__, cls.__name__)) + + @staticmethod + def to_python_string(x, *args): + return x.value + + def b(x): + if isinstance(x, bytes): + return x + return x.encode('utf8') + + xrange = range + +elif sys.version_info[0] == 2: + # Python 2 strings are utf8 byte strings, no translation is needed for + # C-interop. + c_interop_string = c_char_p + + def _to_python_string(x, *args): + return x + + c_interop_string.to_python_string = staticmethod(_to_python_string) + + def b(x): + return x + + # ctypes doesn't implicitly convert c_void_p to the appropriate wrapper # object. This is a problem, because it means that from_parameter will see an # integer and pass the wrong value on platforms where int != void*. Work around @@ -153,10 +210,11 @@ class _CXString(Structure): conf.lib.clang_disposeString(self) @staticmethod - def from_result(res, fn, args): + def from_result(res, fn=None, args=None): assert isinstance(res, _CXString) return conf.lib.clang_getCString(res) + class SourceLocation(Structure): """ A SourceLocation represents a particular location within a source file. @@ -404,8 +462,7 @@ class Diagnostic(object): """The command-line option that disables this diagnostic.""" disable = _CXString() conf.lib.clang_getDiagnosticOption(self, byref(disable)) - - return conf.lib.clang_getCString(disable) + return _CXString.from_result(disable) def format(self, options=None): """ @@ -418,8 +475,7 @@ class Diagnostic(object): options = conf.lib.clang_defaultDiagnosticDisplayOptions() if options & ~Diagnostic._FormatOptionsMask: raise ValueError('Invalid format options') - formatted = conf.lib.clang_formatDiagnostic(self, options) - return conf.lib.clang_getCString(formatted) + return conf.lib.clang_formatDiagnostic(self, options) def __repr__(self): return "<Diagnostic severity %r, location %r, spelling %r>" % ( @@ -596,7 +652,7 @@ class CursorKind(BaseEnumeration): @staticmethod def get_all_kinds(): """Return all CursorKind enumeration instances.""" - return filter(None, CursorKind._kinds) + return [x for x in CursorKind._kinds if not x is None] def is_declaration(self): """Test if this is a declaration kind.""" @@ -727,7 +783,7 @@ CursorKind.CONVERSION_FUNCTION = CursorKind(26) # A C++ template type parameter CursorKind.TEMPLATE_TYPE_PARAMETER = CursorKind(27) -# A C++ non-type template paramater. +# A C++ non-type template parameter. CursorKind.TEMPLATE_NON_TYPE_PARAMETER = CursorKind(28) # A C++ template template parameter. @@ -1312,6 +1368,30 @@ TemplateArgumentKind.DECLARATION = TemplateArgumentKind(2) TemplateArgumentKind.NULLPTR = TemplateArgumentKind(3) TemplateArgumentKind.INTEGRAL = TemplateArgumentKind(4) +### Exception Specification Kinds ### +class ExceptionSpecificationKind(BaseEnumeration): + """ + An ExceptionSpecificationKind describes the kind of exception specification + that a function has. + """ + + # The required BaseEnumeration declarations. + _kinds = [] + _name_map = None + + def __repr__(self): + return 'ExceptionSpecificationKind.{}'.format(self.name) + +ExceptionSpecificationKind.NONE = ExceptionSpecificationKind(0) +ExceptionSpecificationKind.DYNAMIC_NONE = ExceptionSpecificationKind(1) +ExceptionSpecificationKind.DYNAMIC = ExceptionSpecificationKind(2) +ExceptionSpecificationKind.MS_ANY = ExceptionSpecificationKind(3) +ExceptionSpecificationKind.BASIC_NOEXCEPT = ExceptionSpecificationKind(4) +ExceptionSpecificationKind.COMPUTED_NOEXCEPT = ExceptionSpecificationKind(5) +ExceptionSpecificationKind.UNEVALUATED = ExceptionSpecificationKind(6) +ExceptionSpecificationKind.UNINSTANTIATED = ExceptionSpecificationKind(7) +ExceptionSpecificationKind.UNPARSED = ExceptionSpecificationKind(8) + ### Cursors ### class Cursor(Structure): @@ -1399,6 +1479,11 @@ class Cursor(Structure): """ return conf.lib.clang_CXXMethod_isVirtual(self) + def is_scoped_enum(self): + """Returns True if the cursor refers to a scoped enum declaration. + """ + return conf.lib.clang_EnumDecl_isScoped(self) + def get_definition(self): """ If the cursor is a reference to a declaration or a declaration of @@ -1467,6 +1552,22 @@ class Cursor(Structure): return self._loc @property + def linkage(self): + """Return the linkage of this cursor.""" + if not hasattr(self, '_linkage'): + self._linkage = conf.lib.clang_getCursorLinkage(self) + + return LinkageKind.from_id(self._linkage) + + @property + def tls_kind(self): + """Return the thread-local storage (TLS) kind of this cursor.""" + if not hasattr(self, '_tls_kind'): + self._tls_kind = conf.lib.clang_getCursorTLSKind(self) + + return TLSKind.from_id(self._tls_kind) + + @property def extent(self): """ Return the source range (the range of text) occupied by the entity @@ -1489,6 +1590,16 @@ class Cursor(Structure): return StorageClass.from_id(self._storage_class) @property + def availability(self): + """ + Retrieves the availability of the entity pointed at by the cursor. + """ + if not hasattr(self, '_availability'): + self._availability = conf.lib.clang_getCursorAvailability(self) + + return AvailabilityKind.from_id(self._availability) + + @property def access_specifier(self): """ Retrieves the access specifier (if any) of the entity pointed at by the @@ -1532,6 +1643,18 @@ class Cursor(Structure): return self._result_type @property + def exception_specification_kind(self): + ''' + Retrieve the exception specification kind, which is one of the values + from the ExceptionSpecificationKind enumeration. + ''' + if not hasattr(self, '_exception_specification_kind'): + exc_kind = conf.lib.clang_getCursorExceptionSpecificationType(self) + self._exception_specification_kind = ExceptionSpecificationKind.from_id(exc_kind) + + return self._exception_specification_kind + + @property def underlying_typedef_type(self): """Return the underlying type of a typedef declaration. @@ -1813,6 +1936,24 @@ StorageClass.OPENCLWORKGROUPLOCAL = StorageClass(5) StorageClass.AUTO = StorageClass(6) StorageClass.REGISTER = StorageClass(7) +### Availability Kinds ### + +class AvailabilityKind(BaseEnumeration): + """ + Describes the availability of an entity. + """ + + # The unique kind objects, indexed by id. + _kinds = [] + _name_map = None + + def __repr__(self): + return 'AvailabilityKind.%s' % (self.name,) + +AvailabilityKind.AVAILABLE = AvailabilityKind(0) +AvailabilityKind.DEPRECATED = AvailabilityKind(1) +AvailabilityKind.NOT_AVAILABLE = AvailabilityKind(2) +AvailabilityKind.NOT_ACCESSIBLE = AvailabilityKind(3) ### C++ access specifiers ### @@ -1908,6 +2049,47 @@ TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116) TypeKind.MEMBERPOINTER = TypeKind(117) TypeKind.AUTO = TypeKind(118) TypeKind.ELABORATED = TypeKind(119) +TypeKind.PIPE = TypeKind(120) +TypeKind.OCLIMAGE1DRO = TypeKind(121) +TypeKind.OCLIMAGE1DARRAYRO = TypeKind(122) +TypeKind.OCLIMAGE1DBUFFERRO = TypeKind(123) +TypeKind.OCLIMAGE2DRO = TypeKind(124) +TypeKind.OCLIMAGE2DARRAYRO = TypeKind(125) +TypeKind.OCLIMAGE2DDEPTHRO = TypeKind(126) +TypeKind.OCLIMAGE2DARRAYDEPTHRO = TypeKind(127) +TypeKind.OCLIMAGE2DMSAARO = TypeKind(128) +TypeKind.OCLIMAGE2DARRAYMSAARO = TypeKind(129) +TypeKind.OCLIMAGE2DMSAADEPTHRO = TypeKind(130) +TypeKind.OCLIMAGE2DARRAYMSAADEPTHRO = TypeKind(131) +TypeKind.OCLIMAGE3DRO = TypeKind(132) +TypeKind.OCLIMAGE1DWO = TypeKind(133) +TypeKind.OCLIMAGE1DARRAYWO = TypeKind(134) +TypeKind.OCLIMAGE1DBUFFERWO = TypeKind(135) +TypeKind.OCLIMAGE2DWO = TypeKind(136) +TypeKind.OCLIMAGE2DARRAYWO = TypeKind(137) +TypeKind.OCLIMAGE2DDEPTHWO = TypeKind(138) +TypeKind.OCLIMAGE2DARRAYDEPTHWO = TypeKind(139) +TypeKind.OCLIMAGE2DMSAAWO = TypeKind(140) +TypeKind.OCLIMAGE2DARRAYMSAAWO = TypeKind(141) +TypeKind.OCLIMAGE2DMSAADEPTHWO = TypeKind(142) +TypeKind.OCLIMAGE2DARRAYMSAADEPTHWO = TypeKind(143) +TypeKind.OCLIMAGE3DWO = TypeKind(144) +TypeKind.OCLIMAGE1DRW = TypeKind(145) +TypeKind.OCLIMAGE1DARRAYRW = TypeKind(146) +TypeKind.OCLIMAGE1DBUFFERRW = TypeKind(147) +TypeKind.OCLIMAGE2DRW = TypeKind(148) +TypeKind.OCLIMAGE2DARRAYRW = TypeKind(149) +TypeKind.OCLIMAGE2DDEPTHRW = TypeKind(150) +TypeKind.OCLIMAGE2DARRAYDEPTHRW = TypeKind(151) +TypeKind.OCLIMAGE2DMSAARW = TypeKind(152) +TypeKind.OCLIMAGE2DARRAYMSAARW = TypeKind(153) +TypeKind.OCLIMAGE2DMSAADEPTHRW = TypeKind(154) +TypeKind.OCLIMAGE2DARRAYMSAADEPTHRW = TypeKind(155) +TypeKind.OCLIMAGE3DRW = TypeKind(156) +TypeKind.OCLSAMPLER = TypeKind(157) +TypeKind.OCLEVENT = TypeKind(158) +TypeKind.OCLQUEUE = TypeKind(159) +TypeKind.OCLRESERVEID = TypeKind(160) class RefQualifierKind(BaseEnumeration): """Describes a specific ref-qualifier of a type.""" @@ -1926,6 +2108,42 @@ RefQualifierKind.NONE = RefQualifierKind(0) RefQualifierKind.LVALUE = RefQualifierKind(1) RefQualifierKind.RVALUE = RefQualifierKind(2) +class LinkageKind(BaseEnumeration): + """Describes the kind of linkage of a cursor.""" + + # The unique kind objects, indexed by id. + _kinds = [] + _name_map = None + + def from_param(self): + return self.value + + def __repr__(self): + return 'LinkageKind.%s' % (self.name,) + +LinkageKind.INVALID = LinkageKind(0) +LinkageKind.NO_LINKAGE = LinkageKind(1) +LinkageKind.INTERNAL = LinkageKind(2) +LinkageKind.UNIQUE_EXTERNAL = LinkageKind(3) +LinkageKind.EXTERNAL = LinkageKind(4) + +class TLSKind(BaseEnumeration): + """Describes the kind of thread-local storage (TLS) of a cursor.""" + + # The unique kind objects, indexed by id. + _kinds = [] + _name_map = None + + def from_param(self): + return self.value + + def __repr__(self): + return 'TLSKind.%s' % (self.name,) + +TLSKind.NONE = TLSKind(0) +TLSKind.DYNAMIC = TLSKind(1) +TLSKind.STATIC = TLSKind(2) + class Type(Structure): """ The type of an element in the abstract syntax tree. @@ -2066,6 +2284,12 @@ class Type(Structure): return conf.lib.clang_isFunctionTypeVariadic(self) + def get_address_space(self): + return conf.lib.clang_getAddressSpace(self) + + def get_typedef_name(self): + return conf.lib.clang_getTypedefName(self) + def is_pod(self): """Determine whether this Type represents plain old data (POD).""" return conf.lib.clang_isPODType(self) @@ -2128,7 +2352,7 @@ class Type(Structure): """ Retrieve the offset of a field in the record. """ - return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname)) + return conf.lib.clang_Type_getOffsetOf(self, fieldname) def get_ref_qualifier(self): """ @@ -2152,6 +2376,14 @@ class Type(Structure): callbacks['fields_visit'](visitor), fields) return iter(fields) + def get_exception_specification_kind(self): + """ + Return the kind of the exception specification; a value from + the ExceptionSpecificationKind enumeration. + """ + return ExceptionSpecificationKind.from_id( + conf.lib.clang.getExceptionSpecificationType(self)) + @property def spelling(self): """Retrieve the spelling of this Type.""" @@ -2239,7 +2471,7 @@ class CompletionChunk: def spelling(self): if self.__kindNumber in SpellingCache: return SpellingCache[self.__kindNumber] - return conf.lib.clang_getCompletionChunkText(self.cs, self.key).spelling + return conf.lib.clang_getCompletionChunkText(self.cs, self.key) # We do not use @CachedProperty here, as the manual implementation is # apparently still significantly faster. Please profile carefully if you @@ -2345,7 +2577,7 @@ class CompletionString(ClangObject): return " | ".join([str(a) for a in self]) \ + " || Priority: " + str(self.priority) \ + " || Availability: " + str(self.availability) \ - + " || Brief comment: " + str(self.briefComment.spelling) + + " || Brief comment: " + str(self.briefComment) availabilityKinds = { 0: CompletionChunk.Kind("Available"), @@ -2542,7 +2774,7 @@ class TranslationUnit(ClangObject): args_array = None if len(args) > 0: - args_array = (c_char_p * len(args))(* args) + args_array = (c_char_p * len(args))(*[b(x) for x in args]) unsaved_array = None if len(unsaved_files) > 0: @@ -2551,8 +2783,8 @@ class TranslationUnit(ClangObject): if hasattr(contents, "read"): contents = contents.read() - unsaved_array[i].name = name - unsaved_array[i].contents = contents + unsaved_array[i].name = b(name) + unsaved_array[i].contents = b(contents) unsaved_array[i].length = len(contents) ptr = conf.lib.clang_parseTranslationUnit(index, filename, args_array, @@ -2797,8 +3029,8 @@ class TranslationUnit(ClangObject): print(value) if not isinstance(value, str): raise TypeError('Unexpected unsaved file contents.') - unsaved_files_array[i].name = name - unsaved_files_array[i].contents = value + unsaved_files_array[i].name = b(name) + unsaved_files_array[i].contents = b(value) unsaved_files_array[i].length = len(value) ptr = conf.lib.clang_codeCompleteAt(self, path, line, column, unsaved_files_array, len(unsaved_files), options) @@ -2833,7 +3065,7 @@ class File(ClangObject): @property def name(self): """Return the complete file and path name of the file.""" - return conf.lib.clang_getCString(conf.lib.clang_getFileName(self)) + return conf.lib.clang_getFileName(self) @property def time(self): @@ -3042,6 +3274,7 @@ class Token(Structure): def cursor(self): """The Cursor this Token corresponds to.""" cursor = Cursor() + cursor._tu = self._tu conf.lib.clang_annotateTokens(self._tu, byref(self), 1, byref(cursor)) @@ -3064,7 +3297,7 @@ functionList = [ [c_object_p]), ("clang_CompilationDatabase_fromDirectory", - [c_char_p, POINTER(c_uint)], + [c_interop_string, POINTER(c_uint)], c_object_p, CompilationDatabase.from_result), @@ -3074,7 +3307,7 @@ functionList = [ CompileCommands.from_result), ("clang_CompilationDatabase_getCompileCommands", - [c_object_p, c_char_p], + [c_object_p, c_interop_string], c_object_p, CompileCommands.from_result), @@ -3109,7 +3342,7 @@ functionList = [ c_uint), ("clang_codeCompleteAt", - [TranslationUnit, c_char_p, c_int, c_int, c_void_p, c_int, c_int], + [TranslationUnit, c_interop_string, c_int, c_int, c_void_p, c_int, c_int], POINTER(CCRStructure)), ("clang_codeCompleteGetDiagnostic", @@ -3125,7 +3358,7 @@ functionList = [ c_object_p), ("clang_createTranslationUnit", - [Index, c_char_p], + [Index, c_interop_string], c_object_p), ("clang_CXXConstructor_isConvertingConstructor", @@ -3168,6 +3401,10 @@ functionList = [ [Cursor], bool), + ("clang_EnumDecl_isScoped", + [Cursor], + bool), + ("clang_defaultDiagnosticDisplayOptions", [], c_uint), @@ -3215,7 +3452,8 @@ functionList = [ ("clang_formatDiagnostic", [Diagnostic, c_uint], - _CXString), + _CXString, + _CXString.from_result), ("clang_getArgType", [Type, c_uint], @@ -3255,7 +3493,8 @@ functionList = [ ("clang_getCompletionBriefComment", [c_void_p], - _CXString), + _CXString, + _CXString.from_result), ("clang_getCompletionChunkCompletionString", [c_void_p, c_int], @@ -3267,7 +3506,8 @@ functionList = [ ("clang_getCompletionChunkText", [c_void_p, c_int], - _CXString), + _CXString, + _CXString.from_result), ("clang_getCompletionPriority", [c_void_p], @@ -3275,12 +3515,17 @@ functionList = [ ("clang_getCString", [_CXString], - c_char_p), + c_interop_string, + c_interop_string.to_python_string), ("clang_getCursor", [TranslationUnit, SourceLocation], Cursor), + ("clang_getCursorAvailability", + [Cursor], + c_int), + ("clang_getCursorDefinition", [Cursor], Cursor, @@ -3422,12 +3667,13 @@ functionList = [ Type.from_result), ("clang_getFile", - [TranslationUnit, c_char_p], + [TranslationUnit, c_interop_string], c_object_p), ("clang_getFileName", [File], - _CXString), # TODO go through _CXString.from_result? + _CXString, + _CXString.from_result), ("clang_getFileTime", [File], @@ -3551,7 +3797,8 @@ functionList = [ ("clang_getTUResourceUsageName", [c_uint], - c_char_p), + c_interop_string, + c_interop_string.to_python_string), ("clang_getTypeDeclaration", [Type], @@ -3563,6 +3810,11 @@ functionList = [ Type, Type.from_result), + ("clang_getTypedefName", + [Type], + _CXString, + _CXString.from_result), + ("clang_getTypeKindSpelling", [c_uint], _CXString, @@ -3646,7 +3898,7 @@ functionList = [ bool), ("clang_parseTranslationUnit", - [Index, c_char_p, c_void_p, c_int, c_void_p, c_int, c_int], + [Index, c_interop_string, c_void_p, c_int, c_void_p, c_int, c_int], c_object_p), ("clang_reparseTranslationUnit", @@ -3654,7 +3906,7 @@ functionList = [ c_int), ("clang_saveTranslationUnit", - [TranslationUnit, c_char_p, c_uint], + [TranslationUnit, c_interop_string, c_uint], c_int), ("clang_tokenize", @@ -3726,7 +3978,7 @@ functionList = [ Type.from_result), ("clang_Type_getOffsetOf", - [Type, c_char_p], + [Type, c_interop_string], c_longlong), ("clang_Type_getSizeOf", @@ -3785,7 +4037,8 @@ def register_functions(lib, ignore_errors): def register(item): return register_function(lib, item, ignore_errors) - map(register, functionList) + for f in functionList: + register(f) class Config: library_path = None @@ -3888,6 +4141,7 @@ conf = Config() register_enumerations() __all__ = [ + 'AvailabilityKind', 'Config', 'CodeCompletionResults', 'CompilationDatabase', @@ -3899,8 +4153,10 @@ __all__ = [ 'File', 'FixIt', 'Index', + 'LinkageKind', 'SourceLocation', 'SourceRange', + 'TLSKind', 'TokenKind', 'Token', 'TranslationUnitLoadError', diff --git a/bindings/python/tests/cindex/test_cursor.py b/bindings/python/tests/cindex/test_cursor.py index 8103e96df4..8ff0695154 100644 --- a/bindings/python/tests/cindex/test_cursor.py +++ b/bindings/python/tests/cindex/test_cursor.py @@ -1,6 +1,7 @@ import ctypes import gc +from clang.cindex import AvailabilityKind from clang.cindex import CursorKind from clang.cindex import TemplateArgumentKind from clang.cindex import TranslationUnit @@ -255,6 +256,22 @@ def test_is_virtual_method(): assert foo.is_virtual_method() assert not bar.is_virtual_method() +def test_is_scoped_enum(): + """Ensure Cursor.is_scoped_enum works.""" + source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};' + tu = get_tu(source, lang='cpp') + + cls = get_cursor(tu, 'X') + regular_enum = get_cursor(tu, 'RegularEnum') + scoped_enum = get_cursor(tu, 'ScopedEnum') + assert cls is not None + assert regular_enum is not None + assert scoped_enum is not None + + assert not cls.is_scoped_enum() + assert not regular_enum.is_scoped_enum() + assert scoped_enum.is_scoped_enum() + def test_underlying_type(): tu = get_tu('typedef int foo;') typedef = get_cursor(tu, 'foo') @@ -361,6 +378,26 @@ def test_annotation_attribute(): else: assert False, "Couldn't find annotation" +def test_annotation_template(): + annotation = '__attribute__ ((annotate("annotation")))' + for source, kind in [ + ('int foo (T value) %s;', CursorKind.FUNCTION_TEMPLATE), + ('class %s foo {};', CursorKind.CLASS_TEMPLATE), + ]: + source = 'template<typename T> ' + (source % annotation) + tu = get_tu(source, lang="cpp") + + foo = get_cursor(tu, 'foo') + assert foo is not None + assert foo.kind == kind + + for c in foo.get_children(): + if c.kind == CursorKind.ANNOTATE_ATTR: + assert c.displayname == "annotation" + break + else: + assert False, "Couldn't find annotation for {}".format(kind) + def test_result_type(): tu = get_tu('int foo();') foo = get_cursor(tu, 'foo') @@ -369,6 +406,30 @@ def test_result_type(): t = foo.result_type assert t.kind == TypeKind.INT +def test_availability(): + tu = get_tu('class A { A(A const&) = delete; };', lang='cpp') + + # AvailabilityKind.AVAILABLE + cursor = get_cursor(tu, 'A') + assert cursor.kind == CursorKind.CLASS_DECL + assert cursor.availability == AvailabilityKind.AVAILABLE + + # AvailabilityKind.NOT_AVAILABLE + cursors = get_cursors(tu, 'A') + for c in cursors: + if c.kind == CursorKind.CONSTRUCTOR: + assert c.availability == AvailabilityKind.NOT_AVAILABLE + break + else: + assert False, "Could not find cursor for deleted constructor" + + # AvailabilityKind.DEPRECATED + tu = get_tu('void test() __attribute__((deprecated));', lang='cpp') + cursor = get_cursor(tu, 'test') + assert cursor.availability == AvailabilityKind.DEPRECATED + + # AvailabilityKind.NOT_ACCESSIBLE is only used in the code completion results + def test_get_tokens(): """Ensure we can map cursors back to tokens.""" tu = get_tu('int foo(int i);') @@ -379,6 +440,28 @@ def test_get_tokens(): assert tokens[0].spelling == 'int' assert tokens[1].spelling == 'foo' +def test_get_token_cursor(): + """Ensure we can map tokens to cursors.""" + tu = get_tu('class A {}; int foo(A var = A());', lang='cpp') + foo = get_cursor(tu, 'foo') + + for cursor in foo.walk_preorder(): + if cursor.kind.is_expression() and not cursor.kind.is_statement(): + break + else: + assert False, "Could not find default value expression" + + tokens = list(cursor.get_tokens()) + assert len(tokens) == 4, [t.spelling for t in tokens] + assert tokens[0].spelling == '=' + assert tokens[1].spelling == 'A' + assert tokens[2].spelling == '(' + assert tokens[3].spelling == ')' + t_cursor = tokens[1].cursor + assert t_cursor.kind == CursorKind.TYPE_REF + r_cursor = t_cursor.referenced # should not raise an exception + assert r_cursor.kind == CursorKind.CLASS_DECL + def test_get_arguments(): tu = get_tu('void foo(int i, int j);') foo = get_cursor(tu, 'foo') diff --git a/bindings/python/tests/cindex/test_diagnostics.py b/bindings/python/tests/cindex/test_diagnostics.py index ba6e545e8b..23cbe89f65 100644 --- a/bindings/python/tests/cindex/test_diagnostics.py +++ b/bindings/python/tests/cindex/test_diagnostics.py @@ -92,3 +92,11 @@ def test_diagnostic_children(): assert children[0].spelling.endswith('declared here') assert children[0].location.line == 1 assert children[0].location.column == 1 + +def test_diagnostic_string_repr(): + tu = get_tu('struct MissingSemicolon{}') + assert len(tu.diagnostics) == 1 + d = tu.diagnostics[0] + + assert repr(d) == '<Diagnostic severity 3, location <SourceLocation file \'t.c\', line 1, column 26>, spelling "expected \';\' after struct">' + diff --git a/bindings/python/tests/cindex/test_exception_specification_kind.py b/bindings/python/tests/cindex/test_exception_specification_kind.py new file mode 100644 index 0000000000..543d47f7db --- /dev/null +++ b/bindings/python/tests/cindex/test_exception_specification_kind.py @@ -0,0 +1,27 @@ +import clang.cindex +from clang.cindex import ExceptionSpecificationKind +from .util import get_tu + + +def find_function_declarations(node, declarations=[]): + if node.kind == clang.cindex.CursorKind.FUNCTION_DECL: + declarations.append((node.spelling, node.exception_specification_kind)) + for child in node.get_children(): + declarations = find_function_declarations(child, declarations) + return declarations + + +def test_exception_specification_kind(): + source = """int square1(int x); + int square2(int x) noexcept; + int square3(int x) noexcept(noexcept(x * x));""" + + tu = get_tu(source, lang='cpp', flags=['-std=c++14']) + + declarations = find_function_declarations(tu.cursor) + expected = [ + ('square1', ExceptionSpecificationKind.NONE), + ('square2', ExceptionSpecificationKind.BASIC_NOEXCEPT), + ('square3', ExceptionSpecificationKind.COMPUTED_NOEXCEPT) + ] + assert declarations == expected diff --git a/bindings/python/tests/cindex/test_index.py b/bindings/python/tests/cindex/test_index.py index dc173f04d2..ef76692a52 100644 --- a/bindings/python/tests/cindex/test_index.py +++ b/bindings/python/tests/cindex/test_index.py @@ -13,3 +13,5 @@ def test_parse(): assert isinstance(index, Index) tu = index.parse(os.path.join(kInputsDir, 'hello.cpp')) assert isinstance(tu, TranslationUnit) + tu = index.parse(None, ['-c', os.path.join(kInputsDir, 'hello.cpp')]) + assert isinstance(tu, TranslationUnit) diff --git a/bindings/python/tests/cindex/test_linkage.py b/bindings/python/tests/cindex/test_linkage.py new file mode 100644 index 0000000000..2f056d5140 --- /dev/null +++ b/bindings/python/tests/cindex/test_linkage.py @@ -0,0 +1,30 @@ + +from clang.cindex import LinkageKind +from clang.cindex import Cursor +from clang.cindex import TranslationUnit + +from .util import get_cursor +from .util import get_tu + +def test_linkage(): + """Ensure that linkage specifers are available on cursors""" + + tu = get_tu(""" +void foo() { int no_linkage; } +static int internal; +namespace { extern int unique_external; } +extern int external; +""", lang = 'cpp') + + no_linkage = get_cursor(tu.cursor, 'no_linkage') + assert no_linkage.linkage == LinkageKind.NO_LINKAGE; + + internal = get_cursor(tu.cursor, 'internal') + assert internal.linkage == LinkageKind.INTERNAL + + unique_external = get_cursor(tu.cursor, 'unique_external') + assert unique_external.linkage == LinkageKind.UNIQUE_EXTERNAL + + external = get_cursor(tu.cursor, 'external') + assert external.linkage == LinkageKind.EXTERNAL + diff --git a/bindings/python/tests/cindex/test_tls_kind.py b/bindings/python/tests/cindex/test_tls_kind.py new file mode 100644 index 0000000000..6a03c0d5ee --- /dev/null +++ b/bindings/python/tests/cindex/test_tls_kind.py @@ -0,0 +1,37 @@ + +from clang.cindex import TLSKind +from clang.cindex import Cursor +from clang.cindex import TranslationUnit + +from .util import get_cursor +from .util import get_tu + +def test_tls_kind(): + """Ensure that thread-local storage kinds are available on cursors.""" + + tu = get_tu(""" +int tls_none; +thread_local int tls_dynamic; +_Thread_local int tls_static; +""", lang = 'cpp') + + tls_none = get_cursor(tu.cursor, 'tls_none') + assert tls_none.tls_kind == TLSKind.NONE; + + tls_dynamic = get_cursor(tu.cursor, 'tls_dynamic') + assert tls_dynamic.tls_kind == TLSKind.DYNAMIC + + tls_static = get_cursor(tu.cursor, 'tls_static') + assert tls_static.tls_kind == TLSKind.STATIC + + # The following case tests '__declspec(thread)'. Since it is a Microsoft + # specific extension, specific flags are required for the parser to pick + # these up. + flags = ['-fms-extensions', '-target', 'x86_64-unknown-windows-win32'] + tu = get_tu(""" +__declspec(thread) int tls_declspec; +""", lang = 'cpp', flags=flags) + + tls_declspec = get_cursor(tu.cursor, 'tls_declspec') + assert tls_declspec.tls_kind == TLSKind.STATIC + diff --git a/bindings/python/tests/cindex/test_translation_unit.py b/bindings/python/tests/cindex/test_translation_unit.py index be6cd671ae..65d1ee02ff 100644 --- a/bindings/python/tests/cindex/test_translation_unit.py +++ b/bindings/python/tests/cindex/test_translation_unit.py @@ -59,9 +59,12 @@ int SOME_DEFINE; assert spellings[-1] == 'y' def test_unsaved_files_2(): - import StringIO + try: + from StringIO import StringIO + except: + from io import StringIO tu = TranslationUnit.from_source('fake.c', unsaved_files = [ - ('fake.c', StringIO.StringIO('int x;'))]) + ('fake.c', StringIO('int x;'))]) spellings = [c.spelling for c in tu.cursor.get_children()] assert spellings[-1] == 'x' diff --git a/bindings/python/tests/cindex/test_type.py b/bindings/python/tests/cindex/test_type.py index f2184338be..6ee0773828 100644 --- a/bindings/python/tests/cindex/test_type.py +++ b/bindings/python/tests/cindex/test_type.py @@ -37,37 +37,44 @@ def test_a_struct(): 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].type.get_typedef_name() == '' 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].type.get_typedef_name() == '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].type.get_typedef_name() == '' 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].type.get_typedef_name() == '' 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].type.get_typedef_name() == '' 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].type.get_typedef_name() == '' 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[6].type.get_typedef_name() == '' assert fields[7].spelling == 'h' assert not fields[7].type.is_const_qualified() @@ -75,6 +82,7 @@ def test_a_struct(): 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 + assert fields[7].type.get_typedef_name() == '' def test_references(): """Ensure that a Type maintains a reference to a TranslationUnit.""" @@ -404,3 +412,12 @@ def test_decay(): assert a.kind == TypeKind.INCOMPLETEARRAY assert a.element_type.kind == TypeKind.INT assert a.get_canonical().kind == TypeKind.INCOMPLETEARRAY + +def test_addrspace(): + """Ensure the address space can be queried""" + tu = get_tu('__attribute__((address_space(2))) int testInteger = 3;', 'c') + + testInteger = get_cursor(tu, 'testInteger') + + assert testInteger is not None, "Could not find testInteger." + assert testInteger.type.get_address_space() == 2 |