Importing netbsd clang -- pristine
Change-Id: Ia40e9ffdf29b5dab2f122f673ff6802a58bc690f
This commit is contained in:
+17
@@ -0,0 +1,17 @@
|
||||
[
|
||||
{
|
||||
"directory": "/home/john.doe/MyProject",
|
||||
"command": "clang++ -o project.o -c /home/john.doe/MyProject/project.cpp",
|
||||
"file": "/home/john.doe/MyProject/project.cpp"
|
||||
},
|
||||
{
|
||||
"directory": "/home/john.doe/MyProjectA",
|
||||
"command": "clang++ -o project2.o -c /home/john.doe/MyProject/project2.cpp",
|
||||
"file": "/home/john.doe/MyProject/project2.cpp"
|
||||
},
|
||||
{
|
||||
"directory": "/home/john.doe/MyProjectB",
|
||||
"command": "clang++ -DFEATURE=1 -o project2-feature.o -c /home/john.doe/MyProject/project2.cpp",
|
||||
"file": "/home/john.doe/MyProject/project2.cpp"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef HEADER1
|
||||
#define HEADER1
|
||||
|
||||
#include "header3.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef HEADER2
|
||||
#define HEADER2
|
||||
|
||||
#include "header3.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,3 @@
|
||||
// Not a guarded header!
|
||||
|
||||
void f();
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "stdio.h"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
printf("hello world\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include "header1.h"
|
||||
#include "header2.h"
|
||||
#include "header1.h"
|
||||
|
||||
int main() { }
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
int DECL_ONE = 1;
|
||||
int DECL_TWO = 2;
|
||||
@@ -0,0 +1,89 @@
|
||||
from clang.cindex import CompilationDatabase
|
||||
from clang.cindex import CompilationDatabaseError
|
||||
from clang.cindex import CompileCommands
|
||||
from clang.cindex import CompileCommand
|
||||
import os
|
||||
import gc
|
||||
|
||||
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
|
||||
|
||||
def test_create_fail():
|
||||
"""Check we fail loading a database with an assertion"""
|
||||
path = os.path.dirname(__file__)
|
||||
try:
|
||||
cdb = CompilationDatabase.fromDirectory(path)
|
||||
except CompilationDatabaseError as e:
|
||||
assert e.cdb_error == CompilationDatabaseError.ERROR_CANNOTLOADDATABASE
|
||||
else:
|
||||
assert False
|
||||
|
||||
def test_create():
|
||||
"""Check we can load a compilation database"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
|
||||
def test_lookup_fail():
|
||||
"""Check file lookup failure"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
assert cdb.getCompileCommands('file_do_not_exist.cpp') == None
|
||||
|
||||
def test_lookup_succeed():
|
||||
"""Check we get some results if the file exists in the db"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
|
||||
assert len(cmds) != 0
|
||||
|
||||
def test_1_compilecommand():
|
||||
"""Check file with single compile command"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
|
||||
assert len(cmds) == 1
|
||||
assert cmds[0].directory == '/home/john.doe/MyProject'
|
||||
expected = [ 'clang++', '-o', 'project.o', '-c',
|
||||
'/home/john.doe/MyProject/project.cpp']
|
||||
for arg, exp in zip(cmds[0].arguments, expected):
|
||||
assert arg == exp
|
||||
|
||||
def test_2_compilecommand():
|
||||
"""Check file with 2 compile commands"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp')
|
||||
assert len(cmds) == 2
|
||||
expected = [
|
||||
{ 'wd': '/home/john.doe/MyProjectA',
|
||||
'line': ['clang++', '-o', 'project2.o', '-c',
|
||||
'/home/john.doe/MyProject/project2.cpp']},
|
||||
{ 'wd': '/home/john.doe/MyProjectB',
|
||||
'line': ['clang++', '-DFEATURE=1', '-o', 'project2-feature.o', '-c',
|
||||
'/home/john.doe/MyProject/project2.cpp']}
|
||||
]
|
||||
for i in range(len(cmds)):
|
||||
assert cmds[i].directory == expected[i]['wd']
|
||||
for arg, exp in zip(cmds[i].arguments, expected[i]['line']):
|
||||
assert arg == exp
|
||||
|
||||
def test_compilecommand_iterator_stops():
|
||||
"""Check that iterator stops after the correct number of elements"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
count = 0
|
||||
for cmd in cdb.getCompileCommands('/home/john.doe/MyProject/project2.cpp'):
|
||||
count += 1
|
||||
assert count <= 2
|
||||
|
||||
def test_compilationDB_references():
|
||||
"""Ensure CompilationsCommands are independent of the database"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
|
||||
del cdb
|
||||
gc.collect()
|
||||
workingdir = cmds[0].directory
|
||||
|
||||
def test_compilationCommands_references():
|
||||
"""Ensure CompilationsCommand keeps a reference to CompilationCommands"""
|
||||
cdb = CompilationDatabase.fromDirectory(kInputsDir)
|
||||
cmds = cdb.getCompileCommands('/home/john.doe/MyProject/project.cpp')
|
||||
del cdb
|
||||
cmd0 = cmds[0]
|
||||
del cmds
|
||||
gc.collect()
|
||||
workingdir = cmd0.directory
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
from clang.cindex import TranslationUnit
|
||||
|
||||
def check_completion_results(cr, expected):
|
||||
assert cr is not None
|
||||
assert len(cr.diagnostics) == 0
|
||||
|
||||
completions = [str(c) for c in cr.results]
|
||||
|
||||
for c in expected:
|
||||
assert c in completions
|
||||
|
||||
def test_code_complete():
|
||||
files = [('fake.c', """
|
||||
/// Aaa.
|
||||
int test1;
|
||||
|
||||
/// Bbb.
|
||||
void test2(void);
|
||||
|
||||
void f() {
|
||||
|
||||
}
|
||||
""")]
|
||||
|
||||
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
|
||||
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
|
||||
|
||||
cr = tu.codeComplete('fake.c', 9, 1, unsaved_files=files, include_brief_comments=True)
|
||||
|
||||
expected = [
|
||||
"{'int', ResultType} | {'test1', TypedText} || Priority: 50 || Availability: Available || Brief comment: Aaa.",
|
||||
"{'void', ResultType} | {'test2', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 50 || Availability: Available || Brief comment: Bbb.",
|
||||
"{'return', TypedText} || Priority: 40 || Availability: Available || Brief comment: None"
|
||||
]
|
||||
check_completion_results(cr, expected)
|
||||
|
||||
def test_code_complete_availability():
|
||||
files = [('fake.cpp', """
|
||||
class P {
|
||||
protected:
|
||||
int member;
|
||||
};
|
||||
|
||||
class Q : public P {
|
||||
public:
|
||||
using P::member;
|
||||
};
|
||||
|
||||
void f(P x, Q y) {
|
||||
x.; // member is inaccessible
|
||||
y.; // member is accessible
|
||||
}
|
||||
""")]
|
||||
|
||||
tu = TranslationUnit.from_source('fake.cpp', ['-std=c++98'], unsaved_files=files)
|
||||
|
||||
cr = tu.codeComplete('fake.cpp', 12, 5, unsaved_files=files)
|
||||
|
||||
expected = [
|
||||
"{'const', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
|
||||
"{'volatile', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
|
||||
"{'operator', TypedText} || Priority: 40 || Availability: Available || Brief comment: None",
|
||||
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
|
||||
"{'Q', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None"
|
||||
]
|
||||
check_completion_results(cr, expected)
|
||||
|
||||
cr = tu.codeComplete('fake.cpp', 13, 5, unsaved_files=files)
|
||||
expected = [
|
||||
"{'P', TypedText} | {'::', Text} || Priority: 75 || Availability: Available || Brief comment: None",
|
||||
"{'P &', ResultType} | {'operator=', TypedText} | {'(', LeftParen} | {'const P &', Placeholder} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None",
|
||||
"{'int', ResultType} | {'member', TypedText} || Priority: 35 || Availability: NotAccessible || Brief comment: None",
|
||||
"{'void', ResultType} | {'~P', TypedText} | {'(', LeftParen} | {')', RightParen} || Priority: 34 || Availability: Available || Brief comment: None"
|
||||
]
|
||||
check_completion_results(cr, expected)
|
||||
@@ -0,0 +1,40 @@
|
||||
from clang.cindex import TranslationUnit
|
||||
from tests.cindex.util import get_cursor
|
||||
|
||||
def test_comment():
|
||||
files = [('fake.c', """
|
||||
/// Aaa.
|
||||
int test1;
|
||||
|
||||
/// Bbb.
|
||||
/// x
|
||||
void test2(void);
|
||||
|
||||
void f() {
|
||||
|
||||
}
|
||||
""")]
|
||||
# make a comment-aware TU
|
||||
tu = TranslationUnit.from_source('fake.c', ['-std=c99'], unsaved_files=files,
|
||||
options=TranslationUnit.PARSE_INCLUDE_BRIEF_COMMENTS_IN_CODE_COMPLETION)
|
||||
test1 = get_cursor(tu, 'test1')
|
||||
assert test1 is not None, "Could not find test1."
|
||||
assert test1.type.is_pod()
|
||||
raw = test1.raw_comment
|
||||
brief = test1.brief_comment
|
||||
assert raw == """/// Aaa."""
|
||||
assert brief == """Aaa."""
|
||||
|
||||
test2 = get_cursor(tu, 'test2')
|
||||
raw = test2.raw_comment
|
||||
brief = test2.brief_comment
|
||||
assert raw == """/// Bbb.\n/// x"""
|
||||
assert brief == """Bbb. x"""
|
||||
|
||||
f = get_cursor(tu, 'f')
|
||||
raw = f.raw_comment
|
||||
brief = f.brief_comment
|
||||
assert raw is None
|
||||
assert brief is None
|
||||
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
import gc
|
||||
|
||||
from clang.cindex import CursorKind
|
||||
from clang.cindex import TranslationUnit
|
||||
from clang.cindex import TypeKind
|
||||
from .util import get_cursor
|
||||
from .util import get_cursors
|
||||
from .util import get_tu
|
||||
|
||||
kInput = """\
|
||||
// FIXME: Find nicer way to drop builtins and other cruft.
|
||||
int start_decl;
|
||||
|
||||
struct s0 {
|
||||
int a;
|
||||
int b;
|
||||
};
|
||||
|
||||
struct s1;
|
||||
|
||||
void f0(int a0, int a1) {
|
||||
int l0, l1;
|
||||
|
||||
if (a0)
|
||||
return;
|
||||
|
||||
for (;;) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def test_get_children():
|
||||
tu = get_tu(kInput)
|
||||
|
||||
# Skip until past start_decl.
|
||||
it = tu.cursor.get_children()
|
||||
while it.next().spelling != 'start_decl':
|
||||
pass
|
||||
|
||||
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 == 4
|
||||
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_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_underlying_type():
|
||||
tu = get_tu('typedef int foo;')
|
||||
typedef = get_cursor(tu, 'foo')
|
||||
assert typedef is not None
|
||||
|
||||
assert typedef.kind.is_declaration()
|
||||
underlying = typedef.underlying_typedef_type
|
||||
assert underlying.kind == TypeKind.INT
|
||||
|
||||
kParentTest = """\
|
||||
class C {
|
||||
void f();
|
||||
}
|
||||
|
||||
void C::f() { }
|
||||
"""
|
||||
def test_semantic_parent():
|
||||
tu = get_tu(kParentTest, 'cpp')
|
||||
curs = get_cursors(tu, 'f')
|
||||
decl = get_cursor(tu, 'C')
|
||||
assert(len(curs) == 2)
|
||||
assert(curs[0].semantic_parent == curs[1].semantic_parent)
|
||||
assert(curs[0].semantic_parent == decl)
|
||||
|
||||
def test_lexical_parent():
|
||||
tu = get_tu(kParentTest, 'cpp')
|
||||
curs = get_cursors(tu, 'f')
|
||||
decl = get_cursor(tu, 'C')
|
||||
assert(len(curs) == 2)
|
||||
assert(curs[0].lexical_parent != curs[1].lexical_parent)
|
||||
assert(curs[0].lexical_parent == decl)
|
||||
assert(curs[1].lexical_parent == tu.cursor)
|
||||
|
||||
def test_enum_type():
|
||||
tu = get_tu('enum TEST { FOO=1, BAR=2 };')
|
||||
enum = get_cursor(tu, 'TEST')
|
||||
assert enum is not None
|
||||
|
||||
assert enum.kind == CursorKind.ENUM_DECL
|
||||
enum_type = enum.enum_type
|
||||
assert enum_type.kind == TypeKind.UINT
|
||||
|
||||
def test_enum_type_cpp():
|
||||
tu = get_tu('enum TEST : long long { FOO=1, BAR=2 };', lang="cpp")
|
||||
enum = get_cursor(tu, 'TEST')
|
||||
assert enum is not None
|
||||
|
||||
assert enum.kind == CursorKind.ENUM_DECL
|
||||
assert enum.enum_type.kind == TypeKind.LONGLONG
|
||||
|
||||
def test_objc_type_encoding():
|
||||
tu = get_tu('int i;', lang='objc')
|
||||
i = get_cursor(tu, 'i')
|
||||
|
||||
assert i is not None
|
||||
assert i.objc_type_encoding == 'i'
|
||||
|
||||
def test_enum_values():
|
||||
tu = get_tu('enum TEST { SPAM=1, EGG, HAM = EGG * 20};')
|
||||
enum = get_cursor(tu, 'TEST')
|
||||
assert enum is not None
|
||||
|
||||
assert enum.kind == CursorKind.ENUM_DECL
|
||||
|
||||
enum_constants = list(enum.get_children())
|
||||
assert len(enum_constants) == 3
|
||||
|
||||
spam, egg, ham = enum_constants
|
||||
|
||||
assert spam.kind == CursorKind.ENUM_CONSTANT_DECL
|
||||
assert spam.enum_value == 1
|
||||
assert egg.kind == CursorKind.ENUM_CONSTANT_DECL
|
||||
assert egg.enum_value == 2
|
||||
assert ham.kind == CursorKind.ENUM_CONSTANT_DECL
|
||||
assert ham.enum_value == 40
|
||||
|
||||
def test_enum_values_cpp():
|
||||
tu = get_tu('enum TEST : long long { SPAM = -1, HAM = 0x10000000000};', lang="cpp")
|
||||
enum = get_cursor(tu, 'TEST')
|
||||
assert enum is not None
|
||||
|
||||
assert enum.kind == CursorKind.ENUM_DECL
|
||||
|
||||
enum_constants = list(enum.get_children())
|
||||
assert len(enum_constants) == 2
|
||||
|
||||
spam, ham = enum_constants
|
||||
|
||||
assert spam.kind == CursorKind.ENUM_CONSTANT_DECL
|
||||
assert spam.enum_value == -1
|
||||
assert ham.kind == CursorKind.ENUM_CONSTANT_DECL
|
||||
assert ham.enum_value == 0x10000000000
|
||||
|
||||
def test_annotation_attribute():
|
||||
tu = get_tu('int foo (void) __attribute__ ((annotate("here be annotation attribute")));')
|
||||
|
||||
foo = get_cursor(tu, 'foo')
|
||||
assert foo is not None
|
||||
|
||||
for c in foo.get_children():
|
||||
if c.kind == CursorKind.ANNOTATE_ATTR:
|
||||
assert c.displayname == "here be annotation attribute"
|
||||
break
|
||||
else:
|
||||
assert False, "Couldn't find annotation"
|
||||
|
||||
def test_result_type():
|
||||
tu = get_tu('int foo();')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
|
||||
assert foo is not None
|
||||
t = foo.result_type
|
||||
assert t.kind == TypeKind.INT
|
||||
|
||||
def test_get_tokens():
|
||||
"""Ensure we can map cursors back to tokens."""
|
||||
tu = get_tu('int foo(int i);')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
|
||||
tokens = list(foo.get_tokens())
|
||||
assert len(tokens) == 7
|
||||
assert tokens[0].spelling == 'int'
|
||||
assert tokens[1].spelling == 'foo'
|
||||
|
||||
def test_get_arguments():
|
||||
tu = get_tu('void foo(int i, int j);')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
arguments = list(foo.get_arguments())
|
||||
|
||||
assert len(arguments) == 2
|
||||
assert arguments[0].spelling == "i"
|
||||
assert arguments[1].spelling == "j"
|
||||
|
||||
def test_referenced():
|
||||
tu = get_tu('void foo(); void bar() { foo(); }')
|
||||
foo = get_cursor(tu, 'foo')
|
||||
bar = get_cursor(tu, 'bar')
|
||||
for c in bar.get_children():
|
||||
if c.kind == CursorKind.CALL_EXPR:
|
||||
assert c.referenced.spelling == foo.spelling
|
||||
break
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
from clang.cindex import CursorKind
|
||||
|
||||
def test_name():
|
||||
assert CursorKind.UNEXPOSED_DECL.name is 'UNEXPOSED_DECL'
|
||||
|
||||
def test_get_all_kinds():
|
||||
kinds = CursorKind.get_all_kinds()
|
||||
assert CursorKind.UNEXPOSED_DECL in kinds
|
||||
assert CursorKind.TRANSLATION_UNIT in kinds
|
||||
assert CursorKind.VARIABLE_REF in kinds
|
||||
assert CursorKind.LAMBDA_EXPR in kinds
|
||||
assert CursorKind.OBJ_BOOL_LITERAL_EXPR in kinds
|
||||
assert CursorKind.OBJ_SELF_EXPR in kinds
|
||||
assert CursorKind.MS_ASM_STMT in kinds
|
||||
assert CursorKind.MODULE_IMPORT_DECL in kinds
|
||||
|
||||
def test_kind_groups():
|
||||
"""Check that every kind classifies to exactly one group."""
|
||||
|
||||
assert CursorKind.UNEXPOSED_DECL.is_declaration()
|
||||
assert CursorKind.TYPE_REF.is_reference()
|
||||
assert CursorKind.DECL_REF_EXPR.is_expression()
|
||||
assert CursorKind.UNEXPOSED_STMT.is_statement()
|
||||
assert CursorKind.INVALID_FILE.is_invalid()
|
||||
|
||||
assert CursorKind.TRANSLATION_UNIT.is_translation_unit()
|
||||
assert not CursorKind.TYPE_REF.is_translation_unit()
|
||||
|
||||
assert CursorKind.PREPROCESSING_DIRECTIVE.is_preprocessing()
|
||||
assert not CursorKind.TYPE_REF.is_preprocessing()
|
||||
|
||||
assert CursorKind.UNEXPOSED_DECL.is_unexposed()
|
||||
assert not CursorKind.TYPE_REF.is_unexposed()
|
||||
|
||||
for k in CursorKind.get_all_kinds():
|
||||
group = [n for n in ('is_declaration', 'is_reference', 'is_expression',
|
||||
'is_statement', 'is_invalid', 'is_attribute')
|
||||
if getattr(k, n)()]
|
||||
|
||||
if k in ( CursorKind.TRANSLATION_UNIT,
|
||||
CursorKind.MACRO_DEFINITION,
|
||||
CursorKind.MACRO_INSTANTIATION,
|
||||
CursorKind.INCLUSION_DIRECTIVE,
|
||||
CursorKind.PREPROCESSING_DIRECTIVE):
|
||||
assert len(group) == 0
|
||||
else:
|
||||
assert len(group) == 1
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
from clang.cindex import *
|
||||
from .util import get_tu
|
||||
|
||||
# FIXME: We need support for invalid translation units to test better.
|
||||
|
||||
def test_diagnostic_warning():
|
||||
tu = get_tu('int f0() {}\n')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 1
|
||||
assert tu.diagnostics[0].location.column == 11
|
||||
assert (tu.diagnostics[0].spelling ==
|
||||
'control reaches end of non-void function')
|
||||
|
||||
def test_diagnostic_note():
|
||||
# FIXME: We aren't getting notes here for some reason.
|
||||
tu = get_tu('#define A x\nvoid *A = 1;\n')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 2
|
||||
assert tu.diagnostics[0].location.column == 7
|
||||
assert 'incompatible' in tu.diagnostics[0].spelling
|
||||
# assert tu.diagnostics[1].severity == Diagnostic.Note
|
||||
# assert tu.diagnostics[1].location.line == 1
|
||||
# assert tu.diagnostics[1].location.column == 11
|
||||
# assert tu.diagnostics[1].spelling == 'instantiated from'
|
||||
|
||||
def test_diagnostic_fixit():
|
||||
tu = get_tu('struct { int f0; } x = { f0 : 1 };')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 1
|
||||
assert tu.diagnostics[0].location.column == 26
|
||||
assert tu.diagnostics[0].spelling.startswith('use of GNU old-style')
|
||||
assert len(tu.diagnostics[0].fixits) == 1
|
||||
assert tu.diagnostics[0].fixits[0].range.start.line == 1
|
||||
assert tu.diagnostics[0].fixits[0].range.start.column == 26
|
||||
assert tu.diagnostics[0].fixits[0].range.end.line == 1
|
||||
assert tu.diagnostics[0].fixits[0].range.end.column == 30
|
||||
assert tu.diagnostics[0].fixits[0].value == '.f0 = '
|
||||
|
||||
def test_diagnostic_range():
|
||||
tu = get_tu('void f() { int i = "a" + 1; }')
|
||||
assert len(tu.diagnostics) == 1
|
||||
assert tu.diagnostics[0].severity == Diagnostic.Warning
|
||||
assert tu.diagnostics[0].location.line == 1
|
||||
assert tu.diagnostics[0].location.column == 16
|
||||
assert tu.diagnostics[0].spelling.startswith('incompatible pointer to')
|
||||
assert len(tu.diagnostics[0].fixits) == 0
|
||||
assert len(tu.diagnostics[0].ranges) == 1
|
||||
assert tu.diagnostics[0].ranges[0].start.line == 1
|
||||
assert tu.diagnostics[0].ranges[0].start.column == 20
|
||||
assert tu.diagnostics[0].ranges[0].end.line == 1
|
||||
assert tu.diagnostics[0].ranges[0].end.column == 27
|
||||
try:
|
||||
tu.diagnostics[0].ranges[1].start.line
|
||||
except IndexError:
|
||||
assert True
|
||||
else:
|
||||
assert False
|
||||
|
||||
def test_diagnostic_category():
|
||||
"""Ensure that category properties work."""
|
||||
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
|
||||
assert len(tu.diagnostics) == 1
|
||||
d = tu.diagnostics[0]
|
||||
|
||||
assert d.severity == Diagnostic.Warning
|
||||
assert d.location.line == 1
|
||||
assert d.location.column == 11
|
||||
|
||||
assert d.category_number == 2
|
||||
assert d.category_name == 'Semantic Issue'
|
||||
|
||||
def test_diagnostic_option():
|
||||
"""Ensure that category option properties work."""
|
||||
tu = get_tu('int f(int i) { return 7; }', all_warnings=True)
|
||||
assert len(tu.diagnostics) == 1
|
||||
d = tu.diagnostics[0]
|
||||
|
||||
assert d.option == '-Wunused-parameter'
|
||||
assert d.disable_option == '-Wno-unused-parameter'
|
||||
@@ -0,0 +1,9 @@
|
||||
from clang.cindex import Index, File
|
||||
|
||||
def test_file():
|
||||
index = Index.create()
|
||||
tu = index.parse('t.c', unsaved_files = [('t.c', "")])
|
||||
file = File.from_name(tu, "t.c")
|
||||
assert str(file) == "t.c"
|
||||
assert file.name == "t.c"
|
||||
assert repr(file) == "<File: t.c>"
|
||||
@@ -0,0 +1,15 @@
|
||||
from clang.cindex import *
|
||||
import os
|
||||
|
||||
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
|
||||
|
||||
def test_create():
|
||||
index = Index.create()
|
||||
|
||||
# FIXME: test Index.read
|
||||
|
||||
def test_parse():
|
||||
index = Index.create()
|
||||
assert isinstance(index, Index)
|
||||
tu = index.parse(os.path.join(kInputsDir, 'hello.cpp'))
|
||||
assert isinstance(tu, TranslationUnit)
|
||||
@@ -0,0 +1,95 @@
|
||||
from clang.cindex import Cursor
|
||||
from clang.cindex import File
|
||||
from clang.cindex import SourceLocation
|
||||
from clang.cindex import SourceRange
|
||||
from .util import get_cursor
|
||||
from .util import get_tu
|
||||
|
||||
baseInput="int one;\nint two;\n"
|
||||
|
||||
def assert_location(loc, line, column, offset):
|
||||
assert loc.line == line
|
||||
assert loc.column == column
|
||||
assert loc.offset == offset
|
||||
|
||||
def test_location():
|
||||
tu = get_tu(baseInput)
|
||||
one = get_cursor(tu, 'one')
|
||||
two = get_cursor(tu, 'two')
|
||||
|
||||
assert one is not None
|
||||
assert two is not None
|
||||
|
||||
assert_location(one.location,line=1,column=5,offset=4)
|
||||
assert_location(two.location,line=2,column=5,offset=13)
|
||||
|
||||
# adding a linebreak at top should keep columns same
|
||||
tu = get_tu('\n' + baseInput)
|
||||
one = get_cursor(tu, 'one')
|
||||
two = get_cursor(tu, 'two')
|
||||
|
||||
assert one is not None
|
||||
assert two is not None
|
||||
|
||||
assert_location(one.location,line=2,column=5,offset=5)
|
||||
assert_location(two.location,line=3,column=5,offset=14)
|
||||
|
||||
# adding a space should affect column on first line only
|
||||
tu = get_tu(' ' + baseInput)
|
||||
one = get_cursor(tu, 'one')
|
||||
two = get_cursor(tu, 'two')
|
||||
|
||||
assert_location(one.location,line=1,column=6,offset=5)
|
||||
assert_location(two.location,line=2,column=5,offset=14)
|
||||
|
||||
# define the expected location ourselves and see if it matches
|
||||
# the returned location
|
||||
tu = get_tu(baseInput)
|
||||
|
||||
file = File.from_name(tu, 't.c')
|
||||
location = SourceLocation.from_position(tu, file, 1, 5)
|
||||
cursor = Cursor.from_location(tu, location)
|
||||
|
||||
one = get_cursor(tu, 'one')
|
||||
assert one is not None
|
||||
assert one == cursor
|
||||
|
||||
# Ensure locations referring to the same entity are equivalent.
|
||||
location2 = SourceLocation.from_position(tu, file, 1, 5)
|
||||
assert location == location2
|
||||
location3 = SourceLocation.from_position(tu, file, 1, 4)
|
||||
assert location2 != location3
|
||||
|
||||
offset_location = SourceLocation.from_offset(tu, file, 5)
|
||||
cursor = Cursor.from_location(tu, offset_location)
|
||||
verified = False
|
||||
for n in [n for n in tu.cursor.get_children() if n.spelling == 'one']:
|
||||
assert n == cursor
|
||||
verified = True
|
||||
|
||||
assert verified
|
||||
|
||||
def test_extent():
|
||||
tu = get_tu(baseInput)
|
||||
one = get_cursor(tu, 'one')
|
||||
two = get_cursor(tu, 'two')
|
||||
|
||||
assert_location(one.extent.start,line=1,column=1,offset=0)
|
||||
assert_location(one.extent.end,line=1,column=8,offset=7)
|
||||
assert baseInput[one.extent.start.offset:one.extent.end.offset] == "int one"
|
||||
|
||||
assert_location(two.extent.start,line=2,column=1,offset=9)
|
||||
assert_location(two.extent.end,line=2,column=8,offset=16)
|
||||
assert baseInput[two.extent.start.offset:two.extent.end.offset] == "int two"
|
||||
|
||||
file = File.from_name(tu, 't.c')
|
||||
location1 = SourceLocation.from_position(tu, file, 1, 1)
|
||||
location2 = SourceLocation.from_position(tu, file, 1, 8)
|
||||
|
||||
range1 = SourceRange.from_locations(location1, location2)
|
||||
range2 = SourceRange.from_locations(location1, location2)
|
||||
assert range1 == range2
|
||||
|
||||
location3 = SourceLocation.from_position(tu, file, 1, 6)
|
||||
range3 = SourceRange.from_locations(location1, location3)
|
||||
assert range1 != range3
|
||||
@@ -0,0 +1,43 @@
|
||||
from clang.cindex import TokenKind
|
||||
from nose.tools import eq_
|
||||
from nose.tools import ok_
|
||||
from nose.tools import raises
|
||||
|
||||
def test_constructor():
|
||||
"""Ensure TokenKind constructor works as expected."""
|
||||
|
||||
t = TokenKind(5, 'foo')
|
||||
|
||||
eq_(t.value, 5)
|
||||
eq_(t.name, 'foo')
|
||||
|
||||
@raises(ValueError)
|
||||
def test_bad_register():
|
||||
"""Ensure a duplicate value is rejected for registration."""
|
||||
|
||||
TokenKind.register(2, 'foo')
|
||||
|
||||
@raises(ValueError)
|
||||
def test_unknown_value():
|
||||
"""Ensure trying to fetch an unknown value raises."""
|
||||
|
||||
TokenKind.from_value(-1)
|
||||
|
||||
def test_registration():
|
||||
"""Ensure that items registered appear as class attributes."""
|
||||
ok_(hasattr(TokenKind, 'LITERAL'))
|
||||
literal = TokenKind.LITERAL
|
||||
|
||||
ok_(isinstance(literal, TokenKind))
|
||||
|
||||
def test_from_value():
|
||||
"""Ensure registered values can be obtained from from_value()."""
|
||||
t = TokenKind.from_value(3)
|
||||
ok_(isinstance(t, TokenKind))
|
||||
eq_(t, TokenKind.LITERAL)
|
||||
|
||||
def test_repr():
|
||||
"""Ensure repr() works."""
|
||||
|
||||
r = repr(TokenKind.LITERAL)
|
||||
eq_(r, 'TokenKind.LITERAL')
|
||||
@@ -0,0 +1,52 @@
|
||||
from clang.cindex import CursorKind
|
||||
from clang.cindex import Index
|
||||
from clang.cindex import SourceLocation
|
||||
from clang.cindex import SourceRange
|
||||
from clang.cindex import TokenKind
|
||||
from nose.tools import eq_
|
||||
from nose.tools import ok_
|
||||
|
||||
from .util import get_tu
|
||||
|
||||
def test_token_to_cursor():
|
||||
"""Ensure we can obtain a Cursor from a Token instance."""
|
||||
tu = get_tu('int i = 5;')
|
||||
r = tu.get_extent('t.c', (0, 9))
|
||||
tokens = list(tu.get_tokens(extent=r))
|
||||
|
||||
assert len(tokens) == 5
|
||||
assert tokens[1].spelling == 'i'
|
||||
assert tokens[1].kind == TokenKind.IDENTIFIER
|
||||
|
||||
cursor = tokens[1].cursor
|
||||
assert cursor.kind == CursorKind.VAR_DECL
|
||||
assert tokens[1].cursor == tokens[2].cursor
|
||||
|
||||
def test_token_location():
|
||||
"""Ensure Token.location works."""
|
||||
|
||||
tu = get_tu('int foo = 10;')
|
||||
r = tu.get_extent('t.c', (0, 11))
|
||||
|
||||
tokens = list(tu.get_tokens(extent=r))
|
||||
eq_(len(tokens), 4)
|
||||
|
||||
loc = tokens[1].location
|
||||
ok_(isinstance(loc, SourceLocation))
|
||||
eq_(loc.line, 1)
|
||||
eq_(loc.column, 5)
|
||||
eq_(loc.offset, 4)
|
||||
|
||||
def test_token_extent():
|
||||
"""Ensure Token.extent works."""
|
||||
tu = get_tu('int foo = 10;')
|
||||
r = tu.get_extent('t.c', (0, 11))
|
||||
|
||||
tokens = list(tu.get_tokens(extent=r))
|
||||
eq_(len(tokens), 4)
|
||||
|
||||
extent = tokens[1].extent
|
||||
ok_(isinstance(extent, SourceRange))
|
||||
|
||||
eq_(extent.start.offset, 4)
|
||||
eq_(extent.end.offset, 7)
|
||||
+258
@@ -0,0 +1,258 @@
|
||||
import gc
|
||||
import os
|
||||
|
||||
from clang.cindex import CursorKind
|
||||
from clang.cindex import Cursor
|
||||
from clang.cindex import File
|
||||
from clang.cindex import Index
|
||||
from clang.cindex import SourceLocation
|
||||
from clang.cindex import SourceRange
|
||||
from clang.cindex import TranslationUnitSaveError
|
||||
from clang.cindex import TranslationUnitLoadError
|
||||
from clang.cindex import TranslationUnit
|
||||
from .util import get_cursor
|
||||
from .util import get_tu
|
||||
|
||||
kInputsDir = os.path.join(os.path.dirname(__file__), 'INPUTS')
|
||||
|
||||
def test_spelling():
|
||||
path = os.path.join(kInputsDir, 'hello.cpp')
|
||||
tu = TranslationUnit.from_source(path)
|
||||
assert tu.spelling == path
|
||||
|
||||
def test_cursor():
|
||||
path = os.path.join(kInputsDir, 'hello.cpp')
|
||||
tu = get_tu(path)
|
||||
c = tu.cursor
|
||||
assert isinstance(c, Cursor)
|
||||
assert c.kind is CursorKind.TRANSLATION_UNIT
|
||||
|
||||
def test_parse_arguments():
|
||||
path = os.path.join(kInputsDir, 'parse_arguments.c')
|
||||
tu = TranslationUnit.from_source(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-2] == 'hello'
|
||||
assert spellings[-1] == 'hi'
|
||||
|
||||
def test_reparse_arguments():
|
||||
path = os.path.join(kInputsDir, 'parse_arguments.c')
|
||||
tu = TranslationUnit.from_source(path, ['-DDECL_ONE=hello', '-DDECL_TWO=hi'])
|
||||
tu.reparse()
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-2] == 'hello'
|
||||
assert spellings[-1] == 'hi'
|
||||
|
||||
def test_unsaved_files():
|
||||
tu = TranslationUnit.from_source('fake.c', ['-I./'], unsaved_files = [
|
||||
('fake.c', """
|
||||
#include "fake.h"
|
||||
int x;
|
||||
int SOME_DEFINE;
|
||||
"""),
|
||||
('./fake.h', """
|
||||
#define SOME_DEFINE y
|
||||
""")
|
||||
])
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-2] == 'x'
|
||||
assert spellings[-1] == 'y'
|
||||
|
||||
def test_unsaved_files_2():
|
||||
import StringIO
|
||||
tu = TranslationUnit.from_source('fake.c', unsaved_files = [
|
||||
('fake.c', StringIO.StringIO('int x;'))])
|
||||
spellings = [c.spelling for c in tu.cursor.get_children()]
|
||||
assert spellings[-1] == 'x'
|
||||
|
||||
def normpaths_equal(path1, path2):
|
||||
""" Compares two paths for equality after normalizing them with
|
||||
os.path.normpath
|
||||
"""
|
||||
return os.path.normpath(path1) == os.path.normpath(path2)
|
||||
|
||||
def test_includes():
|
||||
def eq(expected, actual):
|
||||
if not actual.is_input_file:
|
||||
return normpaths_equal(expected[0], actual.source.name) and \
|
||||
normpaths_equal(expected[1], actual.include.name)
|
||||
else:
|
||||
return normpaths_equal(expected[1], actual.include.name)
|
||||
|
||||
src = os.path.join(kInputsDir, 'include.cpp')
|
||||
h1 = os.path.join(kInputsDir, "header1.h")
|
||||
h2 = os.path.join(kInputsDir, "header2.h")
|
||||
h3 = os.path.join(kInputsDir, "header3.h")
|
||||
inc = [(src, h1), (h1, h3), (src, h2), (h2, h3)]
|
||||
|
||||
tu = TranslationUnit.from_source(src)
|
||||
for i in zip(inc, tu.get_includes()):
|
||||
assert eq(i[0], i[1])
|
||||
|
||||
def save_tu(tu):
|
||||
"""Convenience API to save a TranslationUnit to a file.
|
||||
|
||||
Returns the filename it was saved to.
|
||||
"""
|
||||
|
||||
# FIXME Generate a temp file path using system APIs.
|
||||
base = 'TEMP_FOR_TRANSLATIONUNIT_SAVE.c'
|
||||
path = os.path.join(kInputsDir, base)
|
||||
|
||||
# Just in case.
|
||||
if os.path.exists(path):
|
||||
os.unlink(path)
|
||||
|
||||
tu.save(path)
|
||||
|
||||
return path
|
||||
|
||||
def test_save():
|
||||
"""Ensure TranslationUnit.save() works."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
|
||||
path = save_tu(tu)
|
||||
assert os.path.exists(path)
|
||||
assert os.path.getsize(path) > 0
|
||||
os.unlink(path)
|
||||
|
||||
def test_save_translation_errors():
|
||||
"""Ensure that saving to an invalid directory raises."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
|
||||
path = '/does/not/exist/llvm-test.ast'
|
||||
assert not os.path.exists(os.path.dirname(path))
|
||||
|
||||
try:
|
||||
tu.save(path)
|
||||
assert False
|
||||
except TranslationUnitSaveError as ex:
|
||||
expected = TranslationUnitSaveError.ERROR_UNKNOWN
|
||||
assert ex.save_error == expected
|
||||
|
||||
def test_load():
|
||||
"""Ensure TranslationUnits can be constructed from saved files."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
assert len(tu.diagnostics) == 0
|
||||
path = save_tu(tu)
|
||||
|
||||
assert os.path.exists(path)
|
||||
assert os.path.getsize(path) > 0
|
||||
|
||||
tu2 = TranslationUnit.from_ast_file(filename=path)
|
||||
assert len(tu2.diagnostics) == 0
|
||||
|
||||
foo = get_cursor(tu2, 'foo')
|
||||
assert foo is not None
|
||||
|
||||
# Just in case there is an open file descriptor somewhere.
|
||||
del tu2
|
||||
|
||||
os.unlink(path)
|
||||
|
||||
def test_index_parse():
|
||||
path = os.path.join(kInputsDir, 'hello.cpp')
|
||||
index = Index.create()
|
||||
tu = index.parse(path)
|
||||
assert isinstance(tu, TranslationUnit)
|
||||
|
||||
def test_get_file():
|
||||
"""Ensure tu.get_file() works appropriately."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
|
||||
f = tu.get_file('t.c')
|
||||
assert isinstance(f, File)
|
||||
assert f.name == 't.c'
|
||||
|
||||
try:
|
||||
f = tu.get_file('foobar.cpp')
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
assert False
|
||||
|
||||
def test_get_source_location():
|
||||
"""Ensure tu.get_source_location() works."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
|
||||
location = tu.get_location('t.c', 2)
|
||||
assert isinstance(location, SourceLocation)
|
||||
assert location.offset == 2
|
||||
assert location.file.name == 't.c'
|
||||
|
||||
location = tu.get_location('t.c', (1, 3))
|
||||
assert isinstance(location, SourceLocation)
|
||||
assert location.line == 1
|
||||
assert location.column == 3
|
||||
assert location.file.name == 't.c'
|
||||
|
||||
def test_get_source_range():
|
||||
"""Ensure tu.get_source_range() works."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
|
||||
r = tu.get_extent('t.c', (1,4))
|
||||
assert isinstance(r, SourceRange)
|
||||
assert r.start.offset == 1
|
||||
assert r.end.offset == 4
|
||||
assert r.start.file.name == 't.c'
|
||||
assert r.end.file.name == 't.c'
|
||||
|
||||
r = tu.get_extent('t.c', ((1,2), (1,3)))
|
||||
assert isinstance(r, SourceRange)
|
||||
assert r.start.line == 1
|
||||
assert r.start.column == 2
|
||||
assert r.end.line == 1
|
||||
assert r.end.column == 3
|
||||
assert r.start.file.name == 't.c'
|
||||
assert r.end.file.name == 't.c'
|
||||
|
||||
start = tu.get_location('t.c', 0)
|
||||
end = tu.get_location('t.c', 5)
|
||||
|
||||
r = tu.get_extent('t.c', (start, end))
|
||||
assert isinstance(r, SourceRange)
|
||||
assert r.start.offset == 0
|
||||
assert r.end.offset == 5
|
||||
assert r.start.file.name == 't.c'
|
||||
assert r.end.file.name == 't.c'
|
||||
|
||||
def test_get_tokens_gc():
|
||||
"""Ensures get_tokens() works properly with garbage collection."""
|
||||
|
||||
tu = get_tu('int foo();')
|
||||
r = tu.get_extent('t.c', (0, 10))
|
||||
tokens = list(tu.get_tokens(extent=r))
|
||||
|
||||
assert tokens[0].spelling == 'int'
|
||||
gc.collect()
|
||||
assert tokens[0].spelling == 'int'
|
||||
|
||||
del tokens[1]
|
||||
gc.collect()
|
||||
assert tokens[0].spelling == 'int'
|
||||
|
||||
# May trigger segfault if we don't do our job properly.
|
||||
del tokens
|
||||
gc.collect()
|
||||
gc.collect() # Just in case.
|
||||
|
||||
def test_fail_from_source():
|
||||
path = os.path.join(kInputsDir, 'non-existent.cpp')
|
||||
try:
|
||||
tu = TranslationUnit.from_source(path)
|
||||
except TranslationUnitLoadError:
|
||||
tu = None
|
||||
assert tu == None
|
||||
|
||||
def test_fail_from_ast_file():
|
||||
path = os.path.join(kInputsDir, 'non-existent.ast')
|
||||
try:
|
||||
tu = TranslationUnit.from_ast_file(path)
|
||||
except TranslationUnitLoadError:
|
||||
tu = None
|
||||
assert tu == None
|
||||
@@ -0,0 +1,397 @@
|
||||
import gc
|
||||
|
||||
from clang.cindex import CursorKind
|
||||
from clang.cindex import TranslationUnit
|
||||
from clang.cindex import TypeKind
|
||||
from nose.tools import raises
|
||||
from .util import get_cursor
|
||||
from .util import get_tu
|
||||
|
||||
kInput = """\
|
||||
|
||||
typedef int I;
|
||||
|
||||
struct teststruct {
|
||||
int a;
|
||||
I b;
|
||||
long c;
|
||||
unsigned long d;
|
||||
signed long e;
|
||||
const int f;
|
||||
int *g;
|
||||
int ***h;
|
||||
};
|
||||
|
||||
"""
|
||||
|
||||
def test_a_struct():
|
||||
tu = get_tu(kInput)
|
||||
|
||||
teststruct = get_cursor(tu, 'teststruct')
|
||||
assert teststruct is not None, "Could not find teststruct."
|
||||
fields = list(teststruct.get_children())
|
||||
assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
|
||||
assert all(x.translation_unit is not None for x in fields)
|
||||
|
||||
assert fields[0].spelling == 'a'
|
||||
assert not fields[0].type.is_const_qualified()
|
||||
assert fields[0].type.kind == TypeKind.INT
|
||||
assert fields[0].type.get_canonical().kind == TypeKind.INT
|
||||
|
||||
assert fields[1].spelling == 'b'
|
||||
assert not fields[1].type.is_const_qualified()
|
||||
assert fields[1].type.kind == TypeKind.TYPEDEF
|
||||
assert fields[1].type.get_canonical().kind == TypeKind.INT
|
||||
assert fields[1].type.get_declaration().spelling == 'I'
|
||||
|
||||
assert fields[2].spelling == 'c'
|
||||
assert not fields[2].type.is_const_qualified()
|
||||
assert fields[2].type.kind == TypeKind.LONG
|
||||
assert fields[2].type.get_canonical().kind == TypeKind.LONG
|
||||
|
||||
assert fields[3].spelling == 'd'
|
||||
assert not fields[3].type.is_const_qualified()
|
||||
assert fields[3].type.kind == TypeKind.ULONG
|
||||
assert fields[3].type.get_canonical().kind == TypeKind.ULONG
|
||||
|
||||
assert fields[4].spelling == 'e'
|
||||
assert not fields[4].type.is_const_qualified()
|
||||
assert fields[4].type.kind == TypeKind.LONG
|
||||
assert fields[4].type.get_canonical().kind == TypeKind.LONG
|
||||
|
||||
assert fields[5].spelling == 'f'
|
||||
assert fields[5].type.is_const_qualified()
|
||||
assert fields[5].type.kind == TypeKind.INT
|
||||
assert fields[5].type.get_canonical().kind == TypeKind.INT
|
||||
|
||||
assert fields[6].spelling == 'g'
|
||||
assert not fields[6].type.is_const_qualified()
|
||||
assert fields[6].type.kind == TypeKind.POINTER
|
||||
assert fields[6].type.get_pointee().kind == TypeKind.INT
|
||||
|
||||
assert fields[7].spelling == 'h'
|
||||
assert not fields[7].type.is_const_qualified()
|
||||
assert fields[7].type.kind == TypeKind.POINTER
|
||||
assert fields[7].type.get_pointee().kind == TypeKind.POINTER
|
||||
assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
|
||||
assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
|
||||
|
||||
def test_references():
|
||||
"""Ensure that a Type maintains a reference to a TranslationUnit."""
|
||||
|
||||
tu = get_tu('int x;')
|
||||
children = list(tu.cursor.get_children())
|
||||
assert len(children) > 0
|
||||
|
||||
cursor = children[0]
|
||||
t = cursor.type
|
||||
|
||||
assert isinstance(t.translation_unit, TranslationUnit)
|
||||
|
||||
# Delete main TranslationUnit reference and force a GC.
|
||||
del tu
|
||||
gc.collect()
|
||||
assert isinstance(t.translation_unit, TranslationUnit)
|
||||
|
||||
# If the TU was destroyed, this should cause a segfault.
|
||||
decl = t.get_declaration()
|
||||
|
||||
constarrayInput="""
|
||||
struct teststruct {
|
||||
void *A[2];
|
||||
};
|
||||
"""
|
||||
def testConstantArray():
|
||||
tu = get_tu(constarrayInput)
|
||||
|
||||
teststruct = get_cursor(tu, 'teststruct')
|
||||
assert teststruct is not None, "Didn't find teststruct??"
|
||||
fields = list(teststruct.get_children())
|
||||
assert fields[0].spelling == 'A'
|
||||
assert fields[0].type.kind == TypeKind.CONSTANTARRAY
|
||||
assert fields[0].type.get_array_element_type() is not None
|
||||
assert fields[0].type.get_array_element_type().kind == TypeKind.POINTER
|
||||
assert fields[0].type.get_array_size() == 2
|
||||
|
||||
def test_equal():
|
||||
"""Ensure equivalence operators work on Type."""
|
||||
source = 'int a; int b; void *v;'
|
||||
tu = get_tu(source)
|
||||
|
||||
a = get_cursor(tu, 'a')
|
||||
b = get_cursor(tu, 'b')
|
||||
v = get_cursor(tu, 'v')
|
||||
|
||||
assert a is not None
|
||||
assert b is not None
|
||||
assert v is not None
|
||||
|
||||
assert a.type == b.type
|
||||
assert a.type != v.type
|
||||
|
||||
assert a.type != None
|
||||
assert a.type != 'foo'
|
||||
|
||||
def test_type_spelling():
|
||||
"""Ensure Type.spelling works."""
|
||||
tu = get_tu('int c[5]; 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]; int i[]; int x; int v[x];')
|
||||
c = get_cursor(tu, 'c')
|
||||
i = get_cursor(tu, 'i')
|
||||
v = get_cursor(tu, 'v')
|
||||
assert c is not None
|
||||
assert i is not None
|
||||
assert v is not None
|
||||
|
||||
assert c.type.kind == TypeKind.CONSTANTARRAY
|
||||
assert c.type.element_type.kind == TypeKind.INT
|
||||
assert i.type.kind == TypeKind.INCOMPLETEARRAY
|
||||
assert i.type.element_type.kind == TypeKind.INT
|
||||
assert v.type.kind == TypeKind.VARIABLEARRAY
|
||||
assert v.type.element_type.kind == TypeKind.INT
|
||||
|
||||
@raises(Exception)
|
||||
def test_invalid_element_type():
|
||||
"""Ensure Type.element_type raises if type doesn't have elements."""
|
||||
tu = get_tu('int i;')
|
||||
i = get_cursor(tu, 'i')
|
||||
assert i is not None
|
||||
i.element_type
|
||||
|
||||
def test_element_count():
|
||||
"""Ensure Type.element_count works."""
|
||||
tu = get_tu('int i[5]; int j;')
|
||||
i = get_cursor(tu, 'i')
|
||||
j = get_cursor(tu, 'j')
|
||||
|
||||
assert i is not None
|
||||
assert j is not None
|
||||
|
||||
assert i.type.element_count == 5
|
||||
|
||||
try:
|
||||
j.type.element_count
|
||||
assert False
|
||||
except:
|
||||
assert True
|
||||
|
||||
def test_is_volatile_qualified():
|
||||
"""Ensure Type.is_volatile_qualified works."""
|
||||
|
||||
tu = get_tu('volatile int i = 4; int j = 2;')
|
||||
|
||||
i = get_cursor(tu, 'i')
|
||||
j = get_cursor(tu, 'j')
|
||||
|
||||
assert i is not None
|
||||
assert j is not None
|
||||
|
||||
assert isinstance(i.type.is_volatile_qualified(), bool)
|
||||
assert i.type.is_volatile_qualified()
|
||||
assert not j.type.is_volatile_qualified()
|
||||
|
||||
def test_is_restrict_qualified():
|
||||
"""Ensure Type.is_restrict_qualified works."""
|
||||
|
||||
tu = get_tu('struct s { void * restrict i; void * j; };')
|
||||
|
||||
i = get_cursor(tu, 'i')
|
||||
j = get_cursor(tu, 'j')
|
||||
|
||||
assert i is not None
|
||||
assert j is not None
|
||||
|
||||
assert isinstance(i.type.is_restrict_qualified(), bool)
|
||||
assert i.type.is_restrict_qualified()
|
||||
assert not j.type.is_restrict_qualified()
|
||||
|
||||
def test_record_layout():
|
||||
"""Ensure Cursor.type.get_size, Cursor.type.get_align and
|
||||
Cursor.type.get_offset works."""
|
||||
|
||||
source ="""
|
||||
struct a {
|
||||
long a1;
|
||||
long a2:3;
|
||||
long a3:4;
|
||||
long long a4;
|
||||
};
|
||||
"""
|
||||
tries=[(['-target','i386-linux-gnu'],(4,16,0,32,35,64)),
|
||||
(['-target','nvptx64-unknown-unknown'],(8,24,0,64,67,128)),
|
||||
(['-target','i386-pc-win32'],(8,16,0,32,35,64)),
|
||||
(['-target','msp430-none-none'],(2,14,0,32,35,48))]
|
||||
for flags, values in tries:
|
||||
align,total,a1,a2,a3,a4 = values
|
||||
|
||||
tu = get_tu(source, flags=flags)
|
||||
teststruct = get_cursor(tu, 'a')
|
||||
fields = list(teststruct.get_children())
|
||||
|
||||
assert teststruct.type.get_align() == align
|
||||
assert teststruct.type.get_size() == total
|
||||
assert teststruct.type.get_offset(fields[0].spelling) == a1
|
||||
assert teststruct.type.get_offset(fields[1].spelling) == a2
|
||||
assert teststruct.type.get_offset(fields[2].spelling) == a3
|
||||
assert teststruct.type.get_offset(fields[3].spelling) == a4
|
||||
assert fields[0].is_bitfield() == False
|
||||
assert fields[1].is_bitfield() == True
|
||||
assert fields[1].get_bitfield_width() == 3
|
||||
assert fields[2].is_bitfield() == True
|
||||
assert fields[2].get_bitfield_width() == 4
|
||||
assert fields[3].is_bitfield() == False
|
||||
|
||||
def test_offset():
|
||||
"""Ensure Cursor.get_record_field_offset works in anonymous records"""
|
||||
source="""
|
||||
struct Test {
|
||||
struct {
|
||||
int bariton;
|
||||
union {
|
||||
int foo;
|
||||
};
|
||||
};
|
||||
int bar;
|
||||
};"""
|
||||
tries=[(['-target','i386-linux-gnu'],(4,16,0,32,64)),
|
||||
(['-target','nvptx64-unknown-unknown'],(8,24,0,32,64)),
|
||||
(['-target','i386-pc-win32'],(8,16,0,32,64)),
|
||||
(['-target','msp430-none-none'],(2,14,0,32,64))]
|
||||
for flags, values in tries:
|
||||
align,total,bariton,foo,bar = values
|
||||
tu = get_tu(source)
|
||||
teststruct = get_cursor(tu, 'Test')
|
||||
fields = list(teststruct.get_children())
|
||||
assert teststruct.type.get_offset("bariton") == bariton
|
||||
assert teststruct.type.get_offset("foo") == foo
|
||||
assert teststruct.type.get_offset("bar") == bar
|
||||
|
||||
|
||||
def test_decay():
|
||||
"""Ensure decayed types are handled as the original type"""
|
||||
|
||||
tu = get_tu("void foo(int a[]);")
|
||||
foo = get_cursor(tu, 'foo')
|
||||
a = foo.type.argument_types()[0]
|
||||
|
||||
assert a.kind == TypeKind.INCOMPLETEARRAY
|
||||
assert a.element_type.kind == TypeKind.INT
|
||||
assert a.get_canonical().kind == TypeKind.INCOMPLETEARRAY
|
||||
@@ -0,0 +1,93 @@
|
||||
# This file provides common utility functions for the test suite.
|
||||
|
||||
from clang.cindex import Cursor
|
||||
from clang.cindex import TranslationUnit
|
||||
|
||||
def get_tu(source, lang='c', all_warnings=False, flags=[]):
|
||||
"""Obtain a translation unit from source and language.
|
||||
|
||||
By default, the translation unit is created from source file "t.<ext>"
|
||||
where <ext> is the default file extension for the specified language. By
|
||||
default it is C, so "t.c" is the default file name.
|
||||
|
||||
Supported languages are {c, cpp, objc}.
|
||||
|
||||
all_warnings is a convenience argument to enable all compiler warnings.
|
||||
"""
|
||||
args = list(flags)
|
||||
name = 't.c'
|
||||
if lang == 'cpp':
|
||||
name = 't.cpp'
|
||||
args.append('-std=c++11')
|
||||
elif lang == 'objc':
|
||||
name = 't.m'
|
||||
elif lang != 'c':
|
||||
raise Exception('Unknown language: %s' % lang)
|
||||
|
||||
if all_warnings:
|
||||
args += ['-Wall', '-Wextra']
|
||||
|
||||
return TranslationUnit.from_source(name, args, unsaved_files=[(name,
|
||||
source)])
|
||||
|
||||
def get_cursor(source, spelling):
|
||||
"""Obtain a cursor from a source object.
|
||||
|
||||
This provides a convenient search mechanism to find a cursor with specific
|
||||
spelling within a source. The first argument can be either a
|
||||
TranslationUnit or Cursor instance.
|
||||
|
||||
If the cursor is not found, None is returned.
|
||||
"""
|
||||
children = []
|
||||
if isinstance(source, Cursor):
|
||||
children = source.get_children()
|
||||
else:
|
||||
# Assume TU
|
||||
children = source.cursor.get_children()
|
||||
|
||||
for cursor in children:
|
||||
if cursor.spelling == spelling:
|
||||
return cursor
|
||||
|
||||
# Recurse into children.
|
||||
result = get_cursor(cursor, spelling)
|
||||
if result is not None:
|
||||
return result
|
||||
|
||||
return None
|
||||
|
||||
def get_cursors(source, spelling):
|
||||
"""Obtain all cursors from a source object with a specific spelling.
|
||||
|
||||
This provides a convenient search mechanism to find all cursors with specific
|
||||
spelling within a source. The first argument can be either a
|
||||
TranslationUnit or Cursor instance.
|
||||
|
||||
If no cursors are found, an empty list is returned.
|
||||
"""
|
||||
cursors = []
|
||||
children = []
|
||||
if isinstance(source, Cursor):
|
||||
children = source.get_children()
|
||||
else:
|
||||
# Assume TU
|
||||
children = source.cursor.get_children()
|
||||
|
||||
for cursor in children:
|
||||
if cursor.spelling == spelling:
|
||||
cursors.append(cursor)
|
||||
|
||||
# Recurse into children.
|
||||
cursors.extend(get_cursors(cursor, spelling))
|
||||
|
||||
return cursors
|
||||
|
||||
|
||||
|
||||
|
||||
__all__ = [
|
||||
'get_cursor',
|
||||
'get_cursors',
|
||||
'get_tu',
|
||||
]
|
||||
Reference in New Issue
Block a user