1import gc
2
3from clang.cindex import CursorKind
4from clang.cindex import TranslationUnit
5from clang.cindex import TypeKind
6from .util import get_cursor
7from .util import get_cursors
8from .util import get_tu
9
10kInput = """\
11// FIXME: Find nicer way to drop builtins and other cruft.
12int start_decl;
13
14struct s0 {
15  int a;
16  int b;
17};
18
19struct s1;
20
21void f0(int a0, int a1) {
22  int l0, l1;
23
24  if (a0)
25    return;
26
27  for (;;) {
28    break;
29  }
30}
31"""
32
33def test_get_children():
34    tu = get_tu(kInput)
35
36    # Skip until past start_decl.
37    it = tu.cursor.get_children()
38    while it.next().spelling != 'start_decl':
39        pass
40
41    tu_nodes = list(it)
42
43    assert len(tu_nodes) == 3
44    for cursor in tu_nodes:
45        assert cursor.translation_unit is not None
46
47    assert tu_nodes[0] != tu_nodes[1]
48    assert tu_nodes[0].kind == CursorKind.STRUCT_DECL
49    assert tu_nodes[0].spelling == 's0'
50    assert tu_nodes[0].is_definition() == True
51    assert tu_nodes[0].location.file.name == 't.c'
52    assert tu_nodes[0].location.line == 4
53    assert tu_nodes[0].location.column == 8
54    assert tu_nodes[0].hash > 0
55    assert tu_nodes[0].translation_unit is not None
56
57    s0_nodes = list(tu_nodes[0].get_children())
58    assert len(s0_nodes) == 2
59    assert s0_nodes[0].kind == CursorKind.FIELD_DECL
60    assert s0_nodes[0].spelling == 'a'
61    assert s0_nodes[0].type.kind == TypeKind.INT
62    assert s0_nodes[1].kind == CursorKind.FIELD_DECL
63    assert s0_nodes[1].spelling == 'b'
64    assert s0_nodes[1].type.kind == TypeKind.INT
65
66    assert tu_nodes[1].kind == CursorKind.STRUCT_DECL
67    assert tu_nodes[1].spelling == 's1'
68    assert tu_nodes[1].displayname == 's1'
69    assert tu_nodes[1].is_definition() == False
70
71    assert tu_nodes[2].kind == CursorKind.FUNCTION_DECL
72    assert tu_nodes[2].spelling == 'f0'
73    assert tu_nodes[2].displayname == 'f0(int, int)'
74    assert tu_nodes[2].is_definition() == True
75
76def test_references():
77    """Ensure that references to TranslationUnit are kept."""
78    tu = get_tu('int x;')
79    cursors = list(tu.cursor.get_children())
80    assert len(cursors) > 0
81
82    cursor = cursors[0]
83    assert isinstance(cursor.translation_unit, TranslationUnit)
84
85    # Delete reference to TU and perform a full GC.
86    del tu
87    gc.collect()
88    assert isinstance(cursor.translation_unit, TranslationUnit)
89
90    # If the TU was destroyed, this should cause a segfault.
91    parent = cursor.semantic_parent
92
93def test_canonical():
94    source = 'struct X; struct X; struct X { int member; };'
95    tu = get_tu(source)
96
97    cursors = []
98    for cursor in tu.cursor.get_children():
99        if cursor.spelling == 'X':
100            cursors.append(cursor)
101
102    assert len(cursors) == 3
103    assert cursors[1].canonical == cursors[2].canonical
104
105def test_is_static_method():
106    """Ensure Cursor.is_static_method works."""
107
108    source = 'class X { static void foo(); void bar(); };'
109    tu = get_tu(source, lang='cpp')
110
111    cls = get_cursor(tu, 'X')
112    foo = get_cursor(tu, 'foo')
113    bar = get_cursor(tu, 'bar')
114    assert cls is not None
115    assert foo is not None
116    assert bar is not None
117
118    assert foo.is_static_method()
119    assert not bar.is_static_method()
120
121def test_underlying_type():
122    tu = get_tu('typedef int foo;')
123    typedef = get_cursor(tu, 'foo')
124    assert typedef is not None
125
126    assert typedef.kind.is_declaration()
127    underlying = typedef.underlying_typedef_type
128    assert underlying.kind == TypeKind.INT
129
130kParentTest = """\
131        class C {
132            void f();
133        }
134
135        void C::f() { }
136    """
137def test_semantic_parent():
138    tu = get_tu(kParentTest, 'cpp')
139    curs = get_cursors(tu, 'f')
140    decl = get_cursor(tu, 'C')
141    assert(len(curs) == 2)
142    assert(curs[0].semantic_parent == curs[1].semantic_parent)
143    assert(curs[0].semantic_parent == decl)
144
145def test_lexical_parent():
146    tu = get_tu(kParentTest, 'cpp')
147    curs = get_cursors(tu, 'f')
148    decl = get_cursor(tu, 'C')
149    assert(len(curs) == 2)
150    assert(curs[0].lexical_parent != curs[1].lexical_parent)
151    assert(curs[0].lexical_parent == decl)
152    assert(curs[1].lexical_parent == tu.cursor)
153
154def test_enum_type():
155    tu = get_tu('enum TEST { FOO=1, BAR=2 };')
156    enum = get_cursor(tu, 'TEST')
157    assert enum is not None
158
159    assert enum.kind == CursorKind.ENUM_DECL
160    enum_type = enum.enum_type
161    assert enum_type.kind == TypeKind.UINT
162
163def test_enum_type_cpp():
164    tu = get_tu('enum TEST : long long { FOO=1, BAR=2 };', lang="cpp")
165    enum = get_cursor(tu, 'TEST')
166    assert enum is not None
167
168    assert enum.kind == CursorKind.ENUM_DECL
169    assert enum.enum_type.kind == TypeKind.LONGLONG
170
171def test_objc_type_encoding():
172    tu = get_tu('int i;', lang='objc')
173    i = get_cursor(tu, 'i')
174
175    assert i is not None
176    assert i.objc_type_encoding == 'i'
177
178def test_enum_values():
179    tu = get_tu('enum TEST { SPAM=1, EGG, HAM = EGG * 20};')
180    enum = get_cursor(tu, 'TEST')
181    assert enum is not None
182
183    assert enum.kind == CursorKind.ENUM_DECL
184
185    enum_constants = list(enum.get_children())
186    assert len(enum_constants) == 3
187
188    spam, egg, ham = enum_constants
189
190    assert spam.kind == CursorKind.ENUM_CONSTANT_DECL
191    assert spam.enum_value == 1
192    assert egg.kind == CursorKind.ENUM_CONSTANT_DECL
193    assert egg.enum_value == 2
194    assert ham.kind == CursorKind.ENUM_CONSTANT_DECL
195    assert ham.enum_value == 40
196
197def test_enum_values_cpp():
198    tu = get_tu('enum TEST : long long { SPAM = -1, HAM = 0x10000000000};', lang="cpp")
199    enum = get_cursor(tu, 'TEST')
200    assert enum is not None
201
202    assert enum.kind == CursorKind.ENUM_DECL
203
204    enum_constants = list(enum.get_children())
205    assert len(enum_constants) == 2
206
207    spam, ham = enum_constants
208
209    assert spam.kind == CursorKind.ENUM_CONSTANT_DECL
210    assert spam.enum_value == -1
211    assert ham.kind == CursorKind.ENUM_CONSTANT_DECL
212    assert ham.enum_value == 0x10000000000
213
214def test_annotation_attribute():
215    tu = get_tu('int foo (void) __attribute__ ((annotate("here be annotation attribute")));')
216
217    foo = get_cursor(tu, 'foo')
218    assert foo is not None
219
220    for c in foo.get_children():
221        if c.kind == CursorKind.ANNOTATE_ATTR:
222            assert c.displayname == "here be annotation attribute"
223            break
224    else:
225        assert False, "Couldn't find annotation"
226
227def test_result_type():
228    tu = get_tu('int foo();')
229    foo = get_cursor(tu, 'foo')
230
231    assert foo is not None
232    t = foo.result_type
233    assert t.kind == TypeKind.INT
234
235def test_get_tokens():
236    """Ensure we can map cursors back to tokens."""
237    tu = get_tu('int foo(int i);')
238    foo = get_cursor(tu, 'foo')
239
240    tokens = list(foo.get_tokens())
241    assert len(tokens) == 7
242    assert tokens[0].spelling == 'int'
243    assert tokens[1].spelling == 'foo'
244
245def test_get_arguments():
246    tu = get_tu('void foo(int i, int j);')
247    foo = get_cursor(tu, 'foo')
248    arguments = list(foo.get_arguments())
249
250    assert len(arguments) == 2
251    assert arguments[0].spelling == "i"
252    assert arguments[1].spelling == "j"
253
254def test_referenced():
255    tu = get_tu('void foo(); void bar() { foo(); }')
256    foo = get_cursor(tu, 'foo')
257    bar = get_cursor(tu, 'bar')
258    for c in bar.get_children():
259        if c.kind == CursorKind.CALL_EXPR:
260            assert c.referenced.spelling == foo.spelling
261            break
262