1import gc
2
3from clang.cindex import CursorKind
4from clang.cindex import TranslationUnit
5from clang.cindex import TypeKind
6from nose.tools import raises
7from .util import get_cursor
8from .util import get_tu
9
10kInput = """\
11
12typedef int I;
13
14struct teststruct {
15  int a;
16  I b;
17  long c;
18  unsigned long d;
19  signed long e;
20  const int f;
21  int *g;
22  int ***h;
23};
24
25"""
26
27def test_a_struct():
28    tu = get_tu(kInput)
29
30    teststruct = get_cursor(tu, 'teststruct')
31    assert teststruct is not None, "Could not find teststruct."
32    fields = list(teststruct.get_children())
33    assert all(x.kind == CursorKind.FIELD_DECL for x in fields)
34    assert all(x.translation_unit is not None for x in fields)
35
36    assert fields[0].spelling == 'a'
37    assert not fields[0].type.is_const_qualified()
38    assert fields[0].type.kind == TypeKind.INT
39    assert fields[0].type.get_canonical().kind == TypeKind.INT
40
41    assert fields[1].spelling == 'b'
42    assert not fields[1].type.is_const_qualified()
43    assert fields[1].type.kind == TypeKind.TYPEDEF
44    assert fields[1].type.get_canonical().kind == TypeKind.INT
45    assert fields[1].type.get_declaration().spelling == 'I'
46
47    assert fields[2].spelling == 'c'
48    assert not fields[2].type.is_const_qualified()
49    assert fields[2].type.kind == TypeKind.LONG
50    assert fields[2].type.get_canonical().kind == TypeKind.LONG
51
52    assert fields[3].spelling == 'd'
53    assert not fields[3].type.is_const_qualified()
54    assert fields[3].type.kind == TypeKind.ULONG
55    assert fields[3].type.get_canonical().kind == TypeKind.ULONG
56
57    assert fields[4].spelling == 'e'
58    assert not fields[4].type.is_const_qualified()
59    assert fields[4].type.kind == TypeKind.LONG
60    assert fields[4].type.get_canonical().kind == TypeKind.LONG
61
62    assert fields[5].spelling == 'f'
63    assert fields[5].type.is_const_qualified()
64    assert fields[5].type.kind == TypeKind.INT
65    assert fields[5].type.get_canonical().kind == TypeKind.INT
66
67    assert fields[6].spelling == 'g'
68    assert not fields[6].type.is_const_qualified()
69    assert fields[6].type.kind == TypeKind.POINTER
70    assert fields[6].type.get_pointee().kind == TypeKind.INT
71
72    assert fields[7].spelling == 'h'
73    assert not fields[7].type.is_const_qualified()
74    assert fields[7].type.kind == TypeKind.POINTER
75    assert fields[7].type.get_pointee().kind == TypeKind.POINTER
76    assert fields[7].type.get_pointee().get_pointee().kind == TypeKind.POINTER
77    assert fields[7].type.get_pointee().get_pointee().get_pointee().kind == TypeKind.INT
78
79def test_references():
80    """Ensure that a Type maintains a reference to a TranslationUnit."""
81
82    tu = get_tu('int x;')
83    children = list(tu.cursor.get_children())
84    assert len(children) > 0
85
86    cursor = children[0]
87    t = cursor.type
88
89    assert isinstance(t.translation_unit, TranslationUnit)
90
91    # Delete main TranslationUnit reference and force a GC.
92    del tu
93    gc.collect()
94    assert isinstance(t.translation_unit, TranslationUnit)
95
96    # If the TU was destroyed, this should cause a segfault.
97    decl = t.get_declaration()
98
99constarrayInput="""
100struct teststruct {
101  void *A[2];
102};
103"""
104def testConstantArray():
105    tu = get_tu(constarrayInput)
106
107    teststruct = get_cursor(tu, 'teststruct')
108    assert teststruct is not None, "Didn't find teststruct??"
109    fields = list(teststruct.get_children())
110    assert fields[0].spelling == 'A'
111    assert fields[0].type.kind == TypeKind.CONSTANTARRAY
112    assert fields[0].type.get_array_element_type() is not None
113    assert fields[0].type.get_array_element_type().kind == TypeKind.POINTER
114    assert fields[0].type.get_array_size() == 2
115
116def test_equal():
117    """Ensure equivalence operators work on Type."""
118    source = 'int a; int b; void *v;'
119    tu = get_tu(source)
120
121    a = get_cursor(tu, 'a')
122    b = get_cursor(tu, 'b')
123    v = get_cursor(tu, 'v')
124
125    assert a is not None
126    assert b is not None
127    assert v is not None
128
129    assert a.type == b.type
130    assert a.type != v.type
131
132    assert a.type != None
133    assert a.type != 'foo'
134
135def test_type_spelling():
136    """Ensure Type.spelling works."""
137    tu = get_tu('int c[5]; int i[]; int x; int v[x];')
138    c = get_cursor(tu, 'c')
139    i = get_cursor(tu, 'i')
140    x = get_cursor(tu, 'x')
141    v = get_cursor(tu, 'v')
142    assert c is not None
143    assert i is not None
144    assert x is not None
145    assert v is not None
146    assert c.type.spelling == "int [5]"
147    assert i.type.spelling == "int []"
148    assert x.type.spelling == "int"
149    assert v.type.spelling == "int [x]"
150
151def test_typekind_spelling():
152    """Ensure TypeKind.spelling works."""
153    tu = get_tu('int a;')
154    a = get_cursor(tu, 'a')
155
156    assert a is not None
157    assert a.type.kind.spelling == 'Int'
158
159def test_function_argument_types():
160    """Ensure that Type.argument_types() works as expected."""
161    tu = get_tu('void f(int, int);')
162    f = get_cursor(tu, 'f')
163    assert f is not None
164
165    args = f.type.argument_types()
166    assert args is not None
167    assert len(args) == 2
168
169    t0 = args[0]
170    assert t0 is not None
171    assert t0.kind == TypeKind.INT
172
173    t1 = args[1]
174    assert t1 is not None
175    assert t1.kind == TypeKind.INT
176
177    args2 = list(args)
178    assert len(args2) == 2
179    assert t0 == args2[0]
180    assert t1 == args2[1]
181
182@raises(TypeError)
183def test_argument_types_string_key():
184    """Ensure that non-int keys raise a TypeError."""
185    tu = get_tu('void f(int, int);')
186    f = get_cursor(tu, 'f')
187    assert f is not None
188
189    args = f.type.argument_types()
190    assert len(args) == 2
191
192    args['foo']
193
194@raises(IndexError)
195def test_argument_types_negative_index():
196    """Ensure that negative indexes on argument_types Raises an IndexError."""
197    tu = get_tu('void f(int, int);')
198    f = get_cursor(tu, 'f')
199    args = f.type.argument_types()
200
201    args[-1]
202
203@raises(IndexError)
204def test_argument_types_overflow_index():
205    """Ensure that indexes beyond the length of Type.argument_types() raise."""
206    tu = get_tu('void f(int, int);')
207    f = get_cursor(tu, 'f')
208    args = f.type.argument_types()
209
210    args[2]
211
212@raises(Exception)
213def test_argument_types_invalid_type():
214    """Ensure that obtaining argument_types on a Type without them raises."""
215    tu = get_tu('int i;')
216    i = get_cursor(tu, 'i')
217    assert i is not None
218
219    i.type.argument_types()
220
221def test_is_pod():
222    """Ensure Type.is_pod() works."""
223    tu = get_tu('int i; void f();')
224    i = get_cursor(tu, 'i')
225    f = get_cursor(tu, 'f')
226
227    assert i is not None
228    assert f is not None
229
230    assert i.type.is_pod()
231    assert not f.type.is_pod()
232
233def test_function_variadic():
234    """Ensure Type.is_function_variadic works."""
235
236    source ="""
237#include <stdarg.h>
238
239void foo(int a, ...);
240void bar(int a, int b);
241"""
242
243    tu = get_tu(source)
244    foo = get_cursor(tu, 'foo')
245    bar = get_cursor(tu, 'bar')
246
247    assert foo is not None
248    assert bar is not None
249
250    assert isinstance(foo.type.is_function_variadic(), bool)
251    assert foo.type.is_function_variadic()
252    assert not bar.type.is_function_variadic()
253
254def test_element_type():
255    """Ensure Type.element_type works."""
256    tu = get_tu('int c[5]; int i[]; int x; int v[x];')
257    c = get_cursor(tu, 'c')
258    i = get_cursor(tu, 'i')
259    v = get_cursor(tu, 'v')
260    assert c is not None
261    assert i is not None
262    assert v is not None
263
264    assert c.type.kind == TypeKind.CONSTANTARRAY
265    assert c.type.element_type.kind == TypeKind.INT
266    assert i.type.kind == TypeKind.INCOMPLETEARRAY
267    assert i.type.element_type.kind == TypeKind.INT
268    assert v.type.kind == TypeKind.VARIABLEARRAY
269    assert v.type.element_type.kind == TypeKind.INT
270
271@raises(Exception)
272def test_invalid_element_type():
273    """Ensure Type.element_type raises if type doesn't have elements."""
274    tu = get_tu('int i;')
275    i = get_cursor(tu, 'i')
276    assert i is not None
277    i.element_type
278
279def test_element_count():
280    """Ensure Type.element_count works."""
281    tu = get_tu('int i[5]; int j;')
282    i = get_cursor(tu, 'i')
283    j = get_cursor(tu, 'j')
284
285    assert i is not None
286    assert j is not None
287
288    assert i.type.element_count == 5
289
290    try:
291        j.type.element_count
292        assert False
293    except:
294        assert True
295
296def test_is_volatile_qualified():
297    """Ensure Type.is_volatile_qualified works."""
298
299    tu = get_tu('volatile int i = 4; int j = 2;')
300
301    i = get_cursor(tu, 'i')
302    j = get_cursor(tu, 'j')
303
304    assert i is not None
305    assert j is not None
306
307    assert isinstance(i.type.is_volatile_qualified(), bool)
308    assert i.type.is_volatile_qualified()
309    assert not j.type.is_volatile_qualified()
310
311def test_is_restrict_qualified():
312    """Ensure Type.is_restrict_qualified works."""
313
314    tu = get_tu('struct s { void * restrict i; void * j; };')
315
316    i = get_cursor(tu, 'i')
317    j = get_cursor(tu, 'j')
318
319    assert i is not None
320    assert j is not None
321
322    assert isinstance(i.type.is_restrict_qualified(), bool)
323    assert i.type.is_restrict_qualified()
324    assert not j.type.is_restrict_qualified()
325
326def test_record_layout():
327    """Ensure Cursor.type.get_size, Cursor.type.get_align and
328    Cursor.type.get_offset works."""
329
330    source ="""
331struct a {
332    long a1;
333    long a2:3;
334    long a3:4;
335    long long a4;
336};
337"""
338    tries=[(['-target','i386-linux-gnu'],(4,16,0,32,35,64)),
339           (['-target','nvptx64-unknown-unknown'],(8,24,0,64,67,128)),
340           (['-target','i386-pc-win32'],(8,16,0,32,35,64)),
341           (['-target','msp430-none-none'],(2,14,0,32,35,48))]
342    for flags, values in tries:
343        align,total,a1,a2,a3,a4 = values
344
345        tu = get_tu(source, flags=flags)
346        teststruct = get_cursor(tu, 'a')
347        fields = list(teststruct.get_children())
348
349        assert teststruct.type.get_align() == align
350        assert teststruct.type.get_size() == total
351        assert teststruct.type.get_offset(fields[0].spelling) == a1
352        assert teststruct.type.get_offset(fields[1].spelling) == a2
353        assert teststruct.type.get_offset(fields[2].spelling) == a3
354        assert teststruct.type.get_offset(fields[3].spelling) == a4
355        assert fields[0].is_bitfield() == False
356        assert fields[1].is_bitfield() == True
357        assert fields[1].get_bitfield_width() == 3
358        assert fields[2].is_bitfield() == True
359        assert fields[2].get_bitfield_width() == 4
360        assert fields[3].is_bitfield() == False
361
362def test_offset():
363    """Ensure Cursor.get_record_field_offset works in anonymous records"""
364    source="""
365struct Test {
366  struct {
367    int bariton;
368    union {
369      int foo;
370    };
371  };
372  int bar;
373};"""
374    tries=[(['-target','i386-linux-gnu'],(4,16,0,32,64)),
375           (['-target','nvptx64-unknown-unknown'],(8,24,0,32,64)),
376           (['-target','i386-pc-win32'],(8,16,0,32,64)),
377           (['-target','msp430-none-none'],(2,14,0,32,64))]
378    for flags, values in tries:
379        align,total,bariton,foo,bar = values
380        tu = get_tu(source)
381        teststruct = get_cursor(tu, 'Test')
382        fields = list(teststruct.get_children())
383        assert teststruct.type.get_offset("bariton") == bariton
384        assert teststruct.type.get_offset("foo") == foo
385        assert teststruct.type.get_offset("bar") == bar
386
387
388def test_decay():
389    """Ensure decayed types are handled as the original type"""
390
391    tu = get_tu("void foo(int a[]);")
392    foo = get_cursor(tu, 'foo')
393    a = foo.type.argument_types()[0]
394
395    assert a.kind == TypeKind.INCOMPLETEARRAY
396    assert a.element_type.kind == TypeKind.INT
397    assert a.get_canonical().kind == TypeKind.INCOMPLETEARRAY
398