Commits

Anonymous committed 5445bce

Update test to https://llvm.org/svn/llvm-project/cfe/trunk@21148291177308-0d34-0410-b5e6-96231b3b80d8.

A few tests are modified to work with Clang 3.4, which is the latest shipped on
Ubuntu 14.04. These are marked with a comment (grep for Clang 3.4)

Comments (0)

Files changed (8)

     def __ne__(self, other):
         return not self.__eq__(other)
 
+    def __contains__(self, other):
+        """Useful to detect the Token/Lexer bug"""
+        if not isinstance(other, SourceLocation):
+            return False
+        if other.file is None and self.start.file is None:
+            pass
+        elif ( self.start.file.name != other.file.name or
+               other.file.name != self.end.file.name):
+            # same file name
+            return False
+        # same file, in between lines
+        if self.start.line < other.line < self.end.line:
+            return True
+        elif self.start.line == other.line:
+            # same file first line
+            if self.start.column <= other.column:
+                return True
+        elif other.line == self.end.line:
+            # same file last line
+            if other.column <= self.end.column:
+                return True
+        return False
+
     def __repr__(self):
         return "<SourceRange start %r, end %r>" % (self.start, self.end)
 
 
     @property
     def category_number(self):
-        """The category number for this diagnostic."""
+        """The category number for this diagnostic or 0 if unavailable."""
         return conf.lib.clang_getDiagnosticCategory(self)
 
     @property
     def category_name(self):
         """The string name of the category for this diagnostic."""
-        return conf.lib.clang_getDiagnosticCategoryName(self.category_number)
+        return conf.lib.clang_getDiagnosticCategoryText(self)
 
     @property
     def option(self):
         """Get the enumeration name of this cursor kind."""
         if self._name_map is None:
             self._name_map = {}
-            for key,value in list(CursorKind.__dict__.items()):
+            for key,value in CursorKind.__dict__.items():
                 if isinstance(value,CursorKind):
                     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')
+            raise ValueError('Unknown cursor kind %d' % id)
         return CursorKind._kinds[id]
 
     @staticmethod
     def get_all_kinds():
         """Return all CursorKind enumeration instances."""
-        return [_f for _f in CursorKind._kinds if _f]
+        return list (filter(None, CursorKind._kinds))
 
     def is_declaration(self):
         """Test if this is a declaration kind."""
 # A reference to a labeled statement.
 CursorKind.LABEL_REF = CursorKind(48)
 
-# A reference toa a set of overloaded functions or function templates
+# A reference to a set of overloaded functions or function templates
 # that has not yet been resolved to a specific function or function template.
 CursorKind.OVERLOADED_DECL_REF = CursorKind(49)
 
+# A reference to a variable that occurs in some non-expression
+# context, e.g., a C++ lambda capture list.
+CursorKind.VARIABLE_REF = CursorKind(50)
+
 ###
 # Invalid/Error Kinds
 
 # pack.
 CursorKind.SIZE_OF_PACK_EXPR = CursorKind(143)
 
+# Represents a C++ lambda expression that produces a local function
+# object.
+#
+#  \code
+#  void abssort(float *x, unsigned N) {
+#    std::sort(x, x + N,
+#              [](float a, float b) {
+#                return std::abs(a) < std::abs(b);
+#              });
+#  }
+#  \endcode
+CursorKind.LAMBDA_EXPR = CursorKind(144)
+
+# Objective-c Boolean Literal.
+CursorKind.OBJ_BOOL_LITERAL_EXPR = CursorKind(145)
+
+# Represents the "self" expression in a ObjC method.
+CursorKind.OBJ_SELF_EXPR = CursorKind(146)
+
+
 # A statement whose specific kind is not exposed via this interface.
 #
 # Unexposed statements have the same operations as any other kind of statement;
 # Windows Structured Exception Handling's finally statement.
 CursorKind.SEH_FINALLY_STMT = CursorKind(228)
 
+# A MS inline assembly statement extension.
+CursorKind.MS_ASM_STMT = CursorKind(229)
+
 # The null statement.
 CursorKind.NULL_STMT = CursorKind(230)
 
 CursorKind.CXX_OVERRIDE_ATTR = CursorKind(405)
 CursorKind.ANNOTATE_ATTR = CursorKind(406)
 CursorKind.ASM_LABEL_ATTR = CursorKind(407)
+CursorKind.PACKED_ATTR = CursorKind(408)
+CursorKind.PURE_ATTR = CursorKind(409)
+CursorKind.CONST_ATTR = CursorKind(410)
+CursorKind.NODUPLICATE_ATTR = CursorKind(411)
+CursorKind.CUDACONSTANT_ATTR = CursorKind(412)
+CursorKind.CUDADEVICE_ATTR = CursorKind(413)
+CursorKind.CUDAGLOBAL_ATTR = CursorKind(414)
+CursorKind.CUDAHOST_ATTR = CursorKind(415)
 
 ###
 # Preprocessing
 CursorKind.MACRO_INSTANTIATION = CursorKind(502)
 CursorKind.INCLUSION_DIRECTIVE = CursorKind(503)
 
+###
+# Extra declaration
+
+# A module import declaration.
+CursorKind.MODULE_IMPORT_DECL = CursorKind(600)
+
 ### Cursors ###
 
 class Cursor(Structure):
     @property
     def spelling(self):
         """Return the spelling of the entity pointed at by the cursor."""
-        if not self.kind.is_declaration():
-            # FIXME: clang_getCursorSpelling should be fixed to not assert on
-            # this, for consistency with clang_getCursorUSR.
-            return None
         if not hasattr(self, '_spelling'):
             self._spelling = conf.lib.clang_getCursorSpelling(self)
 
         return self._extent
 
     @property
+    def access_specifier(self):
+        """
+        Retrieves the access specifier (if any) of the entity pointed at by the
+        cursor.
+        """
+        if not hasattr(self, '_access_specifier'):
+            self._access_specifier = conf.lib.clang_getCXXAccessSpecifier(self)
+
+        return AccessSpecifier.from_id(self._access_specifier)
+
+    @property
     def type(self):
         """
         Retrieve the Type (if any) of the entity pointed at by the cursor.
 
         return self._referenced
 
+    @property
+    def brief_comment(self):
+        """Returns the brief comment text associated with that Cursor"""
+        return conf.lib.clang_Cursor_getBriefCommentText(self)
+
+    @property
+    def raw_comment(self):
+        """Returns the raw comment text associated with that Cursor"""
+        return conf.lib.clang_Cursor_getRawCommentText(self)
+
     def get_arguments(self):
         """Return an iterator for accessing the arguments of this cursor."""
         num_args = conf.lib.clang_Cursor_getNumArguments(self)
             children)
         return iter(children)
 
+    def walk_preorder(self):
+        """Depth-first preorder walk over the cursor and its descendants.
+
+        Yields cursors.
+        """
+        yield self
+        for child in self.get_children():
+            for descendant in child.walk_preorder():
+                yield descendant
+
     def get_tokens(self):
         """Obtain Token instances formulating that compose this Cursor.
 
         res._tu = args[0]._tu
         return res
 
+### C++ access specifiers ###
+
+class AccessSpecifier:
+    """
+    Describes the access of a C++ class member
+    """
+
+    # The unique kind objects, index by id.
+    _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,)
+
+AccessSpecifier.INVALID = AccessSpecifier(0)
+AccessSpecifier.PUBLIC = AccessSpecifier(1)
+AccessSpecifier.PROTECTED = AccessSpecifier(2)
+AccessSpecifier.PRIVATE = AccessSpecifier(3)
+AccessSpecifier.NONE = AccessSpecifier(4)
+
 ### Type Kinds ###
 
 class TypeKind(object):
         """Get the enumeration name of this cursor kind."""
         if self._name_map is None:
             self._name_map = {}
-            for key,value in list(TypeKind.__dict__.items()):
+            for key,value in TypeKind.__dict__.items():
                 if isinstance(value,TypeKind):
                     self._name_map[value] = key
         return self._name_map[self]
 TypeKind.FUNCTIONPROTO = TypeKind(111)
 TypeKind.CONSTANTARRAY = TypeKind(112)
 TypeKind.VECTOR = TypeKind(113)
+TypeKind.INCOMPLETEARRAY = TypeKind(114)
+TypeKind.VARIABLEARRAY = TypeKind(115)
+TypeKind.DEPENDENTSIZEDARRAY = TypeKind(116)
+TypeKind.MEMBERPOINTER = TypeKind(117)
+
+class RefQualifierKind:
+    """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,)
+
+RefQualifierKind.NONE = RefQualifierKind(0)
+RefQualifierKind.LVALUE = RefQualifierKind(1)
+RefQualifierKind.RVALUE = RefQualifierKind(2)
 
 class Type(Structure):
     """
         """
         return conf.lib.clang_getArraySize(self)
 
+    def get_class_type(self):
+        """
+        Retrieve the class type of the member pointer type.
+        """
+        return conf.lib.clang_Type_getClassType(self)
+
     def get_align(self):
         """
         Retrieve the alignment of the record.
         """
         Retrieve the offset of a field in the record.
         """
-        return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname.encode('utf-8')))
+        return conf.lib.clang_Type_getOffsetOf(self, c_char_p(fieldname.encode ('utf-8')))
+
+    def get_ref_qualifier(self):
+        """
+        Retrieve the ref-qualifier of the type.
+        """
+        return RefQualifierKind.from_id(
+                conf.lib.clang_Type_getCXXRefQualifier(self))
+
+    @property
+    def spelling(self):
+        """Retrieve the spelling of this Type."""
+        return conf.lib.clang_getTypeSpelling(self)
 
     def __eq__(self, other):
         if type(other) != type(self):
             # 5 : CompletionChunk.Kind("CurrentParameter"),
             6: '(',   # CompletionChunk.Kind("LeftParen"),
             7: ')',   # CompletionChunk.Kind("RightParen"),
-            8: ']',   # CompletionChunk.Kind("LeftBracket"),
+            8: '[',   # CompletionChunk.Kind("LeftBracket"),
             9: ']',   # CompletionChunk.Kind("RightBracket"),
             10: '{',  # CompletionChunk.Kind("LeftBrace"),
             11: '}',  # CompletionChunk.Kind("RightBrace"),
             return "<Availability: %s>" % self
 
     def __len__(self):
-        self.num_chunks
+        return self.num_chunks
 
     @CachedProperty
     def num_chunks(self):
 
     def read(self, path):
         """Load a TranslationUnit from the given AST file."""
-        return TranslationUnit.from_ast(path, self)
+        return TranslationUnit.from_ast_file(path, self)
 
     def parse(self, path, args=None, unsaved_files=None, options = 0):
         """Load the translation unit from the given source code file by running
     constants in this class.
     """
 
-    # An unknown error occured
+    # An unknown error occurred
     ERROR_UNKNOWN = 0
 
     # The database could not be loaded
         return conf.lib.clang_CompilationDatabase_getCompileCommands(self,
                                                                      filename.encode ('utf-8'))
 
+    def getAllCompileCommands(self):
+        """
+        Get an iterable object providing all the CompileCommands available from
+        the database.
+        """
+        return conf.lib.clang_CompilationDatabase_getAllCompileCommands(self)
+
+
 class Token(Structure):
     """Represents a single token from the preprocessor.
 
    c_object_p,
    CompilationDatabase.from_result),
 
+  ("clang_CompilationDatabase_getAllCompileCommands",
+   [c_object_p],
+   c_object_p,
+   CompileCommands.from_result),
+
   ("clang_CompilationDatabase_getCompileCommands",
    [c_object_p, c_char_p],
    c_object_p,
    [Index, c_char_p],
    c_object_p),
 
+  ("clang_CXXMethod_isPureVirtual",
+   [Cursor],
+   bool),
+
   ("clang_CXXMethod_isStatic",
    [Cursor],
    bool),
    [Diagnostic],
    c_uint),
 
-  ("clang_getDiagnosticCategoryName",
-   [c_uint],
+  ("clang_getDiagnosticCategoryText",
+   [Diagnostic],
    _CXString,
    _CXString.from_result),
 
    _CXString,
    _CXString.from_result),
 
+  ("clang_getTypeSpelling",
+   [Type],
+   _CXString,
+   _CXString.from_result),
+
   ("clang_hashCursor",
    [Cursor],
    c_uint),
    [Cursor],
    bool),
 
+  ("clang_Cursor_getBriefCommentText",
+   [Cursor],
+   _CXString,
+   _CXString.from_result),
+
+  ("clang_Cursor_getRawCommentText",
+   [Cursor],
+   _CXString,
+   _CXString.from_result),
+
   ("clang_Type_getAlignOf",
    [Type],
    c_longlong),
 
+  ("clang_Type_getClassType",
+   [Type],
+   Type,
+   Type.from_result),
+
   ("clang_Type_getOffsetOf",
    [Type, c_char_p],
    c_longlong),
 
   ("clang_Type_getSizeOf",
    [Type],
-   c_ulonglong),
+   c_longlong),
+
+  ("clang_Type_getCXXRefQualifier",
+   [Type],
+   c_uint),
 ]
 
 class LibclangError(Exception):
     def register(item):
         return register_function(lib, item, ignore_errors)
 
-    list(map(register, functionList))
+    for function in functionList:
+        register (function)
 
 class Config:
     library_path = None
         python bindings can disable the compatibility check. This will cause
         the python bindings to load, even though they are written for a newer
         version of libclang. Failures now arise if unsupported or incompatible
-        features are accessed. The user is required to test himself if the
-        features he is using are available and compatible between different
+        features are accessed. The user is required to test themselves if the
+        features they are using are available and compatible between different
         libclang versions.
         """
         if Config.loaded:

tests/cindex/test_cdb.py

     cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
     assert len(cmds) != 0
 
+def test_all_compilecommand():
+    """Check we get all results from the db"""
+    cdb = CompilationDatabase.fromDirectory(kInputsDir)
+    cmds = cdb.getAllCompileCommands()
+    assert len(cmds) == 3
+    expected = [
+        { 'wd': '/home/john.doe/MyProjectA',
+          'line': ['clang++', '-o', 'project2.o', '-c',
+                   '/home/john.doe/MyProject/project2.cpp']},
+        { 'wd': '/home/john.doe/MyProjectB',
+          'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c',
+                   '/home/john.doe/MyProject/project2.cpp']},
+        { 'wd': '/home/john.doe/MyProject',
+          'line': ['clang++', '-o', 'project.o', '-c',
+                   '/home/john.doe/MyProject/project.cpp']}
+        ]
+    for i in range(len(cmds)):
+        assert cmds[i].directory == expected[i]['wd']
+        for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
+            assert arg == exp
+
 def test_1_compilecommand():
     """Check file with single compile command"""
     cdb = CompilationDatabase.fromDirectory(kInputsDir)

tests/cindex/test_code_completion.py

     completions = [str(c) for c in cr.results]
 
     for c in expected:
-        print(c, completions)
         assert c in completions
 
 def test_code_complete():

tests/cindex/test_cursor.py

 from .util import get_tu
 
 kInput = """\
-// FIXME: Find nicer way to drop builtins and other cruft.
-int start_decl;
-
 struct s0 {
   int a;
   int b;
 def test_get_children():
     tu = get_tu(kInput)
 
-    # Skip until past start_decl.
     it = tu.cursor.get_children()
-    while next(it).spelling != 'start_decl':
-        pass
+    tu_nodes = list(it)
 
-    tu_nodes = list(it)
+    # In Clang 3.4, the first three nodes are __int128_t, __uint128_t and
+    # __builtin_va_list
+    tu_nodes = tu_nodes [3:]
 
     assert len(tu_nodes) == 3
     for cursor in tu_nodes:
     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.line == 1
     assert tu_nodes[0].location.column == 8
     assert tu_nodes[0].hash > 0
     assert tu_nodes[0].translation_unit is not None

tests/cindex/test_cursor_kind.py

     assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL'
 
 def test_get_all_kinds():
-    assert CursorKind.UNEXPOSED_DECL in CursorKind.get_all_kinds()
-    assert CursorKind.TRANSLATION_UNIT in CursorKind.get_all_kinds()
+    kinds = CursorKind.get_all_kinds()
+    assert CursorKind.UNEXPOSED_DECL in kinds
+    assert CursorKind.TRANSLATION_UNIT in kinds
+    assert CursorKind.VARIABLE_REF in kinds
+    assert CursorKind.LAMBDA_EXPR in kinds
+    assert CursorKind.OBJ_BOOL_LITERAL_EXPR in kinds
+    assert CursorKind.OBJ_SELF_EXPR in kinds
+    assert CursorKind.MS_ASM_STMT in kinds
+    assert CursorKind.MODULE_IMPORT_DECL in kinds
 
 def test_kind_groups():
     """Check that every kind classifies to exactly one group."""
                              'is_statement', 'is_invalid', 'is_attribute')
                  if getattr(k, n)()]
 
+        # _ATTR not supported in Clang 3.4
+        if k.value >= 400 and k.value < 500:
+            continue
+
         if k in (   CursorKind.TRANSLATION_UNIT,
                     CursorKind.MACRO_DEFINITION,
                     CursorKind.MACRO_INSTANTIATION,
                     CursorKind.PREPROCESSING_DIRECTIVE):
             assert len(group) == 0
         else:
+            if len(group) != 1:
+                print (k)
             assert len(group) == 1

tests/cindex/test_translation_unit.py

 import gc
 import os
+import tempfile
 
 from clang.cindex import CursorKind
 from clang.cindex import Cursor
 
     Returns the filename it was saved to.
     """
-
-    # FIXME Generate a temp file path using system APIs.
-    base = 'TEMP_FOR_TRANSLATIONUNIT_SAVE.c'
-    path = os.path.join(kInputsDir, base)
-
-    # Just in case.
-    if os.path.exists(path):
-        os.unlink(path)
-
+    _, path = tempfile.mkstemp()
     tu.save(path)
 
     return path

tests/cindex/test_type.py

     assert a.type != None
     assert a.type != 'foo'
 
+def test_type_spelling():
+    """Ensure Type.spelling works."""
+    tu = get_tu('int c[5]; int i[]; int x; int v[x];')
+    c = get_cursor(tu, 'c')
+    i = get_cursor(tu, 'i')
+    x = get_cursor(tu, 'x')
+    v = get_cursor(tu, 'v')
+    assert c is not None
+    assert i is not None
+    assert x is not None
+    assert v is not None
+    assert c.type.spelling == "int [5]"
+    assert i.type.spelling == "int []"
+    assert x.type.spelling == "int"
+    assert v.type.spelling == "int [x]"
+
 def test_typekind_spelling():
     """Ensure TypeKind.spelling works."""
     tu = get_tu('int a;')
 
 def test_element_type():
     """Ensure Type.element_type works."""
-    tu = get_tu('int i[5];')
+    tu = get_tu('int c[5]; int i[]; int x; int v[x];')
+    c = get_cursor(tu, 'c')
     i = get_cursor(tu, 'i')
+    v = get_cursor(tu, 'v')
+    assert c is not None
     assert i is not None
+    assert v is not None
 
-    assert i.type.kind == TypeKind.CONSTANTARRAY
+    assert c.type.kind == TypeKind.CONSTANTARRAY
+    assert c.type.element_type.kind == TypeKind.INT
+    assert i.type.kind == TypeKind.INCOMPLETEARRAY
     assert i.type.element_type.kind == TypeKind.INT
+    assert v.type.kind == TypeKind.VARIABLEARRAY
+    assert v.type.element_type.kind == TypeKind.INT
 
 @raises(Exception)
 def test_invalid_element_type():
         assert teststruct.type.get_offset("bar") == bar
 
 
+def test_decay():
+    """Ensure decayed types are handled as the original type"""
+
+    tu = get_tu("void foo(int a[]);")
+    foo = get_cursor(tu, 'foo')
+    a = foo.type.argument_types()[0]
+
+    assert a.kind == TypeKind.INCOMPLETEARRAY
+    assert a.element_type.kind == TypeKind.INT
+    assert a.get_canonical().kind == TypeKind.INCOMPLETEARRAY

tests/cindex/util.py

 
     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()
+    # Convenience for calling on a TU.
+    root_cursor = source if isinstance(source, Cursor) else source.cursor
 
-    for cursor in children:
+    for cursor in root_cursor.walk_preorder():
         if cursor.spelling == spelling:
             return cursor
 
-        # Recurse into children.
-        result = get_cursor(cursor, spelling)
-        if result is not None:
-            return result
+    return None
 
-    return None
- 
 def get_cursors(source, spelling):
     """Obtain all cursors from a source object with a specific spelling.
 
-    This provides a convenient search mechanism to find all cursors with specific
-    spelling within a source. The first argument can be either a
+    This provides a convenient search mechanism to find all cursors with
+    specific spelling within a source. The first argument can be either a
     TranslationUnit or Cursor instance.
 
     If no cursors are found, an empty list is returned.
     """
+    # Convenience for calling on a TU.
+    root_cursor = source if isinstance(source, Cursor) else source.cursor
+
     cursors = []
-    children = []
-    if isinstance(source, Cursor):
-        children = source.get_children()
-    else:
-        # Assume TU
-        children = source.cursor.get_children()
-
-    for cursor in children:
+    for cursor in root_cursor.walk_preorder():
         if cursor.spelling == spelling:
             cursors.append(cursor)
 
-        # Recurse into children.
-        cursors.extend(get_cursors(cursor, spelling))
-
     return cursors
 
-    
-    
 
 __all__ = [
     'get_cursor',