summaryrefslogtreecommitdiffstats
path: root/gnu/llvm/tools/clang/bindings/python/tests
diff options
context:
space:
mode:
authorpascal <pascal@openbsd.org>2016-09-03 22:46:54 +0000
committerpascal <pascal@openbsd.org>2016-09-03 22:46:54 +0000
commitb5500b9ca0102f1ccaf32f0e77e96d0739aded9b (patch)
treee1b7ebb5a0231f9e6d8d3f6f719582cebd64dc98 /gnu/llvm/tools/clang/bindings/python/tests
parentclarify purpose of src/gnu/ directory. (diff)
downloadwireguard-openbsd-b5500b9ca0102f1ccaf32f0e77e96d0739aded9b.tar.xz
wireguard-openbsd-b5500b9ca0102f1ccaf32f0e77e96d0739aded9b.zip
Use the space freed up by sparc and zaurus to import LLVM.
ok hackroom@
Diffstat (limited to 'gnu/llvm/tools/clang/bindings/python/tests')
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/__init__.py0
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/compile_commands.json17
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header1.h6
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header2.h6
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header3.h3
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/hello.cpp6
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/include.cpp5
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/parse_arguments.c2
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/__init__.py0
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_access_specifiers.py34
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cdb.py110
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_code_completion.py75
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_comment.py40
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cursor.py372
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cursor_kind.py48
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_diagnostics.py82
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_file.py9
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_index.py15
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_location.py95
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_token_kind.py43
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_tokens.py52
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_translation_unit.py251
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/test_type.py406
-rw-r--r--gnu/llvm/tools/clang/bindings/python/tests/cindex/util.py75
24 files changed, 1752 insertions, 0 deletions
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/__init__.py b/gnu/llvm/tools/clang/bindings/python/tests/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/__init__.py
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/compile_commands.json b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/compile_commands.json
new file mode 100644
index 00000000000..944150bf7ba
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/compile_commands.json
@@ -0,0 +1,17 @@
+[
+{
+ "directory": "/home/john.doe/MyProject",
+ "command": "clang++ -o project.o -c /home/john.doe/MyProject/project.cpp",
+ "file": "/home/john.doe/MyProject/project.cpp"
+},
+{
+ "directory": "/home/john.doe/MyProjectA",
+ "command": "clang++ -o project2.o -c /home/john.doe/MyProject/project2.cpp",
+ "file": "/home/john.doe/MyProject/project2.cpp"
+},
+{
+ "directory": "/home/john.doe/MyProjectB",
+ "command": "clang++ -DFEATURE=1 -o project2-feature.o -c /home/john.doe/MyProject/project2.cpp",
+ "file": "/home/john.doe/MyProject/project2.cpp"
+}
+]
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header1.h b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header1.h
new file mode 100644
index 00000000000..b4eacbee375
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header1.h
@@ -0,0 +1,6 @@
+#ifndef HEADER1
+#define HEADER1
+
+#include "header3.h"
+
+#endif
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header2.h b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header2.h
new file mode 100644
index 00000000000..c4eddc0c562
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header2.h
@@ -0,0 +1,6 @@
+#ifndef HEADER2
+#define HEADER2
+
+#include "header3.h"
+
+#endif
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header3.h b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header3.h
new file mode 100644
index 00000000000..6dca764860e
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/header3.h
@@ -0,0 +1,3 @@
+// Not a guarded header!
+
+void f();
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/hello.cpp b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/hello.cpp
new file mode 100644
index 00000000000..7ef086e56b2
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/hello.cpp
@@ -0,0 +1,6 @@
+#include "stdio.h"
+
+int main(int argc, char* argv[]) {
+ printf("hello world\n");
+ return 0;
+}
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/include.cpp b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/include.cpp
new file mode 100644
index 00000000000..60cfdaae4d0
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/include.cpp
@@ -0,0 +1,5 @@
+#include "header1.h"
+#include "header2.h"
+#include "header1.h"
+
+int main() { }
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/parse_arguments.c b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/parse_arguments.c
new file mode 100644
index 00000000000..7196486c78a
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/INPUTS/parse_arguments.c
@@ -0,0 +1,2 @@
+int DECL_ONE = 1;
+int DECL_TWO = 2;
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/__init__.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/__init__.py
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_access_specifiers.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_access_specifiers.py
new file mode 100644
index 00000000000..cfa04dc8657
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_access_specifiers.py
@@ -0,0 +1,34 @@
+
+from clang.cindex import AccessSpecifier
+from clang.cindex import Cursor
+from clang.cindex import TranslationUnit
+
+from .util import get_cursor
+from .util import get_tu
+
+def test_access_specifiers():
+ """Ensure that C++ access specifiers are available on cursors"""
+
+ tu = get_tu("""
+class test_class {
+public:
+ void public_member_function();
+protected:
+ void protected_member_function();
+private:
+ void private_member_function();
+};
+""", lang = 'cpp')
+
+ test_class = get_cursor(tu, "test_class")
+ assert test_class.access_specifier == AccessSpecifier.INVALID;
+
+ public = get_cursor(tu.cursor, "public_member_function")
+ assert public.access_specifier == AccessSpecifier.PUBLIC
+
+ protected = get_cursor(tu.cursor, "protected_member_function")
+ assert protected.access_specifier == AccessSpecifier.PROTECTED
+
+ private = get_cursor(tu.cursor, "private_member_function")
+ assert private.access_specifier == AccessSpecifier.PRIVATE
+
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cdb.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cdb.py
new file mode 100644
index 00000000000..e1f824f797f
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cdb.py
@@ -0,0 +1,110 @@
+from clang.cindex import CompilationDatabase
+from clang.cindex import CompilationDatabaseError
+from clang.cindex import CompileCommands
+from clang.cindex import CompileCommand
+import os
+import gc
+
+kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
+
+def test_create_fail():
+ """Check we fail loading a database with an assertion"""
+ path = os.path.dirname(__file__)
+ try:
+ cdb = CompilationDatabase.fromDirectory(path)
+ except CompilationDatabaseError as e:
+ assert e.cdb_error == CompilationDatabaseError.ERROR_CANNOTLOADDATABASE
+ else:
+ assert False
+
+def test_create():
+ """Check we can load a compilation database"""
+ cdb = CompilationDatabase.fromDirectory(kInputsDir)
+
+def test_lookup_fail():
+ """Check file lookup failure"""
+ cdb = CompilationDatabase.fromDirectory(kInputsDir)
+ assert cdb.getCompileCommands('file_do_not_exist.cpp') == None
+
+def test_lookup_succeed():
+ """Check we get some results if the file exists in the db"""
+ cdb = CompilationDatabase.fromDirectory(kInputsDir)
+ 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)
+ cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
+ assert len(cmds) == 1
+ assert cmds[0].directory == '/home/john.doe/MyProject'
+ expected = [ 'clang++', '-o', 'project.o', '-c',
+ '/home/john.doe/MyProject/project.cpp']
+ for arg, exp in zip(cmds[0].arguments, expected):
+ assert arg == exp
+
+def test_2_compilecommand():
+ """Check file with 2 compile commands"""
+ cdb = CompilationDatabase.fromDirectory(kInputsDir)
+ cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp')
+ assert len(cmds) == 2
+ 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']}
+ ]
+ 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_compilecommand_iterator_stops():
+ """Check that iterator stops after the correct number of elements"""
+ cdb = CompilationDatabase.fromDirectory(kInputsDir)
+ count = 0
+ for cmd in cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp'):
+ count += 1
+ assert count <= 2
+
+def test_compilationDB_references():
+ """Ensure CompilationsCommands are independent of the database"""
+ cdb = CompilationDatabase.fromDirectory(kInputsDir)
+ cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
+ del cdb
+ gc.collect()
+ workingdir = cmds[0].directory
+
+def test_compilationCommands_references():
+ """Ensure CompilationsCommand keeps a reference to CompilationCommands"""
+ cdb = CompilationDatabase.fromDirectory(kInputsDir)
+ cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
+ del cdb
+ cmd0 = cmds[0]
+ del cmds
+ gc.collect()
+ workingdir = cmd0.directory
+
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_code_completion.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_code_completion.py
new file mode 100644
index 00000000000..357d50db513
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_code_completion.py
@@ -0,0 +1,75 @@
+from clang.cindex import TranslationUnit
+
+def check_completion_results(cr, expected):
+ assert cr is not None
+ assert len(cr.diagnostics) == 0
+
+ completions = [str(c) for c in cr.results]
+
+ for c in expected:
+ assert c in completions
+
+def test_code_complete():
+ files = [('fake.c', """
+/// Aaa.
+int test1;
+
+/// Bbb.
+void test2(void);
+
+void f() {
+
+}
+""")]
+
+ tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
+ options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
+
+ cr = tu.codeComplete('fake.c', 9, 1, unsaved_files=files, include_brief_comments=True)
+
+ expected = [
+ "{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.",
+ "{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.",
+ "{'return', TypedText} || Priority: 40 || Availability: Available || Brief comment: None"
+ ]
+ check_completion_results(cr, expected)
+
+def test_code_complete_availability():
+ files = [('fake.cpp', """
+class P {
+protected:
+ int member;
+};
+
+class Q : public P {
+public:
+ using P::member;
+};
+
+void f(P x, Q y) {
+ x.; // member is inaccessible
+ y.; // member is accessible
+}
+""")]
+
+ tu = TranslationUnit.from_source('fake.cpp', ['-std=c++98'], unsaved_files=files)
+
+ cr = tu.codeComplete('fake.cpp', 12, 5, unsaved_files=files)
+
+ expected = [
+ "{'const', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
+ "{'volatile', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
+ "{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
+ "{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
+ "{'Q', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None"
+ ]
+ check_completion_results(cr, expected)
+
+ cr = tu.codeComplete('fake.cpp', 13, 5, unsaved_files=files)
+ expected = [
+ "{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
+ "{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None",
+ "{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: None",
+ "{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None"
+ ]
+ check_completion_results(cr, expected)
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_comment.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_comment.py
new file mode 100644
index 00000000000..d8f3129ac51
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_comment.py
@@ -0,0 +1,40 @@
+from clang.cindex import TranslationUnit
+from tests.cindex.util import get_cursor
+
+def test_comment():
+ files = [('fake.c', """
+/// Aaa.
+int test1;
+
+/// Bbb.
+/// x
+void test2(void);
+
+void f() {
+
+}
+""")]
+ # make a comment-aware TU
+ tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
+ options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
+ test1 = get_cursor(tu, 'test1')
+ assert test1 is not None, "Could not find test1."
+ assert test1.type.is_pod()
+ raw = test1.raw_comment
+ brief = test1.brief_comment
+ assert raw == """/// Aaa."""
+ assert brief == """Aaa."""
+
+ test2 = get_cursor(tu, 'test2')
+ raw = test2.raw_comment
+ brief = test2.brief_comment
+ assert raw == """/// Bbb.\n/// x"""
+ assert brief == """Bbb. x"""
+
+ f = get_cursor(tu, 'f')
+ raw = f.raw_comment
+ brief = f.brief_comment
+ assert raw is None
+ assert brief is None
+
+
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cursor.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cursor.py
new file mode 100644
index 00000000000..c5ea50516ad
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cursor.py
@@ -0,0 +1,372 @@
+import ctypes
+import gc
+
+from clang.cindex import CursorKind
+from clang.cindex import TemplateArgumentKind
+from clang.cindex import TranslationUnit
+from clang.cindex import TypeKind
+from .util import get_cursor
+from .util import get_cursors
+from .util import get_tu
+
+kInput = """\
+struct s0 {
+ int a;
+ int b;
+};
+
+struct s1;
+
+void f0(int a0, int a1) {
+ int l0, l1;
+
+ if (a0)
+ return;
+
+ for (;;) {
+ break;
+ }
+}
+"""
+
+def test_get_children():
+ tu = get_tu(kInput)
+
+ it = tu.cursor.get_children()
+ tu_nodes = list(it)
+
+ assert len(tu_nodes) == 3
+ for cursor in tu_nodes:
+ assert cursor.translation_unit is not None
+
+ 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 == 1
+ assert tu_nodes[0].location.column == 8
+ assert tu_nodes[0].hash > 0
+ assert tu_nodes[0].translation_unit is not None
+
+ s0_nodes = list(tu_nodes[0].get_children())
+ assert len(s0_nodes) == 2
+ assert s0_nodes[0].kind == CursorKind.FIELD_DECL
+ assert s0_nodes[0].spelling == 'a'
+ assert s0_nodes[0].type.kind == TypeKind.INT
+ assert s0_nodes[1].kind == CursorKind.FIELD_DECL
+ assert s0_nodes[1].spelling == 'b'
+ assert s0_nodes[1].type.kind == TypeKind.INT
+
+ assert tu_nodes[1].kind == CursorKind.STRUCT_DECL
+ assert tu_nodes[1].spelling == 's1'
+ assert tu_nodes[1].displayname == 's1'
+ assert tu_nodes[1].is_definition() == False
+
+ assert tu_nodes[2].kind == CursorKind.FUNCTION_DECL
+ assert tu_nodes[2].spelling == 'f0'
+ assert tu_nodes[2].displayname == 'f0(int, int)'
+ assert tu_nodes[2].is_definition() == True
+
+def test_references():
+ """Ensure that references to TranslationUnit are kept."""
+ tu = get_tu('int x;')
+ cursors = list(tu.cursor.get_children())
+ assert len(cursors) > 0
+
+ cursor = cursors[0]
+ assert isinstance(cursor.translation_unit, TranslationUnit)
+
+ # Delete reference to TU and perform a full GC.
+ del tu
+ gc.collect()
+ assert isinstance(cursor.translation_unit, TranslationUnit)
+
+ # If the TU was destroyed, this should cause a segfault.
+ parent = cursor.semantic_parent
+
+def test_canonical():
+ source = 'struct X; struct X; struct X { int member; };'
+ tu = get_tu(source)
+
+ cursors = []
+ for cursor in tu.cursor.get_children():
+ if cursor.spelling == 'X':
+ cursors.append(cursor)
+
+ assert len(cursors) == 3
+ assert cursors[1].canonical == cursors[2].canonical
+
+def test_is_const_method():
+ """Ensure Cursor.is_const_method works."""
+ source = 'class X { void foo() const; void bar(); };'
+ tu = get_tu(source, lang='cpp')
+
+ cls = get_cursor(tu, 'X')
+ foo = get_cursor(tu, 'foo')
+ bar = get_cursor(tu, 'bar')
+ assert cls is not None
+ assert foo is not None
+ assert bar is not None
+
+ assert foo.is_const_method()
+ assert not bar.is_const_method()
+
+def test_is_mutable_field():
+ """Ensure Cursor.is_mutable_field works."""
+ source = 'class X { int x_; mutable int y_; };'
+ tu = get_tu(source, lang='cpp')
+
+ cls = get_cursor(tu, 'X')
+ x_ = get_cursor(tu, 'x_')
+ y_ = get_cursor(tu, 'y_')
+ assert cls is not None
+ assert x_ is not None
+ assert y_ is not None
+
+ assert not x_.is_mutable_field()
+ assert y_.is_mutable_field()
+
+def test_is_static_method():
+ """Ensure Cursor.is_static_method works."""
+
+ source = 'class X { static void foo(); void bar(); };'
+ tu = get_tu(source, lang='cpp')
+
+ cls = get_cursor(tu, 'X')
+ foo = get_cursor(tu, 'foo')
+ bar = get_cursor(tu, 'bar')
+ assert cls is not None
+ assert foo is not None
+ assert bar is not None
+
+ assert foo.is_static_method()
+ assert not bar.is_static_method()
+
+def test_is_pure_virtual_method():
+ """Ensure Cursor.is_pure_virtual_method works."""
+ source = 'class X { virtual void foo() = 0; virtual void bar(); };'
+ tu = get_tu(source, lang='cpp')
+
+ cls = get_cursor(tu, 'X')
+ foo = get_cursor(tu, 'foo')
+ bar = get_cursor(tu, 'bar')
+ assert cls is not None
+ assert foo is not None
+ assert bar is not None
+
+ assert foo.is_pure_virtual_method()
+ assert not bar.is_pure_virtual_method()
+
+def test_is_virtual_method():
+ """Ensure Cursor.is_virtual_method works."""
+ source = 'class X { virtual void foo(); void bar(); };'
+ tu = get_tu(source, lang='cpp')
+
+ cls = get_cursor(tu, 'X')
+ foo = get_cursor(tu, 'foo')
+ bar = get_cursor(tu, 'bar')
+ assert cls is not None
+ assert foo is not None
+ assert bar is not None
+
+ assert foo.is_virtual_method()
+ assert not bar.is_virtual_method()
+
+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
+
+kParentTest = """\
+ class C {
+ void f();
+ }
+
+ void C::f() { }
+ """
+def test_semantic_parent():
+ tu = get_tu(kParentTest, 'cpp')
+ curs = get_cursors(tu, 'f')
+ decl = get_cursor(tu, 'C')
+ assert(len(curs) == 2)
+ assert(curs[0].semantic_parent == curs[1].semantic_parent)
+ assert(curs[0].semantic_parent == decl)
+
+def test_lexical_parent():
+ tu = get_tu(kParentTest, 'cpp')
+ curs = get_cursors(tu, 'f')
+ decl = get_cursor(tu, 'C')
+ assert(len(curs) == 2)
+ assert(curs[0].lexical_parent != curs[1].lexical_parent)
+ assert(curs[0].lexical_parent == decl)
+ assert(curs[1].lexical_parent == tu.cursor)
+
+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_enum_type_cpp():
+ tu = get_tu('enum TEST : long long { FOO=1, BAR=2 };', lang="cpp")
+ enum = get_cursor(tu, 'TEST')
+ assert enum is not None
+
+ assert enum.kind == CursorKind.ENUM_DECL
+ assert enum.enum_type.kind == TypeKind.LONGLONG
+
+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'
+
+def test_enum_values():
+ tu = get_tu('enum TEST { SPAM=1, EGG, HAM = EGG * 20};')
+ enum = get_cursor(tu, 'TEST')
+ assert enum is not None
+
+ assert enum.kind == CursorKind.ENUM_DECL
+
+ enum_constants = list(enum.get_children())
+ assert len(enum_constants) == 3
+
+ spam, egg, ham = enum_constants
+
+ assert spam.kind == CursorKind.ENUM_CONSTANT_DECL
+ assert spam.enum_value == 1
+ assert egg.kind == CursorKind.ENUM_CONSTANT_DECL
+ assert egg.enum_value == 2
+ assert ham.kind == CursorKind.ENUM_CONSTANT_DECL
+ assert ham.enum_value == 40
+
+def test_enum_values_cpp():
+ tu = get_tu('enum TEST : long long { SPAM = -1, HAM = 0x10000000000};', lang="cpp")
+ enum = get_cursor(tu, 'TEST')
+ assert enum is not None
+
+ assert enum.kind == CursorKind.ENUM_DECL
+
+ enum_constants = list(enum.get_children())
+ assert len(enum_constants) == 2
+
+ spam, ham = enum_constants
+
+ assert spam.kind == CursorKind.ENUM_CONSTANT_DECL
+ assert spam.enum_value == -1
+ assert ham.kind == CursorKind.ENUM_CONSTANT_DECL
+ assert ham.enum_value == 0x10000000000
+
+def test_annotation_attribute():
+ tu = get_tu('int foo (void) __attribute__ ((annotate("here be annotation attribute")));')
+
+ foo = get_cursor(tu, 'foo')
+ assert foo is not None
+
+ for c in foo.get_children():
+ if c.kind == CursorKind.ANNOTATE_ATTR:
+ assert c.displayname == "here be annotation attribute"
+ break
+ else:
+ assert False, "Couldn't find annotation"
+
+def test_result_type():
+ tu = get_tu('int foo();')
+ foo = get_cursor(tu, 'foo')
+
+ assert foo is not None
+ t = foo.result_type
+ assert t.kind == TypeKind.INT
+
+def test_get_tokens():
+ """Ensure we can map cursors back to tokens."""
+ tu = get_tu('int foo(int i);')
+ foo = get_cursor(tu, 'foo')
+
+ tokens = list(foo.get_tokens())
+ assert len(tokens) == 7
+ assert tokens[0].spelling == 'int'
+ assert tokens[1].spelling == 'foo'
+
+def test_get_arguments():
+ tu = get_tu('void foo(int i, int j);')
+ foo = get_cursor(tu, 'foo')
+ arguments = list(foo.get_arguments())
+
+ assert len(arguments) == 2
+ assert arguments[0].spelling == "i"
+ assert arguments[1].spelling == "j"
+
+kTemplateArgTest = """\
+ template <int kInt, typename T, bool kBool>
+ void foo();
+
+ template<>
+ void foo<-7, float, true>();
+ """
+
+def test_get_num_template_arguments():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_num_template_arguments() == 3
+
+def test_get_template_argument_kind():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_template_argument_kind(0) == TemplateArgumentKind.INTEGRAL
+ assert foos[1].get_template_argument_kind(1) == TemplateArgumentKind.TYPE
+ assert foos[1].get_template_argument_kind(2) == TemplateArgumentKind.INTEGRAL
+
+def test_get_template_argument_type():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_template_argument_type(1).kind == TypeKind.FLOAT
+
+def test_get_template_argument_value():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_template_argument_value(0) == -7
+ assert foos[1].get_template_argument_value(2) == True
+
+def test_get_template_argument_unsigned_value():
+ tu = get_tu(kTemplateArgTest, lang='cpp')
+ foos = get_cursors(tu, 'foo')
+
+ assert foos[1].get_template_argument_unsigned_value(0) == 2 ** 32 - 7
+ assert foos[1].get_template_argument_unsigned_value(2) == True
+
+def test_referenced():
+ tu = get_tu('void foo(); void bar() { foo(); }')
+ foo = get_cursor(tu, 'foo')
+ bar = get_cursor(tu, 'bar')
+ for c in bar.get_children():
+ if c.kind == CursorKind.CALL_EXPR:
+ assert c.referenced.spelling == foo.spelling
+ break
+
+def test_mangled_name():
+ kInputForMangling = """\
+ int foo(int, int);
+ """
+ tu = get_tu(kInputForMangling, lang='cpp')
+ foo = get_cursor(tu, 'foo')
+
+ # Since libclang does not link in targets, we cannot pass a triple to it
+ # and force the target. To enable this test to pass on all platforms, accept
+ # all valid manglings.
+ # [c-index-test handles this by running the source through clang, emitting
+ # an AST file and running libclang on that AST file]
+ assert foo.mangled_name in ('_Z3fooii', '__Z3fooii', '?foo@@YAHHH')
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cursor_kind.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cursor_kind.py
new file mode 100644
index 00000000000..5bac289625b
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_cursor_kind.py
@@ -0,0 +1,48 @@
+from clang.cindex import CursorKind
+
+def test_name():
+ assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL'
+
+def test_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
+ assert CursorKind.TYPE_ALIAS_TEMPLATE_DECL in kinds
+
+def test_kind_groups():
+ """Check that every kind classifies to exactly one group."""
+
+ assert CursorKind.UNEXPOSED_DECL.is_declaration()
+ assert CursorKind.TYPE_REF.is_reference()
+ assert CursorKind.DECL_REF_EXPR.is_expression()
+ 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')
+ if getattr(k, n)()]
+
+ if k in ( CursorKind.TRANSLATION_UNIT,
+ CursorKind.MACRO_DEFINITION,
+ CursorKind.MACRO_INSTANTIATION,
+ CursorKind.INCLUSION_DIRECTIVE,
+ CursorKind.PREPROCESSING_DIRECTIVE):
+ assert len(group) == 0
+ else:
+ assert len(group) == 1
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_diagnostics.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_diagnostics.py
new file mode 100644
index 00000000000..48ab6176fd1
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_diagnostics.py
@@ -0,0 +1,82 @@
+from clang.cindex import *
+from .util import get_tu
+
+# FIXME: We need support for invalid translation units to test better.
+
+def test_diagnostic_warning():
+ 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
+ assert tu.diagnostics[0].location.column == 11
+ assert (tu.diagnostics[0].spelling ==
+ 'control reaches end of non-void function')
+
+def test_diagnostic_note():
+ # FIXME: We aren't getting notes here for some reason.
+ 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
+ assert tu.diagnostics[0].location.column == 7
+ assert 'incompatible' in tu.diagnostics[0].spelling
+# assert tu.diagnostics[1].severity == Diagnostic.Note
+# assert tu.diagnostics[1].location.line == 1
+# assert tu.diagnostics[1].location.column == 11
+# assert tu.diagnostics[1].spelling == 'instantiated from'
+
+def test_diagnostic_fixit():
+ 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
+ assert tu.diagnostics[0].location.column == 26
+ assert tu.diagnostics[0].spelling.startswith('use of GNU old-style')
+ assert len(tu.diagnostics[0].fixits) == 1
+ assert tu.diagnostics[0].fixits[0].range.start.line == 1
+ assert tu.diagnostics[0].fixits[0].range.start.column == 26
+ assert tu.diagnostics[0].fixits[0].range.end.line == 1
+ assert tu.diagnostics[0].fixits[0].range.end.column == 30
+ assert tu.diagnostics[0].fixits[0].value == '.f0 = '
+
+def test_diagnostic_range():
+ 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
+ assert tu.diagnostics[0].location.column == 16
+ assert tu.diagnostics[0].spelling.startswith('incompatible pointer to')
+ assert len(tu.diagnostics[0].fixits) == 0
+ assert len(tu.diagnostics[0].ranges) == 1
+ assert tu.diagnostics[0].ranges[0].start.line == 1
+ assert tu.diagnostics[0].ranges[0].start.column == 20
+ assert tu.diagnostics[0].ranges[0].end.line == 1
+ assert tu.diagnostics[0].ranges[0].end.column == 27
+ try:
+ tu.diagnostics[0].ranges[1].start.line
+ except IndexError:
+ 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/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_file.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_file.py
new file mode 100644
index 00000000000..146e8c57052
--- /dev/null
+++ b/gnu/llvm/tools/clang/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/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_index.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_index.py
new file mode 100644
index 00000000000..dc173f04d21
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_index.py
@@ -0,0 +1,15 @@
+from clang.cindex import *
+import os
+
+kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
+
+def test_create():
+ index = Index.create()
+
+# FIXME: test Index.read
+
+def test_parse():
+ index = Index.create()
+ assert isinstance(index, Index)
+ tu = index.parse(os.path.join(kInputsDir, 'hello.cpp'))
+ assert isinstance(tu, TranslationUnit)
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_location.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_location.py
new file mode 100644
index 00000000000..9e9ef487af1
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_location.py
@@ -0,0 +1,95 @@
+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"
+
+def assert_location(loc, line, column, offset):
+ assert loc.line == line
+ assert loc.column == column
+ assert loc.offset == offset
+
+def test_location():
+ tu = get_tu(baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ 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 = get_tu('\n' + baseInput)
+ one = get_cursor(tu, 'one')
+ two = get_cursor(tu, 'two')
+
+ assert one is not None
+ assert two is not None
+
+ 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 = 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
+
+ # 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
+
+ offset_location = SourceLocation.from_offset(tu, file, 5)
+ cursor = Cursor.from_location(tu, offset_location)
+ verified = False
+ for n in [n for n in tu.cursor.get_children() if n.spelling == 'one']:
+ assert n == cursor
+ verified = True
+
+ assert verified
+
+def test_extent():
+ 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/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_token_kind.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_token_kind.py
new file mode 100644
index 00000000000..62ec63e0ad5
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_token_kind.py
@@ -0,0 +1,43 @@
+from clang.cindex import TokenKind
+from nose.tools import eq_
+from nose.tools import ok_
+from nose.tools import raises
+
+def test_constructor():
+ """Ensure TokenKind constructor works as expected."""
+
+ t = TokenKind(5, 'foo')
+
+ eq_(t.value, 5)
+ eq_(t.name, 'foo')
+
+@raises(ValueError)
+def test_bad_register():
+ """Ensure a duplicate value is rejected for registration."""
+
+ TokenKind.register(2, 'foo')
+
+@raises(ValueError)
+def test_unknown_value():
+ """Ensure trying to fetch an unknown value raises."""
+
+ TokenKind.from_value(-1)
+
+def test_registration():
+ """Ensure that items registered appear as class attributes."""
+ ok_(hasattr(TokenKind, 'LITERAL'))
+ literal = TokenKind.LITERAL
+
+ ok_(isinstance(literal, TokenKind))
+
+def test_from_value():
+ """Ensure registered values can be obtained from from_value()."""
+ t = TokenKind.from_value(3)
+ ok_(isinstance(t, TokenKind))
+ eq_(t, TokenKind.LITERAL)
+
+def test_repr():
+ """Ensure repr() works."""
+
+ r = repr(TokenKind.LITERAL)
+ eq_(r, 'TokenKind.LITERAL')
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_tokens.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_tokens.py
new file mode 100644
index 00000000000..70748429094
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_tokens.py
@@ -0,0 +1,52 @@
+from clang.cindex import CursorKind
+from clang.cindex import Index
+from clang.cindex import SourceLocation
+from clang.cindex import SourceRange
+from clang.cindex import TokenKind
+from nose.tools import eq_
+from nose.tools import ok_
+
+from .util import get_tu
+
+def test_token_to_cursor():
+ """Ensure we can obtain a Cursor from a Token instance."""
+ tu = get_tu('int i = 5;')
+ r = tu.get_extent('t.c', (0, 9))
+ tokens = list(tu.get_tokens(extent=r))
+
+ assert len(tokens) == 5
+ assert tokens[1].spelling == 'i'
+ assert tokens[1].kind == TokenKind.IDENTIFIER
+
+ cursor = tokens[1].cursor
+ assert cursor.kind == CursorKind.VAR_DECL
+ assert tokens[1].cursor == tokens[2].cursor
+
+def test_token_location():
+ """Ensure Token.location works."""
+
+ tu = get_tu('int foo = 10;')
+ r = tu.get_extent('t.c', (0, 11))
+
+ tokens = list(tu.get_tokens(extent=r))
+ eq_(len(tokens), 4)
+
+ loc = tokens[1].location
+ ok_(isinstance(loc, SourceLocation))
+ eq_(loc.line, 1)
+ eq_(loc.column, 5)
+ eq_(loc.offset, 4)
+
+def test_token_extent():
+ """Ensure Token.extent works."""
+ tu = get_tu('int foo = 10;')
+ r = tu.get_extent('t.c', (0, 11))
+
+ tokens = list(tu.get_tokens(extent=r))
+ eq_(len(tokens), 4)
+
+ extent = tokens[1].extent
+ ok_(isinstance(extent, SourceRange))
+
+ eq_(extent.start.offset, 4)
+ eq_(extent.end.offset, 7)
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_translation_unit.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_translation_unit.py
new file mode 100644
index 00000000000..be6cd671ae0
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_translation_unit.py
@@ -0,0 +1,251 @@
+import gc
+import os
+import tempfile
+
+from clang.cindex import CursorKind
+from clang.cindex import Cursor
+from clang.cindex import File
+from clang.cindex import Index
+from clang.cindex import SourceLocation
+from clang.cindex import SourceRange
+from clang.cindex import TranslationUnitSaveError
+from clang.cindex import TranslationUnitLoadError
+from clang.cindex import TranslationUnit
+from .util import get_cursor
+from .util import get_tu
+
+kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
+
+def test_spelling():
+ path = os.path.join(kInputsDir, 'hello.cpp')
+ tu = TranslationUnit.from_source(path)
+ assert tu.spelling == path
+
+def test_cursor():
+ path = os.path.join(kInputsDir, 'hello.cpp')
+ tu = get_tu(path)
+ c = tu.cursor
+ assert isinstance(c, Cursor)
+ assert c.kind is CursorKind.TRANSLATION_UNIT
+
+def test_parse_arguments():
+ path = os.path.join(kInputsDir, 'parse_arguments.c')
+ tu = TranslationUnit.from_source(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
+ spellings = [c.spelling for c in tu.cursor.get_children()]
+ assert spellings[-2] == 'hello'
+ assert spellings[-1] == 'hi'
+
+def test_reparse_arguments():
+ path = os.path.join(kInputsDir, 'parse_arguments.c')
+ tu = TranslationUnit.from_source(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
+ tu.reparse()
+ spellings = [c.spelling for c in tu.cursor.get_children()]
+ assert spellings[-2] == 'hello'
+ assert spellings[-1] == 'hi'
+
+def test_unsaved_files():
+ tu = TranslationUnit.from_source('fake.c', ['-I./'], unsaved_files = [
+ ('fake.c', """
+#include "fake.h"
+int x;
+int SOME_DEFINE;
+"""),
+ ('./fake.h', """
+#define SOME_DEFINE y
+""")
+ ])
+ spellings = [c.spelling for c in tu.cursor.get_children()]
+ assert spellings[-2] == 'x'
+ assert spellings[-1] == 'y'
+
+def test_unsaved_files_2():
+ import StringIO
+ tu = TranslationUnit.from_source('fake.c', unsaved_files = [
+ ('fake.c', StringIO.StringIO('int x;'))])
+ spellings = [c.spelling for c in tu.cursor.get_children()]
+ assert spellings[-1] == 'x'
+
+def normpaths_equal(path1, path2):
+ """ Compares two paths for equality after normalizing them with
+ os.path.normpath
+ """
+ return os.path.normpath(path1) == os.path.normpath(path2)
+
+def test_includes():
+ def eq(expected, actual):
+ if not actual.is_input_file:
+ return normpaths_equal(expected[0], actual.source.name) and \
+ normpaths_equal(expected[1], actual.include.name)
+ else:
+ return normpaths_equal(expected[1], actual.include.name)
+
+ src = os.path.join(kInputsDir, 'include.cpp')
+ h1 = os.path.join(kInputsDir, "header1.h")
+ h2 = os.path.join(kInputsDir, "header2.h")
+ h3 = os.path.join(kInputsDir, "header3.h")
+ inc = [(src, h1), (h1, h3), (src, h2), (h2, h3)]
+
+ tu = TranslationUnit.from_source(src)
+ for i in zip(inc, tu.get_includes()):
+ assert eq(i[0], i[1])
+
+def save_tu(tu):
+ """Convenience API to save a TranslationUnit to a file.
+
+ Returns the filename it was saved to.
+ """
+ _, path = tempfile.mkstemp()
+ tu.save(path)
+
+ return path
+
+def test_save():
+ """Ensure TranslationUnit.save() works."""
+
+ tu = get_tu('int foo();')
+
+ path = save_tu(tu)
+ assert os.path.exists(path)
+ assert os.path.getsize(path) > 0
+ os.unlink(path)
+
+def test_save_translation_errors():
+ """Ensure that saving to an invalid directory raises."""
+
+ tu = get_tu('int foo();')
+
+ path = '/does/not/exist/llvm-test.ast'
+ assert not os.path.exists(os.path.dirname(path))
+
+ try:
+ tu.save(path)
+ assert False
+ except TranslationUnitSaveError as ex:
+ expected = TranslationUnitSaveError.ERROR_UNKNOWN
+ assert ex.save_error == expected
+
+def test_load():
+ """Ensure TranslationUnits can be constructed from saved files."""
+
+ tu = get_tu('int foo();')
+ assert len(tu.diagnostics) == 0
+ path = save_tu(tu)
+
+ assert os.path.exists(path)
+ assert os.path.getsize(path) > 0
+
+ tu2 = TranslationUnit.from_ast_file(filename=path)
+ assert len(tu2.diagnostics) == 0
+
+ foo = get_cursor(tu2, 'foo')
+ assert foo is not None
+
+ # Just in case there is an open file descriptor somewhere.
+ del tu2
+
+ os.unlink(path)
+
+def test_index_parse():
+ path = os.path.join(kInputsDir, 'hello.cpp')
+ index = Index.create()
+ tu = index.parse(path)
+ assert isinstance(tu, TranslationUnit)
+
+def test_get_file():
+ """Ensure tu.get_file() works appropriately."""
+
+ tu = get_tu('int foo();')
+
+ f = tu.get_file('t.c')
+ assert isinstance(f, File)
+ assert f.name == 't.c'
+
+ try:
+ f = tu.get_file('foobar.cpp')
+ except:
+ pass
+ else:
+ assert False
+
+def test_get_source_location():
+ """Ensure tu.get_source_location() works."""
+
+ tu = get_tu('int foo();')
+
+ location = tu.get_location('t.c', 2)
+ assert isinstance(location, SourceLocation)
+ assert location.offset == 2
+ assert location.file.name == 't.c'
+
+ location = tu.get_location('t.c', (1, 3))
+ assert isinstance(location, SourceLocation)
+ assert location.line == 1
+ assert location.column == 3
+ assert location.file.name == 't.c'
+
+def test_get_source_range():
+ """Ensure tu.get_source_range() works."""
+
+ tu = get_tu('int foo();')
+
+ r = tu.get_extent('t.c', (1,4))
+ assert isinstance(r, SourceRange)
+ assert r.start.offset == 1
+ assert r.end.offset == 4
+ assert r.start.file.name == 't.c'
+ assert r.end.file.name == 't.c'
+
+ r = tu.get_extent('t.c', ((1,2), (1,3)))
+ assert isinstance(r, SourceRange)
+ assert r.start.line == 1
+ assert r.start.column == 2
+ assert r.end.line == 1
+ assert r.end.column == 3
+ assert r.start.file.name == 't.c'
+ assert r.end.file.name == 't.c'
+
+ start = tu.get_location('t.c', 0)
+ end = tu.get_location('t.c', 5)
+
+ r = tu.get_extent('t.c', (start, end))
+ assert isinstance(r, SourceRange)
+ assert r.start.offset == 0
+ assert r.end.offset == 5
+ assert r.start.file.name == 't.c'
+ assert r.end.file.name == 't.c'
+
+def test_get_tokens_gc():
+ """Ensures get_tokens() works properly with garbage collection."""
+
+ tu = get_tu('int foo();')
+ r = tu.get_extent('t.c', (0, 10))
+ tokens = list(tu.get_tokens(extent=r))
+
+ assert tokens[0].spelling == 'int'
+ gc.collect()
+ assert tokens[0].spelling == 'int'
+
+ del tokens[1]
+ gc.collect()
+ assert tokens[0].spelling == 'int'
+
+ # May trigger segfault if we don't do our job properly.
+ del tokens
+ gc.collect()
+ gc.collect() # Just in case.
+
+def test_fail_from_source():
+ path = os.path.join(kInputsDir, 'non-existent.cpp')
+ try:
+ tu = TranslationUnit.from_source(path)
+ except TranslationUnitLoadError:
+ tu = None
+ assert tu == None
+
+def test_fail_from_ast_file():
+ path = os.path.join(kInputsDir, 'non-existent.ast')
+ try:
+ tu = TranslationUnit.from_ast_file(path)
+ except TranslationUnitLoadError:
+ tu = None
+ assert tu == None
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_type.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_type.py
new file mode 100644
index 00000000000..f2184338be4
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/test_type.py
@@ -0,0 +1,406 @@
+import gc
+
+from clang.cindex import CursorKind
+from clang.cindex import TranslationUnit
+from clang.cindex import TypeKind
+from nose.tools import raises
+from .util import get_cursor
+from .util import get_tu
+
+kInput = """\
+
+typedef int I;
+
+struct teststruct {
+ int a;
+ I b;
+ long c;
+ unsigned long d;
+ signed long e;
+ const int f;
+ int *g;
+ int ***h;
+};
+
+"""
+
+def test_a_struct():
+ tu = get_tu(kInput)
+
+ 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.translation_unit is not None 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[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[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[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
+
+def test_references():
+ """Ensure that a Type maintains a reference to a TranslationUnit."""
+
+ tu = get_tu('int x;')
+ children = list(tu.cursor.get_children())
+ assert len(children) > 0
+
+ cursor = children[0]
+ t = cursor.type
+
+ assert isinstance(t.translation_unit, TranslationUnit)
+
+ # Delete main TranslationUnit reference and force a GC.
+ del tu
+ gc.collect()
+ assert isinstance(t.translation_unit, TranslationUnit)
+
+ # If the TU was destroyed, this should cause a segfault.
+ decl = t.get_declaration()
+
+constarrayInput="""
+struct teststruct {
+ void *A[2];
+};
+"""
+def testConstantArray():
+ 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_type_spelling():
+ """Ensure Type.spelling works."""
+ tu = get_tu('int c[5]; void f(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;')
+ a = get_cursor(tu, 'a')
+
+ assert a is not None
+ assert a.type.kind.spelling == 'Int'
+
+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 c[5]; void f(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 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():
+ """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()
+
+def test_record_layout():
+ """Ensure Cursor.type.get_size, Cursor.type.get_align and
+ Cursor.type.get_offset works."""
+
+ source ="""
+struct a {
+ long a1;
+ long a2:3;
+ long a3:4;
+ long long a4;
+};
+"""
+ tries=[(['-target','i386-linux-gnu'],(4,16,0,32,35,64)),
+ (['-target','nvptx64-unknown-unknown'],(8,24,0,64,67,128)),
+ (['-target','i386-pc-win32'],(8,16,0,32,35,64)),
+ (['-target','msp430-none-none'],(2,14,0,32,35,48))]
+ for flags, values in tries:
+ align,total,a1,a2,a3,a4 = values
+
+ tu = get_tu(source, flags=flags)
+ teststruct = get_cursor(tu, 'a')
+ fields = list(teststruct.get_children())
+
+ assert teststruct.type.get_align() == align
+ assert teststruct.type.get_size() == total
+ assert teststruct.type.get_offset(fields[0].spelling) == a1
+ assert teststruct.type.get_offset(fields[1].spelling) == a2
+ assert teststruct.type.get_offset(fields[2].spelling) == a3
+ assert teststruct.type.get_offset(fields[3].spelling) == a4
+ assert fields[0].is_bitfield() == False
+ assert fields[1].is_bitfield() == True
+ assert fields[1].get_bitfield_width() == 3
+ assert fields[2].is_bitfield() == True
+ assert fields[2].get_bitfield_width() == 4
+ assert fields[3].is_bitfield() == False
+
+def test_offset():
+ """Ensure Cursor.get_record_field_offset works in anonymous records"""
+ source="""
+struct Test {
+ struct {int a;} typeanon;
+ struct {
+ int bariton;
+ union {
+ int foo;
+ };
+ };
+ int bar;
+};"""
+ tries=[(['-target','i386-linux-gnu'],(4,16,0,32,64,96)),
+ (['-target','nvptx64-unknown-unknown'],(8,24,0,32,64,96)),
+ (['-target','i386-pc-win32'],(8,16,0,32,64,96)),
+ (['-target','msp430-none-none'],(2,14,0,32,64,96))]
+ for flags, values in tries:
+ align,total,f1,bariton,foo,bar = values
+ tu = get_tu(source)
+ teststruct = get_cursor(tu, 'Test')
+ children = list(teststruct.get_children())
+ fields = list(teststruct.type.get_fields())
+ assert children[0].kind == CursorKind.STRUCT_DECL
+ assert children[0].spelling != "typeanon"
+ assert children[1].spelling == "typeanon"
+ assert fields[0].kind == CursorKind.FIELD_DECL
+ assert fields[1].kind == CursorKind.FIELD_DECL
+ assert fields[1].is_anonymous()
+ assert teststruct.type.get_offset("typeanon") == f1
+ assert teststruct.type.get_offset("bariton") == bariton
+ assert teststruct.type.get_offset("foo") == foo
+ 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
diff --git a/gnu/llvm/tools/clang/bindings/python/tests/cindex/util.py b/gnu/llvm/tools/clang/bindings/python/tests/cindex/util.py
new file mode 100644
index 00000000000..c53ba7c81bd
--- /dev/null
+++ b/gnu/llvm/tools/clang/bindings/python/tests/cindex/util.py
@@ -0,0 +1,75 @@
+# This file provides common utility functions for the test suite.
+
+from clang.cindex import Cursor
+from clang.cindex import TranslationUnit
+
+def get_tu(source, lang='c', all_warnings=False, flags=[]):
+ """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.
+ """
+ args = list(flags)
+ name = 't.c'
+ if lang == 'cpp':
+ name = 't.cpp'
+ args.append('-std=c++11')
+ elif lang == 'objc':
+ name = 't.m'
+ elif lang != 'c':
+ raise Exception('Unknown language: %s' % lang)
+
+ if all_warnings:
+ args += ['-Wall', '-Wextra']
+
+ return TranslationUnit.from_source(name, args, unsaved_files=[(name,
+ source)])
+
+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.
+ """
+ # Convenience for calling on a TU.
+ root_cursor = source if isinstance(source, Cursor) else source.cursor
+
+ for cursor in root_cursor.walk_preorder():
+ if cursor.spelling == spelling:
+ return cursor
+
+ 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
+ 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 = []
+ for cursor in root_cursor.walk_preorder():
+ if cursor.spelling == spelling:
+ cursors.append(cursor)
+
+ return cursors
+
+
+__all__ = [
+ 'get_cursor',
+ 'get_cursors',
+ 'get_tu',
+]