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_underlying_type():
106    tu = get_tu('typedef int foo;')
107    typedef = get_cursor(tu, 'foo')
108    assert typedef is not None
109
110    assert typedef.kind.is_declaration()
111    underlying = typedef.underlying_typedef_type
112    assert underlying.kind == TypeKind.INT
113
114kParentTest = """\
115        class C {
116            void f();
117        }
118
119        void C::f() { }
120    """
121def test_semantic_parent():
122    tu = get_tu(kParentTest, 'cpp')
123    curs = get_cursors(tu, 'f')
124    decl = get_cursor(tu, 'C')
125    assert(len(curs) == 2)
126    assert(curs[0].semantic_parent == curs[1].semantic_parent)
127    assert(curs[0].semantic_parent == decl)
128
129def test_lexical_parent():
130    tu = get_tu(kParentTest, 'cpp')
131    curs = get_cursors(tu, 'f')
132    decl = get_cursor(tu, 'C')
133    assert(len(curs) == 2)
134    assert(curs[0].lexical_parent != curs[1].lexical_parent)
135    assert(curs[0].lexical_parent == decl)
136    assert(curs[1].lexical_parent == tu.cursor)
137
138def test_enum_type():
139    tu = get_tu('enum TEST { FOO=1, BAR=2 };')
140    enum = get_cursor(tu, 'TEST')
141    assert enum is not None
142
143    assert enum.kind == CursorKind.ENUM_DECL
144    enum_type = enum.enum_type
145    assert enum_type.kind == TypeKind.UINT
146
147def test_enum_type_cpp():
148    tu = get_tu('enum TEST : long long { FOO=1, BAR=2 };', lang="cpp")
149    enum = get_cursor(tu, 'TEST')
150    assert enum is not None
151
152    assert enum.kind == CursorKind.ENUM_DECL
153    assert enum.enum_type.kind == TypeKind.LONGLONG
154
155def test_objc_type_encoding():
156    tu = get_tu('int i;', lang='objc')
157    i = get_cursor(tu, 'i')
158
159    assert i is not None
160    assert i.objc_type_encoding == 'i'
161
162def test_enum_values():
163    tu = get_tu('enum TEST { SPAM=1, EGG, HAM = EGG * 20};')
164    enum = get_cursor(tu, 'TEST')
165    assert enum is not None
166
167    assert enum.kind == CursorKind.ENUM_DECL
168
169    enum_constants = list(enum.get_children())
170    assert len(enum_constants) == 3
171
172    spam, egg, ham = enum_constants
173
174    assert spam.kind == CursorKind.ENUM_CONSTANT_DECL
175    assert spam.enum_value == 1
176    assert egg.kind == CursorKind.ENUM_CONSTANT_DECL
177    assert egg.enum_value == 2
178    assert ham.kind == CursorKind.ENUM_CONSTANT_DECL
179    assert ham.enum_value == 40
180
181def test_enum_values_cpp():
182    tu = get_tu('enum TEST : long long { SPAM = -1, HAM = 0x10000000000};', lang="cpp")
183    enum = get_cursor(tu, 'TEST')
184    assert enum is not None
185
186    assert enum.kind == CursorKind.ENUM_DECL
187
188    enum_constants = list(enum.get_children())
189    assert len(enum_constants) == 2
190
191    spam, ham = enum_constants
192
193    assert spam.kind == CursorKind.ENUM_CONSTANT_DECL
194    assert spam.enum_value == -1
195    assert ham.kind == CursorKind.ENUM_CONSTANT_DECL
196    assert ham.enum_value == 0x10000000000
197
198def test_annotation_attribute():
199    tu = get_tu('int foo (void) __attribute__ ((annotate("here be annotation attribute")));')
200
201    foo = get_cursor(tu, 'foo')
202    assert foo is not None
203
204    for c in foo.get_children():
205        if c.kind == CursorKind.ANNOTATE_ATTR:
206            assert c.displayname == "here be annotation attribute"
207            break
208    else:
209        assert False, "Couldn't find annotation"
210
211def test_result_type():
212    tu = get_tu('int foo();')
213    foo = get_cursor(tu, 'foo')
214
215    assert foo is not None
216    t = foo.result_type
217    assert t.kind == TypeKind.INT
218