diff options
| author | 2016-09-03 22:46:54 +0000 | |
|---|---|---|
| committer | 2016-09-03 22:46:54 +0000 | |
| commit | b5500b9ca0102f1ccaf32f0e77e96d0739aded9b (patch) | |
| tree | e1b7ebb5a0231f9e6d8d3f6f719582cebd64dc98 /gnu/llvm/tools/clang/bindings/python/tests | |
| parent | clarify purpose of src/gnu/ directory. (diff) | |
| download | wireguard-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')
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', +] |
