[python] [tests] Rewrite to use standard unittest module

Rewrite the tests from using plain 'assert' mixed with some nosetests
methods to the standard unittest module layout. Improve the code
to use the most canonical assertion methods whenever possible.

This has a few major advantages:

- the code uses standard methods now, resulting in a reduced number
of WTFs whenever someone with basic Python knowledge gets to read it,

- completely unnecessary dependency on nosetests is removed since
the standard library supplies all that is necessary for the tests
to run,

- the tests can be run via any test runner, including the one built-in
in Python,

- the failure output for most of the tests is improved from 'assertion
x == y failed' to actually telling the values.

Differential Revision: https://reviews.llvm.org/D39763

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@317897 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Michal Gorny 2017-11-10 16:44:12 +00:00
parent 181561d074
commit 01e75bdff2
18 changed files with 1631 additions and 1569 deletions

View File

@ -5,11 +5,12 @@
This directory implements Python bindings for Clang. This directory implements Python bindings for Clang.
You may need to alter LD_LIBRARY_PATH so that the Clang library can be You may need to alter LD_LIBRARY_PATH so that the Clang library can be
found. The unit tests are designed to be run with 'nosetests'. For example: found. The unit tests are designed to be run with any standard test
runner. For example:
-- --
$ env PYTHONPATH=$(echo ~/llvm/tools/clang/bindings/python/) \ $ env PYTHONPATH=$(echo ~/llvm/tools/clang/bindings/python/) \
LD_LIBRARY_PATH=$(llvm-config --libdir) \ LD_LIBRARY_PATH=$(llvm-config --libdir) \
nosetests -v python -m unittest discover -v
tests.cindex.test_index.test_create ... ok tests.cindex.test_index.test_create ... ok
... ...

View File

@ -6,10 +6,14 @@ from clang.cindex import TranslationUnit
from .util import get_cursor from .util import get_cursor
from .util import get_tu from .util import get_tu
def test_access_specifiers(): import unittest
"""Ensure that C++ access specifiers are available on cursors"""
tu = get_tu("""
class TestAccessSpecifiers(unittest.TestCase):
def test_access_specifiers(self):
"""Ensure that C++ access specifiers are available on cursors"""
tu = get_tu("""
class test_class { class test_class {
public: public:
void public_member_function(); void public_member_function();
@ -20,15 +24,14 @@ private:
}; };
""", lang = 'cpp') """, lang = 'cpp')
test_class = get_cursor(tu, "test_class") test_class = get_cursor(tu, "test_class")
assert test_class.access_specifier == AccessSpecifier.INVALID; self.assertEqual(test_class.access_specifier, AccessSpecifier.INVALID)
public = get_cursor(tu.cursor, "public_member_function") public = get_cursor(tu.cursor, "public_member_function")
assert public.access_specifier == AccessSpecifier.PUBLIC self.assertEqual(public.access_specifier, AccessSpecifier.PUBLIC)
protected = get_cursor(tu.cursor, "protected_member_function") protected = get_cursor(tu.cursor, "protected_member_function")
assert protected.access_specifier == AccessSpecifier.PROTECTED self.assertEqual(protected.access_specifier, AccessSpecifier.PROTECTED)
private = get_cursor(tu.cursor, "private_member_function")
assert private.access_specifier == AccessSpecifier.PRIVATE
private = get_cursor(tu.cursor, "private_member_function")
self.assertEqual(private.access_specifier, AccessSpecifier.PRIVATE)

View File

@ -4,114 +4,116 @@ from clang.cindex import CompileCommands
from clang.cindex import CompileCommand from clang.cindex import CompileCommand
import os import os
import gc import gc
import unittest
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS') 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(): class TestCDB(unittest.TestCase):
"""Check we can load a compilation database""" def test_create_fail(self):
cdb = CompilationDatabase.fromDirectory(kInputsDir) """Check we fail loading a database with an assertion"""
path = os.path.dirname(__file__)
with self.assertRaises(CompilationDatabaseError) as cm:
cdb = CompilationDatabase.fromDirectory(path)
e = cm.exception
self.assertEqual(e.cdb_error,
CompilationDatabaseError.ERROR_CANNOTLOADDATABASE)
def test_lookup_fail(): def test_create(self):
"""Check file lookup failure""" """Check we can load a compilation database"""
cdb = CompilationDatabase.fromDirectory(kInputsDir) cdb = CompilationDatabase.fromDirectory(kInputsDir)
assert cdb.getCompileCommands('file_do_not_exist.cpp') == None
def test_lookup_succeed(): def test_lookup_fail(self):
"""Check we get some results if the file exists in the db""" """Check file lookup failure"""
cdb = CompilationDatabase.fromDirectory(kInputsDir) cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp') self.assertIsNone(cdb.getCompileCommands('file_do_not_exist.cpp'))
assert len(cmds) != 0
def test_all_compilecommand(): def test_lookup_succeed(self):
"""Check we get all results from the db""" """Check we get some results if the file exists in the db"""
cdb = CompilationDatabase.fromDirectory(kInputsDir) cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getAllCompileCommands() cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
assert len(cmds) == 3 self.assertNotEqual(len(cmds), 0)
expected = [
{ 'wd': '/home/john.doe/MyProject',
'file': '/home/john.doe/MyProject/project.cpp',
'line': ['clang++', '-o', 'project.o', '-c',
'/home/john.doe/MyProject/project.cpp']},
{ 'wd': '/home/john.doe/MyProjectA',
'file': '/home/john.doe/MyProject/project2.cpp',
'line': ['clang++', '-o', 'project2.o', '-c',
'/home/john.doe/MyProject/project2.cpp']},
{ 'wd': '/home/john.doe/MyProjectB',
'file': '/home/john.doe/MyProject/project2.cpp',
'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c',
'/home/john.doe/MyProject/project2.cpp']},
] def test_all_compilecommand(self):
for i in range(len(cmds)): """Check we get all results from the db"""
assert cmds[i].directory == expected[i]['wd'] cdb = CompilationDatabase.fromDirectory(kInputsDir)
assert cmds[i].filename == expected[i]['file'] cmds = cdb.getAllCompileCommands()
for arg, exp in zip(cmds[i].arguments, expected[i]['line']): self.assertEqual(len(cmds), 3)
assert arg == exp expected = [
{ 'wd': '/home/john.doe/MyProject',
'file': '/home/john.doe/MyProject/project.cpp',
'line': ['clang++', '-o', 'project.o', '-c',
'/home/john.doe/MyProject/project.cpp']},
{ 'wd': '/home/john.doe/MyProjectA',
'file': '/home/john.doe/MyProject/project2.cpp',
'line': ['clang++', '-o', 'project2.o', '-c',
'/home/john.doe/MyProject/project2.cpp']},
{ 'wd': '/home/john.doe/MyProjectB',
'file': '/home/john.doe/MyProject/project2.cpp',
'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c',
'/home/john.doe/MyProject/project2.cpp']},
def test_1_compilecommand(): ]
"""Check file with single compile command""" for i in range(len(cmds)):
cdb = CompilationDatabase.fromDirectory(kInputsDir) self.assertEqual(cmds[i].directory, expected[i]['wd'])
file = '/home/john.doe/MyProject/project.cpp' self.assertEqual(cmds[i].filename, expected[i]['file'])
cmds = cdb.getCompileCommands(file) for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
assert len(cmds) == 1 self.assertEqual(arg, exp)
assert cmds[0].directory == os.path.dirname(file)
assert cmds[0].filename == file
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(): def test_1_compilecommand(self):
"""Check file with 2 compile commands""" """Check file with single compile command"""
cdb = CompilationDatabase.fromDirectory(kInputsDir) cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp') file = '/home/john.doe/MyProject/project.cpp'
assert len(cmds) == 2 cmds = cdb.getCompileCommands(file)
expected = [ self.assertEqual(len(cmds), 1)
{ 'wd': '/home/john.doe/MyProjectA', self.assertEqual(cmds[0].directory, os.path.dirname(file))
'line': ['clang++', '-o', 'project2.o', '-c', self.assertEqual(cmds[0].filename, file)
'/home/john.doe/MyProject/project2.cpp']}, expected = [ 'clang++', '-o', 'project.o', '-c',
{ 'wd': '/home/john.doe/MyProjectB', '/home/john.doe/MyProject/project.cpp']
'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c', for arg, exp in zip(cmds[0].arguments, expected):
'/home/john.doe/MyProject/project2.cpp']} self.assertEqual(arg, exp)
]
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(): def test_2_compilecommand(self):
"""Check that iterator stops after the correct number of elements""" """Check file with 2 compile commands"""
cdb = CompilationDatabase.fromDirectory(kInputsDir) cdb = CompilationDatabase.fromDirectory(kInputsDir)
count = 0 cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp')
for cmd in cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp'): self.assertEqual(len(cmds), 2)
count += 1 expected = [
assert count <= 2 { '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)):
self.assertEqual(cmds[i].directory, expected[i]['wd'])
for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
self.assertEqual(arg, exp)
def test_compilationDB_references(): def test_compilecommand_iterator_stops(self):
"""Ensure CompilationsCommands are independent of the database""" """Check that iterator stops after the correct number of elements"""
cdb = CompilationDatabase.fromDirectory(kInputsDir) cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp') count = 0
del cdb for cmd in cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp'):
gc.collect() count += 1
workingdir = cmds[0].directory self.assertLessEqual(count, 2)
def test_compilationCommands_references(): def test_compilationDB_references(self):
"""Ensure CompilationsCommand keeps a reference to CompilationCommands""" """Ensure CompilationsCommands are independent of the database"""
cdb = CompilationDatabase.fromDirectory(kInputsDir) cdb = CompilationDatabase.fromDirectory(kInputsDir)
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp') cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
del cdb del cdb
cmd0 = cmds[0] gc.collect()
del cmds workingdir = cmds[0].directory
gc.collect()
workingdir = cmd0.directory
def test_compilationCommands_references(self):
"""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

View File

@ -1,16 +1,20 @@
from clang.cindex import TranslationUnit from clang.cindex import TranslationUnit
def check_completion_results(cr, expected): import unittest
assert cr is not None
assert len(cr.diagnostics) == 0
completions = [str(c) for c in cr.results]
for c in expected: class TestCodeCompletion(unittest.TestCase):
assert c in completions def check_completion_results(self, cr, expected):
self.assertIsNotNone(cr)
self.assertEqual(len(cr.diagnostics), 0)
def test_code_complete(): completions = [str(c) for c in cr.results]
files = [('fake.c', """
for c in expected:
self.assertIn(c, completions)
def test_code_complete(self):
files = [('fake.c', """
/// Aaa. /// Aaa.
int test1; int test1;
@ -22,20 +26,20 @@ void f() {
} }
""")] """)]
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files, tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION) options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
cr = tu.codeComplete('fake.c', 9, 1, unsaved_files=files, include_brief_comments=True) cr = tu.codeComplete('fake.c', 9, 1, unsaved_files=files, include_brief_comments=True)
expected = [ expected = [
"{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.", "{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.",
"{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.", "{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.",
"{'return', TypedText} || Priority: 40 || Availability: Available || Brief comment: None" "{'return', TypedText} || Priority: 40 || Availability: Available || Brief comment: None"
] ]
check_completion_results(cr, expected) self.check_completion_results(cr, expected)
def test_code_complete_availability(): def test_code_complete_availability(self):
files = [('fake.cpp', """ files = [('fake.cpp', """
class P { class P {
protected: protected:
int member; int member;
@ -52,24 +56,24 @@ void f(P x, Q y) {
} }
""")] """)]
tu = TranslationUnit.from_source('fake.cpp', ['-std=c++98'], unsaved_files=files) tu = TranslationUnit.from_source('fake.cpp', ['-std=c++98'], unsaved_files=files)
cr = tu.codeComplete('fake.cpp', 12, 5, unsaved_files=files) cr = tu.codeComplete('fake.cpp', 12, 5, unsaved_files=files)
expected = [ expected = [
"{'const', TypedText} || Priority: 40 || Availability: Available || Brief comment: None", "{'const', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'volatile', 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", "{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
"{'P', TypedText} | {'::', Text} || Priority: 75 || 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" "{'Q', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None"
] ]
check_completion_results(cr, expected) self.check_completion_results(cr, expected)
cr = tu.codeComplete('fake.cpp', 13, 5, unsaved_files=files) cr = tu.codeComplete('fake.cpp', 13, 5, unsaved_files=files)
expected = [ expected = [
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None", "{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
"{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: None", "{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: None",
"{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: None", "{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: None",
"{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: None" "{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 79 || Availability: Available || Brief comment: None"
] ]
check_completion_results(cr, expected) self.check_completion_results(cr, expected)

View File

@ -1,8 +1,12 @@
from clang.cindex import TranslationUnit from clang.cindex import TranslationUnit
from tests.cindex.util import get_cursor from tests.cindex.util import get_cursor
def test_comment(): import unittest
files = [('fake.c', """
class TestComment(unittest.TestCase):
def test_comment(self):
files = [('fake.c', """
/// Aaa. /// Aaa.
int test1; int test1;
@ -14,27 +18,25 @@ void f() {
} }
""")] """)]
# make a comment-aware TU # make a comment-aware TU
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files, tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION) options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
test1 = get_cursor(tu, 'test1') test1 = get_cursor(tu, 'test1')
assert test1 is not None, "Could not find test1." self.assertIsNotNone(test1, "Could not find test1.")
assert test1.type.is_pod() self.assertTrue(test1.type.is_pod())
raw = test1.raw_comment raw = test1.raw_comment
brief = test1.brief_comment brief = test1.brief_comment
assert raw == """/// Aaa.""" self.assertEqual(raw, """/// Aaa.""")
assert brief == """Aaa.""" self.assertEqual(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
test2 = get_cursor(tu, 'test2')
raw = test2.raw_comment
brief = test2.brief_comment
self.assertEqual(raw, """/// Bbb.\n/// x""")
self.assertEqual(brief, """Bbb. x""")
f = get_cursor(tu, 'f')
raw = f.raw_comment
brief = f.brief_comment
self.assertIsNone(raw)
self.assertIsNone(brief)

View File

@ -1,5 +1,6 @@
import ctypes import ctypes
import gc import gc
import unittest
from clang.cindex import AvailabilityKind from clang.cindex import AvailabilityKind
from clang.cindex import CursorKind from clang.cindex import CursorKind
@ -10,6 +11,7 @@ from .util import get_cursor
from .util import get_cursors from .util import get_cursors
from .util import get_tu from .util import get_tu
kInput = """\ kInput = """\
struct s0 { struct s0 {
int a; int a;
@ -30,257 +32,6 @@ void f0(int a0, int a1) {
} }
""" """
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_converting_constructor():
"""Ensure Cursor.is_converting_constructor works."""
source = 'class X { explicit X(int); X(double); X(); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
assert len(xs) == 4
assert xs[0].kind == CursorKind.CLASS_DECL
cs = xs[1:]
assert cs[0].kind == CursorKind.CONSTRUCTOR
assert cs[1].kind == CursorKind.CONSTRUCTOR
assert cs[2].kind == CursorKind.CONSTRUCTOR
assert not cs[0].is_converting_constructor()
assert cs[1].is_converting_constructor()
assert not cs[2].is_converting_constructor()
def test_is_copy_constructor():
"""Ensure Cursor.is_copy_constructor works."""
source = 'class X { X(); X(const X&); X(X&&); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
assert xs[0].kind == CursorKind.CLASS_DECL
cs = xs[1:]
assert cs[0].kind == CursorKind.CONSTRUCTOR
assert cs[1].kind == CursorKind.CONSTRUCTOR
assert cs[2].kind == CursorKind.CONSTRUCTOR
assert not cs[0].is_copy_constructor()
assert cs[1].is_copy_constructor()
assert not cs[2].is_copy_constructor()
def test_is_default_constructor():
"""Ensure Cursor.is_default_constructor works."""
source = 'class X { X(); X(int); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
assert xs[0].kind == CursorKind.CLASS_DECL
cs = xs[1:]
assert cs[0].kind == CursorKind.CONSTRUCTOR
assert cs[1].kind == CursorKind.CONSTRUCTOR
assert cs[0].is_default_constructor()
assert not cs[1].is_default_constructor()
def test_is_move_constructor():
"""Ensure Cursor.is_move_constructor works."""
source = 'class X { X(); X(const X&); X(X&&); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
assert xs[0].kind == CursorKind.CLASS_DECL
cs = xs[1:]
assert cs[0].kind == CursorKind.CONSTRUCTOR
assert cs[1].kind == CursorKind.CONSTRUCTOR
assert cs[2].kind == CursorKind.CONSTRUCTOR
assert not cs[0].is_move_constructor()
assert not cs[1].is_move_constructor()
assert cs[2].is_move_constructor()
def test_is_default_method():
"""Ensure Cursor.is_default_method works."""
source = 'class X { X() = default; }; class Y { Y(); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
ys = get_cursors(tu, 'Y')
assert len(xs) == 2
assert len(ys) == 2
xc = xs[1]
yc = ys[1]
assert xc.is_default_method()
assert not yc.is_default_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_is_scoped_enum():
"""Ensure Cursor.is_scoped_enum works."""
source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
regular_enum = get_cursor(tu, 'RegularEnum')
scoped_enum = get_cursor(tu, 'ScopedEnum')
assert cls is not None
assert regular_enum is not None
assert scoped_enum is not None
assert not cls.is_scoped_enum()
assert not regular_enum.is_scoped_enum()
assert scoped_enum.is_scoped_enum()
def test_underlying_type():
tu = get_tu('typedef int foo;')
typedef = get_cursor(tu, 'foo')
assert typedef is not None
assert typedef.kind.is_declaration()
underlying = typedef.underlying_typedef_type
assert underlying.kind == TypeKind.INT
kParentTest = """\ kParentTest = """\
class C { class C {
void f(); void f();
@ -288,188 +39,6 @@ kParentTest = """\
void C::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_annotation_template():
annotation = '__attribute__ ((annotate("annotation")))'
for source, kind in [
('int foo (T value) %s;', CursorKind.FUNCTION_TEMPLATE),
('class %s foo {};', CursorKind.CLASS_TEMPLATE),
]:
source = 'template<typename T> ' + (source % annotation)
tu = get_tu(source, lang="cpp")
foo = get_cursor(tu, 'foo')
assert foo is not None
assert foo.kind == kind
for c in foo.get_children():
if c.kind == CursorKind.ANNOTATE_ATTR:
assert c.displayname == "annotation"
break
else:
assert False, "Couldn't find annotation for {}".format(kind)
def test_result_type():
tu = get_tu('int foo();')
foo = get_cursor(tu, 'foo')
assert foo is not None
t = foo.result_type
assert t.kind == TypeKind.INT
def test_availability():
tu = get_tu('class A { A(A const&) = delete; };', lang='cpp')
# AvailabilityKind.AVAILABLE
cursor = get_cursor(tu, 'A')
assert cursor.kind == CursorKind.CLASS_DECL
assert cursor.availability == AvailabilityKind.AVAILABLE
# AvailabilityKind.NOT_AVAILABLE
cursors = get_cursors(tu, 'A')
for c in cursors:
if c.kind == CursorKind.CONSTRUCTOR:
assert c.availability == AvailabilityKind.NOT_AVAILABLE
break
else:
assert False, "Could not find cursor for deleted constructor"
# AvailabilityKind.DEPRECATED
tu = get_tu('void test() __attribute__((deprecated));', lang='cpp')
cursor = get_cursor(tu, 'test')
assert cursor.availability == AvailabilityKind.DEPRECATED
# AvailabilityKind.NOT_ACCESSIBLE is only used in the code completion results
def test_get_tokens():
"""Ensure we can map cursors back to tokens."""
tu = get_tu('int foo(int i);')
foo = get_cursor(tu, 'foo')
tokens = list(foo.get_tokens())
assert len(tokens) == 6
assert tokens[0].spelling == 'int'
assert tokens[1].spelling == 'foo'
def test_get_token_cursor():
"""Ensure we can map tokens to cursors."""
tu = get_tu('class A {}; int foo(A var = A());', lang='cpp')
foo = get_cursor(tu, 'foo')
for cursor in foo.walk_preorder():
if cursor.kind.is_expression() and not cursor.kind.is_statement():
break
else:
assert False, "Could not find default value expression"
tokens = list(cursor.get_tokens())
assert len(tokens) == 4, [t.spelling for t in tokens]
assert tokens[0].spelling == '='
assert tokens[1].spelling == 'A'
assert tokens[2].spelling == '('
assert tokens[3].spelling == ')'
t_cursor = tokens[1].cursor
assert t_cursor.kind == CursorKind.TYPE_REF
r_cursor = t_cursor.referenced # should not raise an exception
assert r_cursor.kind == CursorKind.CLASS_DECL
def test_get_arguments():
tu = get_tu('void foo(int i, int j);')
foo = get_cursor(tu, 'foo')
arguments = list(foo.get_arguments())
assert len(arguments) == 2
assert arguments[0].spelling == "i"
assert arguments[1].spelling == "j"
kTemplateArgTest = """\ kTemplateArgTest = """\
template <int kInt, typename T, bool kBool> template <int kInt, typename T, bool kBool>
@ -479,59 +48,494 @@ kTemplateArgTest = """\
void foo<-7, float, true>(); void foo<-7, float, true>();
""" """
def test_get_num_template_arguments(): class TestCursor(unittest.TestCase):
tu = get_tu(kTemplateArgTest, lang='cpp') def test_get_children(self):
foos = get_cursors(tu, 'foo') tu = get_tu(kInput)
assert foos[1].get_num_template_arguments() == 3 it = tu.cursor.get_children()
tu_nodes = list(it)
def test_get_template_argument_kind(): self.assertEqual(len(tu_nodes), 3)
tu = get_tu(kTemplateArgTest, lang='cpp') for cursor in tu_nodes:
foos = get_cursors(tu, 'foo') self.assertIsNotNone(cursor.translation_unit)
assert foos[1].get_template_argument_kind(0) == TemplateArgumentKind.INTEGRAL self.assertNotEqual(tu_nodes[0], tu_nodes[1])
assert foos[1].get_template_argument_kind(1) == TemplateArgumentKind.TYPE self.assertEqual(tu_nodes[0].kind, CursorKind.STRUCT_DECL)
assert foos[1].get_template_argument_kind(2) == TemplateArgumentKind.INTEGRAL self.assertEqual(tu_nodes[0].spelling, 's0')
self.assertEqual(tu_nodes[0].is_definition(), True)
self.assertEqual(tu_nodes[0].location.file.name, 't.c')
self.assertEqual(tu_nodes[0].location.line, 1)
self.assertEqual(tu_nodes[0].location.column, 8)
self.assertGreater(tu_nodes[0].hash, 0)
self.assertIsNotNone(tu_nodes[0].translation_unit)
def test_get_template_argument_type(): s0_nodes = list(tu_nodes[0].get_children())
tu = get_tu(kTemplateArgTest, lang='cpp') self.assertEqual(len(s0_nodes), 2)
foos = get_cursors(tu, 'foo') self.assertEqual(s0_nodes[0].kind, CursorKind.FIELD_DECL)
self.assertEqual(s0_nodes[0].spelling, 'a')
self.assertEqual(s0_nodes[0].type.kind, TypeKind.INT)
self.assertEqual(s0_nodes[1].kind, CursorKind.FIELD_DECL)
self.assertEqual(s0_nodes[1].spelling, 'b')
self.assertEqual(s0_nodes[1].type.kind, TypeKind.INT)
assert foos[1].get_template_argument_type(1).kind == TypeKind.FLOAT self.assertEqual(tu_nodes[1].kind, CursorKind.STRUCT_DECL)
self.assertEqual(tu_nodes[1].spelling, 's1')
self.assertEqual(tu_nodes[1].displayname, 's1')
self.assertEqual(tu_nodes[1].is_definition(), False)
def test_get_template_argument_value(): self.assertEqual(tu_nodes[2].kind, CursorKind.FUNCTION_DECL)
tu = get_tu(kTemplateArgTest, lang='cpp') self.assertEqual(tu_nodes[2].spelling, 'f0')
foos = get_cursors(tu, 'foo') self.assertEqual(tu_nodes[2].displayname, 'f0(int, int)')
self.assertEqual(tu_nodes[2].is_definition(), True)
assert foos[1].get_template_argument_value(0) == -7 def test_references(self):
assert foos[1].get_template_argument_value(2) == True """Ensure that references to TranslationUnit are kept."""
tu = get_tu('int x;')
cursors = list(tu.cursor.get_children())
self.assertGreater(len(cursors), 0)
def test_get_template_argument_unsigned_value(): cursor = cursors[0]
tu = get_tu(kTemplateArgTest, lang='cpp') self.assertIsInstance(cursor.translation_unit, TranslationUnit)
foos = get_cursors(tu, 'foo')
assert foos[1].get_template_argument_unsigned_value(0) == 2 ** 32 - 7 # Delete reference to TU and perform a full GC.
assert foos[1].get_template_argument_unsigned_value(2) == True del tu
gc.collect()
self.assertIsInstance(cursor.translation_unit, TranslationUnit)
def test_referenced(): # If the TU was destroyed, this should cause a segfault.
tu = get_tu('void foo(); void bar() { foo(); }') parent = cursor.semantic_parent
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(): def test_canonical(self):
kInputForMangling = """\ source = 'struct X; struct X; struct X { int member; };'
int foo(int, int); tu = get_tu(source)
"""
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 cursors = []
# and force the target. To enable this test to pass on all platforms, accept for cursor in tu.cursor.get_children():
# all valid manglings. if cursor.spelling == 'X':
# [c-index-test handles this by running the source through clang, emitting cursors.append(cursor)
# an AST file and running libclang on that AST file]
assert foo.mangled_name in ('_Z3fooii', '__Z3fooii', '?foo@@YAHHH') self.assertEqual(len(cursors), 3)
self.assertEqual(cursors[1].canonical, cursors[2].canonical)
def test_is_const_method(self):
"""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')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_const_method())
self.assertFalse(bar.is_const_method())
def test_is_converting_constructor(self):
"""Ensure Cursor.is_converting_constructor works."""
source = 'class X { explicit X(int); X(double); X(); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(len(xs), 4)
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[2].kind, CursorKind.CONSTRUCTOR)
self.assertFalse(cs[0].is_converting_constructor())
self.assertTrue(cs[1].is_converting_constructor())
self.assertFalse(cs[2].is_converting_constructor())
def test_is_copy_constructor(self):
"""Ensure Cursor.is_copy_constructor works."""
source = 'class X { X(); X(const X&); X(X&&); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[2].kind, CursorKind.CONSTRUCTOR)
self.assertFalse(cs[0].is_copy_constructor())
self.assertTrue(cs[1].is_copy_constructor())
self.assertFalse(cs[2].is_copy_constructor())
def test_is_default_constructor(self):
"""Ensure Cursor.is_default_constructor works."""
source = 'class X { X(); X(int); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertTrue(cs[0].is_default_constructor())
self.assertFalse(cs[1].is_default_constructor())
def test_is_move_constructor(self):
"""Ensure Cursor.is_move_constructor works."""
source = 'class X { X(); X(const X&); X(X&&); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
self.assertEqual(xs[0].kind, CursorKind.CLASS_DECL)
cs = xs[1:]
self.assertEqual(cs[0].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[1].kind, CursorKind.CONSTRUCTOR)
self.assertEqual(cs[2].kind, CursorKind.CONSTRUCTOR)
self.assertFalse(cs[0].is_move_constructor())
self.assertFalse(cs[1].is_move_constructor())
self.assertTrue(cs[2].is_move_constructor())
def test_is_default_method(self):
"""Ensure Cursor.is_default_method works."""
source = 'class X { X() = default; }; class Y { Y(); };'
tu = get_tu(source, lang='cpp')
xs = get_cursors(tu, 'X')
ys = get_cursors(tu, 'Y')
self.assertEqual(len(xs), 2)
self.assertEqual(len(ys), 2)
xc = xs[1]
yc = ys[1]
self.assertTrue(xc.is_default_method())
self.assertFalse(yc.is_default_method())
def test_is_mutable_field(self):
"""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_')
self.assertIsNotNone(cls)
self.assertIsNotNone(x_)
self.assertIsNotNone(y_)
self.assertFalse(x_.is_mutable_field())
self.assertTrue(y_.is_mutable_field())
def test_is_static_method(self):
"""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')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_static_method())
self.assertFalse(bar.is_static_method())
def test_is_pure_virtual_method(self):
"""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')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_pure_virtual_method())
self.assertFalse(bar.is_pure_virtual_method())
def test_is_virtual_method(self):
"""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')
self.assertIsNotNone(cls)
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertTrue(foo.is_virtual_method())
self.assertFalse(bar.is_virtual_method())
def test_is_scoped_enum(self):
"""Ensure Cursor.is_scoped_enum works."""
source = 'class X {}; enum RegularEnum {}; enum class ScopedEnum {};'
tu = get_tu(source, lang='cpp')
cls = get_cursor(tu, 'X')
regular_enum = get_cursor(tu, 'RegularEnum')
scoped_enum = get_cursor(tu, 'ScopedEnum')
self.assertIsNotNone(cls)
self.assertIsNotNone(regular_enum)
self.assertIsNotNone(scoped_enum)
self.assertFalse(cls.is_scoped_enum())
self.assertFalse(regular_enum.is_scoped_enum())
self.assertTrue(scoped_enum.is_scoped_enum())
def test_underlying_type(self):
tu = get_tu('typedef int foo;')
typedef = get_cursor(tu, 'foo')
self.assertIsNotNone(typedef)
self.assertTrue(typedef.kind.is_declaration())
underlying = typedef.underlying_typedef_type
self.assertEqual(underlying.kind, TypeKind.INT)
def test_semantic_parent(self):
tu = get_tu(kParentTest, 'cpp')
curs = get_cursors(tu, 'f')
decl = get_cursor(tu, 'C')
self.assertEqual(len(curs), 2)
self.assertEqual(curs[0].semantic_parent, curs[1].semantic_parent)
self.assertEqual(curs[0].semantic_parent, decl)
def test_lexical_parent(self):
tu = get_tu(kParentTest, 'cpp')
curs = get_cursors(tu, 'f')
decl = get_cursor(tu, 'C')
self.assertEqual(len(curs), 2)
self.assertNotEqual(curs[0].lexical_parent, curs[1].lexical_parent)
self.assertEqual(curs[0].lexical_parent, decl)
self.assertEqual(curs[1].lexical_parent, tu.cursor)
def test_enum_type(self):
tu = get_tu('enum TEST { FOO=1, BAR=2 };')
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
enum_type = enum.enum_type
self.assertEqual(enum_type.kind, TypeKind.UINT)
def test_enum_type_cpp(self):
tu = get_tu('enum TEST : long long { FOO=1, BAR=2 };', lang="cpp")
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
self.assertEqual(enum.enum_type.kind, TypeKind.LONGLONG)
def test_objc_type_encoding(self):
tu = get_tu('int i;', lang='objc')
i = get_cursor(tu, 'i')
self.assertIsNotNone(i)
self.assertEqual(i.objc_type_encoding, 'i')
def test_enum_values(self):
tu = get_tu('enum TEST { SPAM=1, EGG, HAM = EGG * 20};')
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
enum_constants = list(enum.get_children())
self.assertEqual(len(enum_constants), 3)
spam, egg, ham = enum_constants
self.assertEqual(spam.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(spam.enum_value, 1)
self.assertEqual(egg.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(egg.enum_value, 2)
self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(ham.enum_value, 40)
def test_enum_values_cpp(self):
tu = get_tu('enum TEST : long long { SPAM = -1, HAM = 0x10000000000};', lang="cpp")
enum = get_cursor(tu, 'TEST')
self.assertIsNotNone(enum)
self.assertEqual(enum.kind, CursorKind.ENUM_DECL)
enum_constants = list(enum.get_children())
self.assertEqual(len(enum_constants), 2)
spam, ham = enum_constants
self.assertEqual(spam.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(spam.enum_value, -1)
self.assertEqual(ham.kind, CursorKind.ENUM_CONSTANT_DECL)
self.assertEqual(ham.enum_value, 0x10000000000)
def test_annotation_attribute(self):
tu = get_tu('int foo (void) __attribute__ ((annotate("here be annotation attribute")));')
foo = get_cursor(tu, 'foo')
self.assertIsNotNone(foo)
for c in foo.get_children():
if c.kind == CursorKind.ANNOTATE_ATTR:
self.assertEqual(c.displayname, "here be annotation attribute")
break
else:
self.fail("Couldn't find annotation")
def test_annotation_template(self):
annotation = '__attribute__ ((annotate("annotation")))'
for source, kind in [
('int foo (T value) %s;', CursorKind.FUNCTION_TEMPLATE),
('class %s foo {};', CursorKind.CLASS_TEMPLATE),
]:
source = 'template<typename T> ' + (source % annotation)
tu = get_tu(source, lang="cpp")
foo = get_cursor(tu, 'foo')
self.assertIsNotNone(foo)
self.assertEqual(foo.kind, kind)
for c in foo.get_children():
if c.kind == CursorKind.ANNOTATE_ATTR:
self.assertEqual(c.displayname, "annotation")
break
else:
self.fail("Couldn't find annotation for {}".format(kind))
def test_result_type(self):
tu = get_tu('int foo();')
foo = get_cursor(tu, 'foo')
self.assertIsNotNone(foo)
t = foo.result_type
self.assertEqual(t.kind, TypeKind.INT)
def test_availability(self):
tu = get_tu('class A { A(A const&) = delete; };', lang='cpp')
# AvailabilityKind.AVAILABLE
cursor = get_cursor(tu, 'A')
self.assertEqual(cursor.kind, CursorKind.CLASS_DECL)
self.assertEqual(cursor.availability, AvailabilityKind.AVAILABLE)
# AvailabilityKind.NOT_AVAILABLE
cursors = get_cursors(tu, 'A')
for c in cursors:
if c.kind == CursorKind.CONSTRUCTOR:
self.assertEqual(c.availability, AvailabilityKind.NOT_AVAILABLE)
break
else:
self.fail("Could not find cursor for deleted constructor")
# AvailabilityKind.DEPRECATED
tu = get_tu('void test() __attribute__((deprecated));', lang='cpp')
cursor = get_cursor(tu, 'test')
self.assertEqual(cursor.availability, AvailabilityKind.DEPRECATED)
# AvailabilityKind.NOT_ACCESSIBLE is only used in the code completion results
def test_get_tokens(self):
"""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())
self.assertEqual(len(tokens), 6)
self.assertEqual(tokens[0].spelling, 'int')
self.assertEqual(tokens[1].spelling, 'foo')
def test_get_token_cursor(self):
"""Ensure we can map tokens to cursors."""
tu = get_tu('class A {}; int foo(A var = A());', lang='cpp')
foo = get_cursor(tu, 'foo')
for cursor in foo.walk_preorder():
if cursor.kind.is_expression() and not cursor.kind.is_statement():
break
else:
self.fail("Could not find default value expression")
tokens = list(cursor.get_tokens())
self.assertEqual(len(tokens), 4, [t.spelling for t in tokens])
self.assertEqual(tokens[0].spelling, '=')
self.assertEqual(tokens[1].spelling, 'A')
self.assertEqual(tokens[2].spelling, '(')
self.assertEqual(tokens[3].spelling, ')')
t_cursor = tokens[1].cursor
self.assertEqual(t_cursor.kind, CursorKind.TYPE_REF)
r_cursor = t_cursor.referenced # should not raise an exception
self.assertEqual(r_cursor.kind, CursorKind.CLASS_DECL)
def test_get_arguments(self):
tu = get_tu('void foo(int i, int j);')
foo = get_cursor(tu, 'foo')
arguments = list(foo.get_arguments())
self.assertEqual(len(arguments), 2)
self.assertEqual(arguments[0].spelling, "i")
self.assertEqual(arguments[1].spelling, "j")
def test_get_num_template_arguments(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_num_template_arguments(), 3)
def test_get_template_argument_kind(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_kind(0), TemplateArgumentKind.INTEGRAL)
self.assertEqual(foos[1].get_template_argument_kind(1), TemplateArgumentKind.TYPE)
self.assertEqual(foos[1].get_template_argument_kind(2), TemplateArgumentKind.INTEGRAL)
def test_get_template_argument_type(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_type(1).kind, TypeKind.FLOAT)
def test_get_template_argument_value(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_value(0), -7)
self.assertEqual(foos[1].get_template_argument_value(2), True)
def test_get_template_argument_unsigned_value(self):
tu = get_tu(kTemplateArgTest, lang='cpp')
foos = get_cursors(tu, 'foo')
self.assertEqual(foos[1].get_template_argument_unsigned_value(0), 2 ** 32 - 7)
self.assertEqual(foos[1].get_template_argument_unsigned_value(2), True)
def test_referenced(self):
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:
self.assertEqual(c.referenced.spelling, foo.spelling)
break
def test_mangled_name(self):
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]
self.assertIn(foo.mangled_name, ('_Z3fooii', '__Z3fooii', '?foo@@YAHHH'))

View File

@ -1,49 +1,53 @@
from clang.cindex import CursorKind from clang.cindex import CursorKind
def test_name(): import unittest
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(): class TestCursorKind(unittest.TestCase):
"""Check that every kind classifies to exactly one group.""" def test_name(self):
self.assertTrue(CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL')
assert CursorKind.UNEXPOSED_DECL.is_declaration() def test_get_all_kinds(self):
assert CursorKind.TYPE_REF.is_reference() kinds = CursorKind.get_all_kinds()
assert CursorKind.DECL_REF_EXPR.is_expression() self.assertIn(CursorKind.UNEXPOSED_DECL, kinds)
assert CursorKind.UNEXPOSED_STMT.is_statement() self.assertIn(CursorKind.TRANSLATION_UNIT, kinds)
assert CursorKind.INVALID_FILE.is_invalid() self.assertIn(CursorKind.VARIABLE_REF, kinds)
self.assertIn(CursorKind.LAMBDA_EXPR, kinds)
self.assertIn(CursorKind.OBJ_BOOL_LITERAL_EXPR, kinds)
self.assertIn(CursorKind.OBJ_SELF_EXPR, kinds)
self.assertIn(CursorKind.MS_ASM_STMT, kinds)
self.assertIn(CursorKind.MODULE_IMPORT_DECL, kinds)
self.assertIn(CursorKind.TYPE_ALIAS_TEMPLATE_DECL, kinds)
assert CursorKind.TRANSLATION_UNIT.is_translation_unit() def test_kind_groups(self):
assert not CursorKind.TYPE_REF.is_translation_unit() """Check that every kind classifies to exactly one group."""
assert CursorKind.PREPROCESSING_DIRECTIVE.is_preprocessing() self.assertTrue(CursorKind.UNEXPOSED_DECL.is_declaration())
assert not CursorKind.TYPE_REF.is_preprocessing() self.assertTrue(CursorKind.TYPE_REF.is_reference())
self.assertTrue(CursorKind.DECL_REF_EXPR.is_expression())
self.assertTrue(CursorKind.UNEXPOSED_STMT.is_statement())
self.assertTrue(CursorKind.INVALID_FILE.is_invalid())
assert CursorKind.UNEXPOSED_DECL.is_unexposed() self.assertTrue(CursorKind.TRANSLATION_UNIT.is_translation_unit())
assert not CursorKind.TYPE_REF.is_unexposed() self.assertFalse(CursorKind.TYPE_REF.is_translation_unit())
for k in CursorKind.get_all_kinds(): self.assertTrue(CursorKind.PREPROCESSING_DIRECTIVE.is_preprocessing())
group = [n for n in ('is_declaration', 'is_reference', 'is_expression', self.assertFalse(CursorKind.TYPE_REF.is_preprocessing())
'is_statement', 'is_invalid', 'is_attribute')
if getattr(k, n)()]
if k in ( CursorKind.TRANSLATION_UNIT, self.assertTrue(CursorKind.UNEXPOSED_DECL.is_unexposed())
CursorKind.MACRO_DEFINITION, self.assertFalse(CursorKind.TYPE_REF.is_unexposed())
CursorKind.MACRO_INSTANTIATION,
CursorKind.INCLUSION_DIRECTIVE, for k in CursorKind.get_all_kinds():
CursorKind.PREPROCESSING_DIRECTIVE, group = [n for n in ('is_declaration', 'is_reference', 'is_expression',
CursorKind.OVERLOAD_CANDIDATE): 'is_statement', 'is_invalid', 'is_attribute')
assert len(group) == 0 if getattr(k, n)()]
else:
assert len(group) == 1 if k in ( CursorKind.TRANSLATION_UNIT,
CursorKind.MACRO_DEFINITION,
CursorKind.MACRO_INSTANTIATION,
CursorKind.INCLUSION_DIRECTIVE,
CursorKind.PREPROCESSING_DIRECTIVE,
CursorKind.OVERLOAD_CANDIDATE):
self.assertEqual(len(group), 0)
else:
self.assertEqual(len(group), 1)

View File

@ -1,102 +1,105 @@
from clang.cindex import * from clang.cindex import *
from .util import get_tu from .util import get_tu
import unittest
# FIXME: We need support for invalid translation units to test better. # 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(): class TestDiagnostics(unittest.TestCase):
# FIXME: We aren't getting notes here for some reason. def test_diagnostic_warning(self):
tu = get_tu('#define A x\nvoid *A = 1;\n') tu = get_tu('int f0() {}\n')
assert len(tu.diagnostics) == 1 self.assertEqual(len(tu.diagnostics), 1)
assert tu.diagnostics[0].severity == Diagnostic.Warning self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
assert tu.diagnostics[0].location.line == 2 self.assertEqual(tu.diagnostics[0].location.line, 1)
assert tu.diagnostics[0].location.column == 7 self.assertEqual(tu.diagnostics[0].location.column, 11)
assert 'incompatible' in tu.diagnostics[0].spelling self.assertEqual(tu.diagnostics[0].spelling,
# assert tu.diagnostics[1].severity == Diagnostic.Note 'control reaches end of non-void function')
# 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(): def test_diagnostic_note(self):
tu = get_tu('struct { int f0; } x = { f0 : 1 };') # FIXME: We aren't getting notes here for some reason.
assert len(tu.diagnostics) == 1 tu = get_tu('#define A x\nvoid *A = 1;\n')
assert tu.diagnostics[0].severity == Diagnostic.Warning self.assertEqual(len(tu.diagnostics), 1)
assert tu.diagnostics[0].location.line == 1 self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
assert tu.diagnostics[0].location.column == 26 self.assertEqual(tu.diagnostics[0].location.line, 2)
assert tu.diagnostics[0].spelling.startswith('use of GNU old-style') self.assertEqual(tu.diagnostics[0].location.column, 7)
assert len(tu.diagnostics[0].fixits) == 1 self.assertIn('incompatible', tu.diagnostics[0].spelling)
assert tu.diagnostics[0].fixits[0].range.start.line == 1 # self.assertEqual(tu.diagnostics[1].severity, Diagnostic.Note)
assert tu.diagnostics[0].fixits[0].range.start.column == 26 # self.assertEqual(tu.diagnostics[1].location.line, 1)
assert tu.diagnostics[0].fixits[0].range.end.line == 1 # self.assertEqual(tu.diagnostics[1].location.column, 11)
assert tu.diagnostics[0].fixits[0].range.end.column == 30 # self.assertEqual(tu.diagnostics[1].spelling, 'instantiated from')
assert tu.diagnostics[0].fixits[0].value == '.f0 = '
def test_diagnostic_range(): def test_diagnostic_fixit(self):
tu = get_tu('void f() { int i = "a" + 1; }') tu = get_tu('struct { int f0; } x = { f0 : 1 };')
assert len(tu.diagnostics) == 1 self.assertEqual(len(tu.diagnostics), 1)
assert tu.diagnostics[0].severity == Diagnostic.Warning self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
assert tu.diagnostics[0].location.line == 1 self.assertEqual(tu.diagnostics[0].location.line, 1)
assert tu.diagnostics[0].location.column == 16 self.assertEqual(tu.diagnostics[0].location.column, 26)
assert tu.diagnostics[0].spelling.startswith('incompatible pointer to') self.assertRegexpMatches(tu.diagnostics[0].spelling,
assert len(tu.diagnostics[0].fixits) == 0 'use of GNU old-style.*')
assert len(tu.diagnostics[0].ranges) == 1 self.assertEqual(len(tu.diagnostics[0].fixits), 1)
assert tu.diagnostics[0].ranges[0].start.line == 1 self.assertEqual(tu.diagnostics[0].fixits[0].range.start.line, 1)
assert tu.diagnostics[0].ranges[0].start.column == 20 self.assertEqual(tu.diagnostics[0].fixits[0].range.start.column, 26)
assert tu.diagnostics[0].ranges[0].end.line == 1 self.assertEqual(tu.diagnostics[0].fixits[0].range.end.line, 1)
assert tu.diagnostics[0].ranges[0].end.column == 27 self.assertEqual(tu.diagnostics[0].fixits[0].range.end.column, 30)
try: self.assertEqual(tu.diagnostics[0].fixits[0].value, '.f0 = ')
tu.diagnostics[0].ranges[1].start.line
except IndexError:
assert True
else:
assert False
def test_diagnostic_category(): def test_diagnostic_range(self):
"""Ensure that category properties work.""" tu = get_tu('void f() { int i = "a" + 1; }')
tu = get_tu('int f(int i) { return 7; }', all_warnings=True) self.assertEqual(len(tu.diagnostics), 1)
assert len(tu.diagnostics) == 1 self.assertEqual(tu.diagnostics[0].severity, Diagnostic.Warning)
d = tu.diagnostics[0] self.assertEqual(tu.diagnostics[0].location.line, 1)
self.assertEqual(tu.diagnostics[0].location.column, 16)
self.assertRegexpMatches(tu.diagnostics[0].spelling,
'incompatible pointer to.*')
self.assertEqual(len(tu.diagnostics[0].fixits), 0)
self.assertEqual(len(tu.diagnostics[0].ranges), 1)
self.assertEqual(tu.diagnostics[0].ranges[0].start.line, 1)
self.assertEqual(tu.diagnostics[0].ranges[0].start.column, 20)
self.assertEqual(tu.diagnostics[0].ranges[0].end.line, 1)
self.assertEqual(tu.diagnostics[0].ranges[0].end.column, 27)
with self.assertRaises(IndexError):
tu.diagnostics[0].ranges[1].start.line
assert d.severity == Diagnostic.Warning def test_diagnostic_category(self):
assert d.location.line == 1 """Ensure that category properties work."""
assert d.location.column == 11 tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
self.assertEqual(len(tu.diagnostics), 1)
d = tu.diagnostics[0]
assert d.category_number == 2 self.assertEqual(d.severity, Diagnostic.Warning)
assert d.category_name == 'Semantic Issue' self.assertEqual(d.location.line, 1)
self.assertEqual(d.location.column, 11)
def test_diagnostic_option(): self.assertEqual(d.category_number, 2)
"""Ensure that category option properties work.""" self.assertEqual(d.category_name, 'Semantic Issue')
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' def test_diagnostic_option(self):
assert d.disable_option == '-Wno-unused-parameter' """Ensure that category option properties work."""
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
self.assertEqual(len(tu.diagnostics), 1)
d = tu.diagnostics[0]
def test_diagnostic_children(): self.assertEqual(d.option, '-Wunused-parameter')
tu = get_tu('void f(int x) {} void g() { f(); }') self.assertEqual(d.disable_option, '-Wno-unused-parameter')
assert len(tu.diagnostics) == 1
d = tu.diagnostics[0]
children = d.children def test_diagnostic_children(self):
assert len(children) == 1 tu = get_tu('void f(int x) {} void g() { f(); }')
assert children[0].severity == Diagnostic.Note self.assertEqual(len(tu.diagnostics), 1)
assert children[0].spelling.endswith('declared here') d = tu.diagnostics[0]
assert children[0].location.line == 1
assert children[0].location.column == 1
def test_diagnostic_string_repr(): children = d.children
tu = get_tu('struct MissingSemicolon{}') self.assertEqual(len(children), 1)
assert len(tu.diagnostics) == 1 self.assertEqual(children[0].severity, Diagnostic.Note)
d = tu.diagnostics[0] self.assertRegexpMatches(children[0].spelling,
'.*declared here')
self.assertEqual(children[0].location.line, 1)
self.assertEqual(children[0].location.column, 1)
assert repr(d) == '<Diagnostic severity 3, location <SourceLocation file \'t.c\', line 1, column 26>, spelling "expected \';\' after struct">' def test_diagnostic_string_repr(self):
tu = get_tu('struct MissingSemicolon{}')
self.assertEqual(len(tu.diagnostics), 1)
d = tu.diagnostics[0]
self.assertEqual(repr(d), '<Diagnostic severity 3, location <SourceLocation file \'t.c\', line 1, column 26>, spelling "expected \';\' after struct">')

View File

@ -2,6 +2,8 @@ import clang.cindex
from clang.cindex import ExceptionSpecificationKind from clang.cindex import ExceptionSpecificationKind
from .util import get_tu from .util import get_tu
import unittest
def find_function_declarations(node, declarations=[]): def find_function_declarations(node, declarations=[]):
if node.kind == clang.cindex.CursorKind.FUNCTION_DECL: if node.kind == clang.cindex.CursorKind.FUNCTION_DECL:
@ -11,17 +13,18 @@ def find_function_declarations(node, declarations=[]):
return declarations return declarations
def test_exception_specification_kind(): class TestExceptionSpecificationKind(unittest.TestCase):
source = """int square1(int x); def test_exception_specification_kind(self):
int square2(int x) noexcept; source = """int square1(int x);
int square3(int x) noexcept(noexcept(x * x));""" int square2(int x) noexcept;
int square3(int x) noexcept(noexcept(x * x));"""
tu = get_tu(source, lang='cpp', flags=['-std=c++14']) tu = get_tu(source, lang='cpp', flags=['-std=c++14'])
declarations = find_function_declarations(tu.cursor) declarations = find_function_declarations(tu.cursor)
expected = [ expected = [
('square1', ExceptionSpecificationKind.NONE), ('square1', ExceptionSpecificationKind.NONE),
('square2', ExceptionSpecificationKind.BASIC_NOEXCEPT), ('square2', ExceptionSpecificationKind.BASIC_NOEXCEPT),
('square3', ExceptionSpecificationKind.COMPUTED_NOEXCEPT) ('square3', ExceptionSpecificationKind.COMPUTED_NOEXCEPT)
] ]
assert declarations == expected self.assertListEqual(declarations, expected)

View File

@ -1,9 +1,13 @@
from clang.cindex import Index, File from clang.cindex import Index, File
def test_file(): import unittest
index = Index.create()
tu = index.parse('t.c', unsaved_files = [('t.c', "")])
file = File.from_name(tu, "t.c") class TestFile(unittest.TestCase):
assert str(file) == "t.c" def test_file(self):
assert file.name == "t.c" index = Index.create()
assert repr(file) == "<File: t.c>" tu = index.parse('t.c', unsaved_files = [('t.c', "")])
file = File.from_name(tu, "t.c")
self.assertEqual(str(file), "t.c")
self.assertEqual(file.name, "t.c")
self.assertEqual(repr(file), "<File: t.c>")

View File

@ -1,17 +1,21 @@
from clang.cindex import * from clang.cindex import *
import os import os
import unittest
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS') kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
def test_create():
index = Index.create()
# FIXME: test Index.read class TestIndex(unittest.TestCase):
def test_create(self):
index = Index.create()
def test_parse(): # FIXME: test Index.read
index = Index.create()
assert isinstance(index, Index) def test_parse(self):
tu = index.parse(os.path.join(kInputsDir, 'hello.cpp')) index = Index.create()
assert isinstance(tu, TranslationUnit) self.assertIsInstance(index, Index)
tu = index.parse(None, ['-c', os.path.join(kInputsDir, 'hello.cpp')]) tu = index.parse(os.path.join(kInputsDir, 'hello.cpp'))
assert isinstance(tu, TranslationUnit) self.assertIsInstance(tu, TranslationUnit)
tu = index.parse(None, ['-c', os.path.join(kInputsDir, 'hello.cpp')])
self.assertIsInstance(tu, TranslationUnit)

View File

@ -1,4 +1,3 @@
from clang.cindex import LinkageKind from clang.cindex import LinkageKind
from clang.cindex import Cursor from clang.cindex import Cursor
from clang.cindex import TranslationUnit from clang.cindex import TranslationUnit
@ -6,25 +5,28 @@ from clang.cindex import TranslationUnit
from .util import get_cursor from .util import get_cursor
from .util import get_tu from .util import get_tu
def test_linkage(): import unittest
"""Ensure that linkage specifers are available on cursors"""
tu = get_tu("""
class TestLinkage(unittest.TestCase):
def test_linkage(self):
"""Ensure that linkage specifers are available on cursors"""
tu = get_tu("""
void foo() { int no_linkage; } void foo() { int no_linkage; }
static int internal; static int internal;
namespace { extern int unique_external; } namespace { extern int unique_external; }
extern int external; extern int external;
""", lang = 'cpp') """, lang = 'cpp')
no_linkage = get_cursor(tu.cursor, 'no_linkage') no_linkage = get_cursor(tu.cursor, 'no_linkage')
assert no_linkage.linkage == LinkageKind.NO_LINKAGE; self.assertEqual(no_linkage.linkage, LinkageKind.NO_LINKAGE)
internal = get_cursor(tu.cursor, 'internal') internal = get_cursor(tu.cursor, 'internal')
assert internal.linkage == LinkageKind.INTERNAL self.assertEqual(internal.linkage, LinkageKind.INTERNAL)
unique_external = get_cursor(tu.cursor, 'unique_external') unique_external = get_cursor(tu.cursor, 'unique_external')
assert unique_external.linkage == LinkageKind.UNIQUE_EXTERNAL self.assertEqual(unique_external.linkage, LinkageKind.UNIQUE_EXTERNAL)
external = get_cursor(tu.cursor, 'external')
assert external.linkage == LinkageKind.EXTERNAL
external = get_cursor(tu.cursor, 'external')
self.assertEqual(external.linkage, LinkageKind.EXTERNAL)

View File

@ -5,91 +5,96 @@ from clang.cindex import SourceRange
from .util import get_cursor from .util import get_cursor
from .util import get_tu from .util import get_tu
import unittest
baseInput="int one;\nint two;\n" 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(): class TestLocation(unittest.TestCase):
tu = get_tu(baseInput) def assert_location(self, loc, line, column, offset):
one = get_cursor(tu, 'one') self.assertEqual(loc.line, line)
two = get_cursor(tu, 'two') self.assertEqual(loc.column, column)
self.assertEqual(loc.offset, offset)
assert one is not None def test_location(self):
assert two is not None tu = get_tu(baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
assert_location(one.location,line=1,column=5,offset=4) self.assertIsNotNone(one)
assert_location(two.location,line=2,column=5,offset=13) self.assertIsNotNone(two)
# adding a linebreak at top should keep columns same self.assert_location(one.location,line=1,column=5,offset=4)
tu = get_tu('\n' + baseInput) self.assert_location(two.location,line=2,column=5,offset=13)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
assert one is not None # adding a linebreak at top should keep columns same
assert two is not None tu = get_tu('\n' + baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
assert_location(one.location,line=2,column=5,offset=5) self.assertIsNotNone(one)
assert_location(two.location,line=3,column=5,offset=14) self.assertIsNotNone(two)
# adding a space should affect column on first line only self.assert_location(one.location,line=2,column=5,offset=5)
tu = get_tu(' ' + baseInput) self.assert_location(two.location,line=3,column=5,offset=14)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
assert_location(one.location,line=1,column=6,offset=5) # adding a space should affect column on first line only
assert_location(two.location,line=2,column=5,offset=14) tu = get_tu(' ' + baseInput)
one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
# define the expected location ourselves and see if it matches self.assert_location(one.location,line=1,column=6,offset=5)
# the returned location self.assert_location(two.location,line=2,column=5,offset=14)
tu = get_tu(baseInput)
file = File.from_name(tu, 't.c') # define the expected location ourselves and see if it matches
location = SourceLocation.from_position(tu, file, 1, 5) # the returned location
cursor = Cursor.from_location(tu, location) tu = get_tu(baseInput)
one = get_cursor(tu, 'one') file = File.from_name(tu, 't.c')
assert one is not None location = SourceLocation.from_position(tu, file, 1, 5)
assert one == cursor cursor = Cursor.from_location(tu, location)
# Ensure locations referring to the same entity are equivalent. one = get_cursor(tu, 'one')
location2 = SourceLocation.from_position(tu, file, 1, 5) self.assertIsNotNone(one)
assert location == location2 self.assertEqual(one, cursor)
location3 = SourceLocation.from_position(tu, file, 1, 4)
assert location2 != location3
offset_location = SourceLocation.from_offset(tu, file, 5) # Ensure locations referring to the same entity are equivalent.
cursor = Cursor.from_location(tu, offset_location) location2 = SourceLocation.from_position(tu, file, 1, 5)
verified = False self.assertEqual(location, location2)
for n in [n for n in tu.cursor.get_children() if n.spelling == 'one']: location3 = SourceLocation.from_position(tu, file, 1, 4)
assert n == cursor self.assertNotEqual(location2, location3)
verified = True
assert verified 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']:
self.assertEqual(n, cursor)
verified = True
def test_extent(): self.assertTrue(verified)
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) def test_extent(self):
assert_location(one.extent.end,line=1,column=8,offset=7) tu = get_tu(baseInput)
assert baseInput[one.extent.start.offset:one.extent.end.offset] == "int one" one = get_cursor(tu, 'one')
two = get_cursor(tu, 'two')
assert_location(two.extent.start,line=2,column=1,offset=9) self.assert_location(one.extent.start,line=1,column=1,offset=0)
assert_location(two.extent.end,line=2,column=8,offset=16) self.assert_location(one.extent.end,line=1,column=8,offset=7)
assert baseInput[two.extent.start.offset:two.extent.end.offset] == "int two" self.assertEqual(baseInput[one.extent.start.offset:one.extent.end.offset], "int one")
file = File.from_name(tu, 't.c') self.assert_location(two.extent.start,line=2,column=1,offset=9)
location1 = SourceLocation.from_position(tu, file, 1, 1) self.assert_location(two.extent.end,line=2,column=8,offset=16)
location2 = SourceLocation.from_position(tu, file, 1, 8) self.assertEqual(baseInput[two.extent.start.offset:two.extent.end.offset], "int two")
range1 = SourceRange.from_locations(location1, location2) file = File.from_name(tu, 't.c')
range2 = SourceRange.from_locations(location1, location2) location1 = SourceLocation.from_position(tu, file, 1, 1)
assert range1 == range2 location2 = SourceLocation.from_position(tu, file, 1, 8)
location3 = SourceLocation.from_position(tu, file, 1, 6) range1 = SourceRange.from_locations(location1, location2)
range3 = SourceRange.from_locations(location1, location3) range2 = SourceRange.from_locations(location1, location2)
assert range1 != range3 self.assertEqual(range1, range2)
location3 = SourceLocation.from_position(tu, file, 1, 6)
range3 = SourceRange.from_locations(location1, location3)
self.assertNotEqual(range1, range3)

View File

@ -1,4 +1,3 @@
from clang.cindex import TLSKind from clang.cindex import TLSKind
from clang.cindex import Cursor from clang.cindex import Cursor
from clang.cindex import TranslationUnit from clang.cindex import TranslationUnit
@ -6,42 +5,45 @@ from clang.cindex import TranslationUnit
from .util import get_cursor from .util import get_cursor
from .util import get_tu from .util import get_tu
def test_tls_kind(): import unittest
"""Ensure that thread-local storage kinds are available on cursors."""
tu = get_tu("""
class TestTLSKind(unittest.TestCase):
def test_tls_kind(self):
"""Ensure that thread-local storage kinds are available on cursors."""
tu = get_tu("""
int tls_none; int tls_none;
thread_local int tls_dynamic; thread_local int tls_dynamic;
_Thread_local int tls_static; _Thread_local int tls_static;
""", lang = 'cpp') """, lang = 'cpp')
tls_none = get_cursor(tu.cursor, 'tls_none') tls_none = get_cursor(tu.cursor, 'tls_none')
assert tls_none.tls_kind == TLSKind.NONE; self.assertEqual(tls_none.tls_kind, TLSKind.NONE)
tls_dynamic = get_cursor(tu.cursor, 'tls_dynamic') tls_dynamic = get_cursor(tu.cursor, 'tls_dynamic')
assert tls_dynamic.tls_kind == TLSKind.DYNAMIC self.assertEqual(tls_dynamic.tls_kind, TLSKind.DYNAMIC)
tls_static = get_cursor(tu.cursor, 'tls_static') tls_static = get_cursor(tu.cursor, 'tls_static')
assert tls_static.tls_kind == TLSKind.STATIC self.assertEqual(tls_static.tls_kind, TLSKind.STATIC)
# The following case tests '__declspec(thread)'. Since it is a Microsoft # The following case tests '__declspec(thread)'. Since it is a Microsoft
# specific extension, specific flags are required for the parser to pick # specific extension, specific flags are required for the parser to pick
# these up. # these up.
flags = ['-fms-extensions', '-target', 'x86_64-unknown-windows-win32', flags = ['-fms-extensions', '-target', 'x86_64-unknown-windows-win32',
'-fms-compatibility-version=18'] '-fms-compatibility-version=18']
tu = get_tu(""" tu = get_tu("""
__declspec(thread) int tls_declspec_msvc18; __declspec(thread) int tls_declspec_msvc18;
""", lang = 'cpp', flags=flags) """, lang = 'cpp', flags=flags)
tls_declspec_msvc18 = get_cursor(tu.cursor, 'tls_declspec_msvc18') tls_declspec_msvc18 = get_cursor(tu.cursor, 'tls_declspec_msvc18')
assert tls_declspec_msvc18.tls_kind == TLSKind.STATIC self.assertEqual(tls_declspec_msvc18.tls_kind, TLSKind.STATIC)
flags = ['-fms-extensions', '-target', 'x86_64-unknown-windows-win32', flags = ['-fms-extensions', '-target', 'x86_64-unknown-windows-win32',
'-fms-compatibility-version=19'] '-fms-compatibility-version=19']
tu = get_tu(""" tu = get_tu("""
__declspec(thread) int tls_declspec_msvc19; __declspec(thread) int tls_declspec_msvc19;
""", lang = 'cpp', flags=flags) """, lang = 'cpp', flags=flags)
tls_declspec_msvc19 = get_cursor(tu.cursor, 'tls_declspec_msvc19') tls_declspec_msvc19 = get_cursor(tu.cursor, 'tls_declspec_msvc19')
assert tls_declspec_msvc19.tls_kind == TLSKind.DYNAMIC self.assertEqual(tls_declspec_msvc19.tls_kind, TLSKind.DYNAMIC)

View File

@ -1,43 +1,44 @@
from clang.cindex import TokenKind from clang.cindex import TokenKind
from nose.tools import eq_
from nose.tools import ok_
from nose.tools import raises
def test_constructor(): import unittest
"""Ensure TokenKind constructor works as expected."""
t = TokenKind(5, 'foo')
eq_(t.value, 5) class TestTokenKind(unittest.TestCase):
eq_(t.name, 'foo') def test_constructor(self):
"""Ensure TokenKind constructor works as expected."""
@raises(ValueError) t = TokenKind(5, 'foo')
def test_bad_register():
"""Ensure a duplicate value is rejected for registration."""
TokenKind.register(2, 'foo') self.assertEqual(t.value, 5)
self.assertEqual(t.name, 'foo')
@raises(ValueError) def test_bad_register(self):
def test_unknown_value(): """Ensure a duplicate value is rejected for registration."""
"""Ensure trying to fetch an unknown value raises."""
TokenKind.from_value(-1) with self.assertRaises(ValueError):
TokenKind.register(2, 'foo')
def test_registration(): def test_unknown_value(self):
"""Ensure that items registered appear as class attributes.""" """Ensure trying to fetch an unknown value raises."""
ok_(hasattr(TokenKind, 'LITERAL'))
literal = TokenKind.LITERAL
ok_(isinstance(literal, TokenKind)) with self.assertRaises(ValueError):
TokenKind.from_value(-1)
def test_from_value(): def test_registration(self):
"""Ensure registered values can be obtained from from_value().""" """Ensure that items registered appear as class attributes."""
t = TokenKind.from_value(3) self.assertTrue(hasattr(TokenKind, 'LITERAL'))
ok_(isinstance(t, TokenKind)) literal = TokenKind.LITERAL
eq_(t, TokenKind.LITERAL)
def test_repr(): self.assertIsInstance(literal, TokenKind)
"""Ensure repr() works."""
r = repr(TokenKind.LITERAL) def test_from_value(self):
eq_(r, 'TokenKind.LITERAL') """Ensure registered values can be obtained from from_value()."""
t = TokenKind.from_value(3)
self.assertIsInstance(t, TokenKind)
self.assertEqual(t, TokenKind.LITERAL)
def test_repr(self):
"""Ensure repr() works."""
r = repr(TokenKind.LITERAL)
self.assertEqual(r, 'TokenKind.LITERAL')

View File

@ -3,50 +3,52 @@ from clang.cindex import Index
from clang.cindex import SourceLocation from clang.cindex import SourceLocation
from clang.cindex import SourceRange from clang.cindex import SourceRange
from clang.cindex import TokenKind from clang.cindex import TokenKind
from nose.tools import eq_
from nose.tools import ok_
from .util import get_tu from .util import get_tu
def test_token_to_cursor(): import unittest
"""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) == 4
assert tokens[1].spelling == 'i'
assert tokens[1].kind == TokenKind.IDENTIFIER
cursor = tokens[1].cursor class TestTokens(unittest.TestCase):
assert cursor.kind == CursorKind.VAR_DECL def test_token_to_cursor(self):
assert tokens[1].cursor == tokens[2].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))
def test_token_location(): self.assertEqual(len(tokens), 4)
"""Ensure Token.location works.""" self.assertEqual(tokens[1].spelling, 'i')
self.assertEqual(tokens[1].kind, TokenKind.IDENTIFIER)
tu = get_tu('int foo = 10;') cursor = tokens[1].cursor
r = tu.get_extent('t.c', (0, 11)) self.assertEqual(cursor.kind, CursorKind.VAR_DECL)
self.assertEqual(tokens[1].cursor, tokens[2].cursor)
tokens = list(tu.get_tokens(extent=r)) def test_token_location(self):
eq_(len(tokens), 4) """Ensure Token.location works."""
loc = tokens[1].location tu = get_tu('int foo = 10;')
ok_(isinstance(loc, SourceLocation)) r = tu.get_extent('t.c', (0, 11))
eq_(loc.line, 1)
eq_(loc.column, 5)
eq_(loc.offset, 4)
def test_token_extent(): tokens = list(tu.get_tokens(extent=r))
"""Ensure Token.extent works.""" self.assertEqual(len(tokens), 4)
tu = get_tu('int foo = 10;')
r = tu.get_extent('t.c', (0, 11))
tokens = list(tu.get_tokens(extent=r)) loc = tokens[1].location
eq_(len(tokens), 4) self.assertIsInstance(loc, SourceLocation)
self.assertEqual(loc.line, 1)
self.assertEqual(loc.column, 5)
self.assertEqual(loc.offset, 4)
extent = tokens[1].extent def test_token_extent(self):
ok_(isinstance(extent, SourceRange)) """Ensure Token.extent works."""
tu = get_tu('int foo = 10;')
r = tu.get_extent('t.c', (0, 11))
eq_(extent.start.offset, 4) tokens = list(tu.get_tokens(extent=r))
eq_(extent.end.offset, 7) self.assertEqual(len(tokens), 4)
extent = tokens[1].extent
self.assertIsInstance(extent, SourceRange)
self.assertEqual(extent.start.offset, 4)
self.assertEqual(extent.end.offset, 7)

View File

@ -1,6 +1,7 @@
import gc import gc
import os import os
import tempfile import tempfile
import unittest
from clang.cindex import CursorKind from clang.cindex import CursorKind
from clang.cindex import Cursor from clang.cindex import Cursor
@ -14,83 +15,9 @@ from clang.cindex import TranslationUnit
from .util import get_cursor from .util import get_cursor
from .util import get_tu from .util import get_tu
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS') 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():
try:
from StringIO import StringIO
except:
from io import StringIO
tu = TranslationUnit.from_source('fake.c', unsaved_files = [
('fake.c', 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): def save_tu(tu):
"""Convenience API to save a TranslationUnit to a file. """Convenience API to save a TranslationUnit to a file.
@ -102,153 +29,227 @@ def save_tu(tu):
return path return path
def test_save():
"""Ensure TranslationUnit.save() works."""
tu = get_tu('int foo();') class TestTranslationUnit(unittest.TestCase):
def test_spelling(self):
path = save_tu(tu) path = os.path.join(kInputsDir, 'hello.cpp')
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) tu = TranslationUnit.from_source(path)
except TranslationUnitLoadError: self.assertEqual(tu.spelling, path)
tu = None
assert tu == None
def test_fail_from_ast_file(): def test_cursor(self):
path = os.path.join(kInputsDir, 'non-existent.ast') path = os.path.join(kInputsDir, 'hello.cpp')
try: tu = get_tu(path)
tu = TranslationUnit.from_ast_file(path) c = tu.cursor
except TranslationUnitLoadError: self.assertIsInstance(c, Cursor)
tu = None self.assertIs(c.kind, CursorKind.TRANSLATION_UNIT)
assert tu == None
def test_parse_arguments(self):
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()]
self.assertEqual(spellings[-2], 'hello')
self.assertEqual(spellings[-1], 'hi')
def test_reparse_arguments(self):
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()]
self.assertEqual(spellings[-2], 'hello')
self.assertEqual(spellings[-1], 'hi')
def test_unsaved_files(self):
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()]
self.assertEqual(spellings[-2], 'x')
self.assertEqual(spellings[-1], 'y')
def test_unsaved_files_2(self):
try:
from StringIO import StringIO
except:
from io import StringIO
tu = TranslationUnit.from_source('fake.c', unsaved_files = [
('fake.c', StringIO('int x;'))])
spellings = [c.spelling for c in tu.cursor.get_children()]
self.assertEqual(spellings[-1], 'x')
def assert_normpaths_equal(self, path1, path2):
""" Compares two paths for equality after normalizing them with
os.path.normpath
"""
self.assertEqual(os.path.normpath(path1),
os.path.normpath(path2))
def test_includes(self):
def eq(expected, actual):
if not actual.is_input_file:
self.assert_normpaths_equal(expected[0], actual.source.name)
self.assert_normpaths_equal(expected[1], actual.include.name)
else:
self.assert_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()):
eq(i[0], i[1])
def test_save(self):
"""Ensure TranslationUnit.save() works."""
tu = get_tu('int foo();')
path = save_tu(tu)
self.assertTrue(os.path.exists(path))
self.assertGreater(os.path.getsize(path), 0)
os.unlink(path)
def test_save_translation_errors(self):
"""Ensure that saving to an invalid directory raises."""
tu = get_tu('int foo();')
path = '/does/not/exist/llvm-test.ast'
self.assertFalse(os.path.exists(os.path.dirname(path)))
with self.assertRaises(TranslationUnitSaveError) as cm:
tu.save(path)
ex = cm.exception
expected = TranslationUnitSaveError.ERROR_UNKNOWN
self.assertEqual(ex.save_error, expected)
def test_load(self):
"""Ensure TranslationUnits can be constructed from saved files."""
tu = get_tu('int foo();')
self.assertEqual(len(tu.diagnostics), 0)
path = save_tu(tu)
self.assertTrue(os.path.exists(path))
self.assertGreater(os.path.getsize(path), 0)
tu2 = TranslationUnit.from_ast_file(filename=path)
self.assertEqual(len(tu2.diagnostics), 0)
foo = get_cursor(tu2, 'foo')
self.assertIsNotNone(foo)
# Just in case there is an open file descriptor somewhere.
del tu2
os.unlink(path)
def test_index_parse(self):
path = os.path.join(kInputsDir, 'hello.cpp')
index = Index.create()
tu = index.parse(path)
self.assertIsInstance(tu, TranslationUnit)
def test_get_file(self):
"""Ensure tu.get_file() works appropriately."""
tu = get_tu('int foo();')
f = tu.get_file('t.c')
self.assertIsInstance(f, File)
self.assertEqual(f.name, 't.c')
with self.assertRaises(Exception):
f = tu.get_file('foobar.cpp')
def test_get_source_location(self):
"""Ensure tu.get_source_location() works."""
tu = get_tu('int foo();')
location = tu.get_location('t.c', 2)
self.assertIsInstance(location, SourceLocation)
self.assertEqual(location.offset, 2)
self.assertEqual(location.file.name, 't.c')
location = tu.get_location('t.c', (1, 3))
self.assertIsInstance(location, SourceLocation)
self.assertEqual(location.line, 1)
self.assertEqual(location.column, 3)
self.assertEqual(location.file.name, 't.c')
def test_get_source_range(self):
"""Ensure tu.get_source_range() works."""
tu = get_tu('int foo();')
r = tu.get_extent('t.c', (1,4))
self.assertIsInstance(r, SourceRange)
self.assertEqual(r.start.offset, 1)
self.assertEqual(r.end.offset, 4)
self.assertEqual(r.start.file.name, 't.c')
self.assertEqual(r.end.file.name, 't.c')
r = tu.get_extent('t.c', ((1,2), (1,3)))
self.assertIsInstance(r, SourceRange)
self.assertEqual(r.start.line, 1)
self.assertEqual(r.start.column, 2)
self.assertEqual(r.end.line, 1)
self.assertEqual(r.end.column, 3)
self.assertEqual(r.start.file.name, 't.c')
self.assertEqual(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))
self.assertIsInstance(r, SourceRange)
self.assertEqual(r.start.offset, 0)
self.assertEqual(r.end.offset, 5)
self.assertEqual(r.start.file.name, 't.c')
self.assertEqual(r.end.file.name, 't.c')
def test_get_tokens_gc(self):
"""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))
self.assertEqual(tokens[0].spelling, 'int')
gc.collect()
self.assertEqual(tokens[0].spelling, 'int')
del tokens[1]
gc.collect()
self.assertEqual(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(self):
path = os.path.join(kInputsDir, 'non-existent.cpp')
try:
tu = TranslationUnit.from_source(path)
except TranslationUnitLoadError:
tu = None
self.assertEqual(tu, None)
def test_fail_from_ast_file(self):
path = os.path.join(kInputsDir, 'non-existent.ast')
try:
tu = TranslationUnit.from_ast_file(path)
except TranslationUnitLoadError:
tu = None
self.assertEqual(tu, None)

View File

@ -1,12 +1,13 @@
import gc import gc
import unittest
from clang.cindex import CursorKind from clang.cindex import CursorKind
from clang.cindex import TranslationUnit from clang.cindex import TranslationUnit
from clang.cindex import TypeKind from clang.cindex import TypeKind
from nose.tools import raises
from .util import get_cursor from .util import get_cursor
from .util import get_tu from .util import get_tu
kInput = """\ kInput = """\
typedef int I; typedef int I;
@ -24,400 +25,414 @@ struct teststruct {
""" """
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[0].type.get_typedef_name() == ''
assert fields[1].spelling == 'b'
assert not fields[1].type.is_const_qualified()
assert fields[1].type.kind == TypeKind.TYPEDEF
assert fields[1].type.get_canonical().kind == TypeKind.INT
assert fields[1].type.get_declaration().spelling == 'I'
assert fields[1].type.get_typedef_name() == 'I'
assert fields[2].spelling == 'c'
assert not fields[2].type.is_const_qualified()
assert fields[2].type.kind == TypeKind.LONG
assert fields[2].type.get_canonical().kind == TypeKind.LONG
assert fields[2].type.get_typedef_name() == ''
assert fields[3].spelling == 'd'
assert not fields[3].type.is_const_qualified()
assert fields[3].type.kind == TypeKind.ULONG
assert fields[3].type.get_canonical().kind == TypeKind.ULONG
assert fields[3].type.get_typedef_name() == ''
assert fields[4].spelling == 'e'
assert not fields[4].type.is_const_qualified()
assert fields[4].type.kind == TypeKind.LONG
assert fields[4].type.get_canonical().kind == TypeKind.LONG
assert fields[4].type.get_typedef_name() == ''
assert fields[5].spelling == 'f'
assert fields[5].type.is_const_qualified()
assert fields[5].type.kind == TypeKind.INT
assert fields[5].type.get_canonical().kind == TypeKind.INT
assert fields[5].type.get_typedef_name() == ''
assert fields[6].spelling == 'g'
assert not fields[6].type.is_const_qualified()
assert fields[6].type.kind == TypeKind.POINTER
assert fields[6].type.get_pointee().kind == TypeKind.INT
assert fields[6].type.get_typedef_name() == ''
assert fields[7].spelling == 'h'
assert not fields[7].type.is_const_qualified()
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
assert fields[7].type.get_typedef_name() == ''
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=""" constarrayInput="""
struct teststruct { struct teststruct {
void *A[2]; 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(): class TestType(unittest.TestCase):
"""Ensure equivalence operators work on Type.""" def test_a_struct(self):
source = 'int a; int b; void *v;' tu = get_tu(kInput)
tu = get_tu(source)
a = get_cursor(tu, 'a') teststruct = get_cursor(tu, 'teststruct')
b = get_cursor(tu, 'b') self.assertIsNotNone(teststruct, "Could not find teststruct.")
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()) fields = list(teststruct.get_children())
assert teststruct.type.get_align() == align self.assertEqual(fields[0].kind, CursorKind.FIELD_DECL)
assert teststruct.type.get_size() == total self.assertIsNotNone(fields[0].translation_unit)
assert teststruct.type.get_offset(fields[0].spelling) == a1 self.assertEqual(fields[0].spelling, 'a')
assert teststruct.type.get_offset(fields[1].spelling) == a2 self.assertFalse(fields[0].type.is_const_qualified())
assert teststruct.type.get_offset(fields[2].spelling) == a3 self.assertEqual(fields[0].type.kind, TypeKind.INT)
assert teststruct.type.get_offset(fields[3].spelling) == a4 self.assertEqual(fields[0].type.get_canonical().kind, TypeKind.INT)
assert fields[0].is_bitfield() == False self.assertEqual(fields[0].type.get_typedef_name(), '')
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(): self.assertEqual(fields[1].kind, CursorKind.FIELD_DECL)
"""Ensure Cursor.get_record_field_offset works in anonymous records""" self.assertIsNotNone(fields[1].translation_unit)
source=""" self.assertEqual(fields[1].spelling, 'b')
struct Test { self.assertFalse(fields[1].type.is_const_qualified())
struct {int a;} typeanon; self.assertEqual(fields[1].type.kind, TypeKind.TYPEDEF)
struct { self.assertEqual(fields[1].type.get_canonical().kind, TypeKind.INT)
int bariton; self.assertEqual(fields[1].type.get_declaration().spelling, 'I')
union { self.assertEqual(fields[1].type.get_typedef_name(), 'I')
int foo;
}; self.assertEqual(fields[2].kind, CursorKind.FIELD_DECL)
}; self.assertIsNotNone(fields[2].translation_unit)
int bar; self.assertEqual(fields[2].spelling, 'c')
};""" self.assertFalse(fields[2].type.is_const_qualified())
tries=[(['-target','i386-linux-gnu'],(4,16,0,32,64,96)), self.assertEqual(fields[2].type.kind, TypeKind.LONG)
(['-target','nvptx64-unknown-unknown'],(8,24,0,32,64,96)), self.assertEqual(fields[2].type.get_canonical().kind, TypeKind.LONG)
(['-target','i386-pc-win32'],(8,16,0,32,64,96)), self.assertEqual(fields[2].type.get_typedef_name(), '')
(['-target','msp430-none-none'],(2,14,0,32,64,96))]
for flags, values in tries: self.assertEqual(fields[3].kind, CursorKind.FIELD_DECL)
align,total,f1,bariton,foo,bar = values self.assertIsNotNone(fields[3].translation_unit)
self.assertEqual(fields[3].spelling, 'd')
self.assertFalse(fields[3].type.is_const_qualified())
self.assertEqual(fields[3].type.kind, TypeKind.ULONG)
self.assertEqual(fields[3].type.get_canonical().kind, TypeKind.ULONG)
self.assertEqual(fields[3].type.get_typedef_name(), '')
self.assertEqual(fields[4].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[4].translation_unit)
self.assertEqual(fields[4].spelling, 'e')
self.assertFalse(fields[4].type.is_const_qualified())
self.assertEqual(fields[4].type.kind, TypeKind.LONG)
self.assertEqual(fields[4].type.get_canonical().kind, TypeKind.LONG)
self.assertEqual(fields[4].type.get_typedef_name(), '')
self.assertEqual(fields[5].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[5].translation_unit)
self.assertEqual(fields[5].spelling, 'f')
self.assertTrue(fields[5].type.is_const_qualified())
self.assertEqual(fields[5].type.kind, TypeKind.INT)
self.assertEqual(fields[5].type.get_canonical().kind, TypeKind.INT)
self.assertEqual(fields[5].type.get_typedef_name(), '')
self.assertEqual(fields[6].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[6].translation_unit)
self.assertEqual(fields[6].spelling, 'g')
self.assertFalse(fields[6].type.is_const_qualified())
self.assertEqual(fields[6].type.kind, TypeKind.POINTER)
self.assertEqual(fields[6].type.get_pointee().kind, TypeKind.INT)
self.assertEqual(fields[6].type.get_typedef_name(), '')
self.assertEqual(fields[7].kind, CursorKind.FIELD_DECL)
self.assertIsNotNone(fields[7].translation_unit)
self.assertEqual(fields[7].spelling, 'h')
self.assertFalse(fields[7].type.is_const_qualified())
self.assertEqual(fields[7].type.kind, TypeKind.POINTER)
self.assertEqual(fields[7].type.get_pointee().kind, TypeKind.POINTER)
self.assertEqual(fields[7].type.get_pointee().get_pointee().kind, TypeKind.POINTER)
self.assertEqual(fields[7].type.get_pointee().get_pointee().get_pointee().kind, TypeKind.INT)
self.assertEqual(fields[7].type.get_typedef_name(), '')
def test_references(self):
"""Ensure that a Type maintains a reference to a TranslationUnit."""
tu = get_tu('int x;')
children = list(tu.cursor.get_children())
self.assertGreater(len(children), 0)
cursor = children[0]
t = cursor.type
self.assertIsInstance(t.translation_unit, TranslationUnit)
# Delete main TranslationUnit reference and force a GC.
del tu
gc.collect()
self.assertIsInstance(t.translation_unit, TranslationUnit)
# If the TU was destroyed, this should cause a segfault.
decl = t.get_declaration()
def testConstantArray(self):
tu = get_tu(constarrayInput)
teststruct = get_cursor(tu, 'teststruct')
self.assertIsNotNone(teststruct, "Didn't find teststruct??")
fields = list(teststruct.get_children())
self.assertEqual(fields[0].spelling, 'A')
self.assertEqual(fields[0].type.kind, TypeKind.CONSTANTARRAY)
self.assertIsNotNone(fields[0].type.get_array_element_type())
self.assertEqual(fields[0].type.get_array_element_type().kind, TypeKind.POINTER)
self.assertEqual(fields[0].type.get_array_size(), 2)
def test_equal(self):
"""Ensure equivalence operators work on Type."""
source = 'int a; int b; void *v;'
tu = get_tu(source) 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
a = get_cursor(tu, 'a')
b = get_cursor(tu, 'b')
v = get_cursor(tu, 'v')
def test_decay(): self.assertIsNotNone(a)
"""Ensure decayed types are handled as the original type""" self.assertIsNotNone(b)
self.assertIsNotNone(v)
tu = get_tu("void foo(int a[]);") self.assertEqual(a.type, b.type)
foo = get_cursor(tu, 'foo') self.assertNotEqual(a.type, v.type)
a = foo.type.argument_types()[0]
assert a.kind == TypeKind.INCOMPLETEARRAY self.assertNotEqual(a.type, None)
assert a.element_type.kind == TypeKind.INT self.assertNotEqual(a.type, 'foo')
assert a.get_canonical().kind == TypeKind.INCOMPLETEARRAY
def test_addrspace(): def test_type_spelling(self):
"""Ensure the address space can be queried""" """Ensure Type.spelling works."""
tu = get_tu('__attribute__((address_space(2))) int testInteger = 3;', 'c') 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')
self.assertIsNotNone(c)
self.assertIsNotNone(i)
self.assertIsNotNone(x)
self.assertIsNotNone(v)
self.assertEqual(c.type.spelling, "int [5]")
self.assertEqual(i.type.spelling, "int []")
self.assertEqual(x.type.spelling, "int")
self.assertEqual(v.type.spelling, "int [x]")
testInteger = get_cursor(tu, 'testInteger') def test_typekind_spelling(self):
"""Ensure TypeKind.spelling works."""
tu = get_tu('int a;')
a = get_cursor(tu, 'a')
assert testInteger is not None, "Could not find testInteger." self.assertIsNotNone(a)
assert testInteger.type.get_address_space() == 2 self.assertEqual(a.type.kind.spelling, 'Int')
def test_function_argument_types(self):
"""Ensure that Type.argument_types() works as expected."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
self.assertIsNotNone(f)
args = f.type.argument_types()
self.assertIsNotNone(args)
self.assertEqual(len(args), 2)
t0 = args[0]
self.assertIsNotNone(t0)
self.assertEqual(t0.kind, TypeKind.INT)
t1 = args[1]
self.assertIsNotNone(t1)
self.assertEqual(t1.kind, TypeKind.INT)
args2 = list(args)
self.assertEqual(len(args2), 2)
self.assertEqual(t0, args2[0])
self.assertEqual(t1, args2[1])
def test_argument_types_string_key(self):
"""Ensure that non-int keys raise a TypeError."""
tu = get_tu('void f(int, int);')
f = get_cursor(tu, 'f')
self.assertIsNotNone(f)
args = f.type.argument_types()
self.assertEqual(len(args), 2)
with self.assertRaises(TypeError):
args['foo']
def test_argument_types_negative_index(self):
"""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()
with self.assertRaises(IndexError):
args[-1]
def test_argument_types_overflow_index(self):
"""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()
with self.assertRaises(IndexError):
args[2]
def test_argument_types_invalid_type(self):
"""Ensure that obtaining argument_types on a Type without them raises."""
tu = get_tu('int i;')
i = get_cursor(tu, 'i')
self.assertIsNotNone(i)
with self.assertRaises(Exception):
i.type.argument_types()
def test_is_pod(self):
"""Ensure Type.is_pod() works."""
tu = get_tu('int i; void f();')
i = get_cursor(tu, 'i')
f = get_cursor(tu, 'f')
self.assertIsNotNone(i)
self.assertIsNotNone(f)
self.assertTrue(i.type.is_pod())
self.assertFalse(f.type.is_pod())
def test_function_variadic(self):
"""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')
self.assertIsNotNone(foo)
self.assertIsNotNone(bar)
self.assertIsInstance(foo.type.is_function_variadic(), bool)
self.assertTrue(foo.type.is_function_variadic())
self.assertFalse(bar.type.is_function_variadic())
def test_element_type(self):
"""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')
self.assertIsNotNone(c)
self.assertIsNotNone(i)
self.assertIsNotNone(v)
self.assertEqual(c.type.kind, TypeKind.CONSTANTARRAY)
self.assertEqual(c.type.element_type.kind, TypeKind.INT)
self.assertEqual(i.type.kind, TypeKind.INCOMPLETEARRAY)
self.assertEqual(i.type.element_type.kind, TypeKind.INT)
self.assertEqual(v.type.kind, TypeKind.VARIABLEARRAY)
self.assertEqual(v.type.element_type.kind, TypeKind.INT)
def test_invalid_element_type(self):
"""Ensure Type.element_type raises if type doesn't have elements."""
tu = get_tu('int i;')
i = get_cursor(tu, 'i')
self.assertIsNotNone(i)
with self.assertRaises(Exception):
i.element_type
def test_element_count(self):
"""Ensure Type.element_count works."""
tu = get_tu('int i[5]; int j;')
i = get_cursor(tu, 'i')
j = get_cursor(tu, 'j')
self.assertIsNotNone(i)
self.assertIsNotNone(j)
self.assertEqual(i.type.element_count, 5)
with self.assertRaises(Exception):
j.type.element_count
def test_is_volatile_qualified(self):
"""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')
self.assertIsNotNone(i)
self.assertIsNotNone(j)
self.assertIsInstance(i.type.is_volatile_qualified(), bool)
self.assertTrue(i.type.is_volatile_qualified())
self.assertFalse(j.type.is_volatile_qualified())
def test_is_restrict_qualified(self):
"""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')
self.assertIsNotNone(i)
self.assertIsNotNone(j)
self.assertIsInstance(i.type.is_restrict_qualified(), bool)
self.assertTrue(i.type.is_restrict_qualified())
self.assertFalse(j.type.is_restrict_qualified())
def test_record_layout(self):
"""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())
self.assertEqual(teststruct.type.get_align(), align)
self.assertEqual(teststruct.type.get_size(), total)
self.assertEqual(teststruct.type.get_offset(fields[0].spelling), a1)
self.assertEqual(teststruct.type.get_offset(fields[1].spelling), a2)
self.assertEqual(teststruct.type.get_offset(fields[2].spelling), a3)
self.assertEqual(teststruct.type.get_offset(fields[3].spelling), a4)
self.assertEqual(fields[0].is_bitfield(), False)
self.assertEqual(fields[1].is_bitfield(), True)
self.assertEqual(fields[1].get_bitfield_width(), 3)
self.assertEqual(fields[2].is_bitfield(), True)
self.assertEqual(fields[2].get_bitfield_width(), 4)
self.assertEqual(fields[3].is_bitfield(), False)
def test_offset(self):
"""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())
self.assertEqual(children[0].kind, CursorKind.STRUCT_DECL)
self.assertNotEqual(children[0].spelling, "typeanon")
self.assertEqual(children[1].spelling, "typeanon")
self.assertEqual(fields[0].kind, CursorKind.FIELD_DECL)
self.assertEqual(fields[1].kind, CursorKind.FIELD_DECL)
self.assertTrue(fields[1].is_anonymous())
self.assertEqual(teststruct.type.get_offset("typeanon"), f1)
self.assertEqual(teststruct.type.get_offset("bariton"), bariton)
self.assertEqual(teststruct.type.get_offset("foo"), foo)
self.assertEqual(teststruct.type.get_offset("bar"), bar)
def test_decay(self):
"""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]
self.assertEqual(a.kind, TypeKind.INCOMPLETEARRAY)
self.assertEqual(a.element_type.kind, TypeKind.INT)
self.assertEqual(a.get_canonical().kind, TypeKind.INCOMPLETEARRAY)
def test_addrspace(self):
"""Ensure the address space can be queried"""
tu = get_tu('__attribute__((address_space(2))) int testInteger = 3;', 'c')
testInteger = get_cursor(tu, 'testInteger')
self.assertIsNotNone(testInteger, "Could not find testInteger.")
self.assertEqual(testInteger.type.get_address_space(), 2)