• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

trolldbois / ctypeslib / 4773564691

pending completion
4773564691

push

github

Loic Jaquemet
try without baipp

1601 of 1912 relevant lines covered (83.73%)

50.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

69.05
/ctypeslib/codegen/typehandler.py
1
"""Handler for Type nodes from the clang AST tree."""
2

3
from clang.cindex import TypeKind
4

5
from ctypeslib.codegen import typedesc
6
from ctypeslib.codegen.util import log_entity
7
from ctypeslib.codegen.handler import ClangHandler
8
from ctypeslib.codegen.handler import InvalidDefinitionError
9

10
import logging
11
log = logging.getLogger('typehandler')
12

13

14
class TypeHandler(ClangHandler):
15

16
    """
17
    Handles Cursor Kind and transform them into typedesc.
×
18
    """
19

20
    def __init__(self, parser):
48✔
21
        ClangHandler.__init__(self, parser)
48✔
22
        self.init_fundamental_types()
48✔
23

24
    def parse_cursor_type(self, _cursor_type):
48✔
25
        mth = getattr(self, _cursor_type.kind.name)
48✔
26
        return mth(_cursor_type)
48✔
27

28
    ##########################################################################
29
    ##### TypeKind handlers#######
30

31
    def init_fundamental_types(self):
48✔
32
        """Registers all fundamental typekind handlers"""
33
        for _id in range(2, 25):
12✔
34
            setattr(self, TypeKind.from_id(_id).name,
12✔
35
                    self._handle_fundamental_types)
12✔
36

37
    def _handle_fundamental_types(self, typ):
12✔
38
        """
39
        Handles POD types nodes.
40
        see init_fundamental_types for the registration.
41
        """
42
        ctypesname = self.get_ctypes_name(typ.kind)
60✔
43
        if typ.kind == TypeKind.VOID:
60✔
44
            size = align = 1
60✔
45
        else:
×
46
            size = typ.get_size()
60✔
47
            align = typ.get_align()
60✔
48
        return typedesc.FundamentalType(ctypesname, size, align)
60✔
49

50
    # INVALID
51
    # OVERLOAD
52
    # DEPENDENT
53
    # OBJCID
54
    # OBJCCLASS
55
    # OBJCSEL
56
    # COMPLEX
57
    # BLOCKPOINTER
58
    # LVALUEREFERENCE
59
    # RVALUEREFERENCE
60
    # OBJCINTERFACE
61
    # OBJCOBJECTPOINTER
62
    # FUNCTIONNOPROTO
63
    # FUNCTIONPROTO
64
    # VECTOR
65
    # MEMBERPOINTER
66

67
    ## const, restrict and volatile
68
    ## typedesc.CvQualifiedType(typ, const, volatile)
69
    # Type has multiple functions for const, volatile, restrict
70
    # not listed has node in the AST.
71
    # not very useful in python anyway.
72

73
    @log_entity
60✔
74
    def TYPEDEF(self, _cursor_type):
48✔
75
        """
76
        Handles TYPEDEF statement.
77
        """
78
        _decl = _cursor_type.get_declaration()
60✔
79
        name = self.get_unique_name(_decl)
60✔
80
        if self.is_registered(name):
60✔
81
            obj = self.get_registered(name)
60✔
82
        else:
×
83
            log.debug('Was in TYPEDEF but had to parse record declaration for %s', name)
×
84
            obj = self.parse_cursor(_decl)
×
85
        return obj
60✔
86

87
    @log_entity
60✔
88
    def ENUM(self, _cursor_type):
48✔
89
        """
90
        Handles ENUM typedef.
91
        """
92
        _decl = _cursor_type.get_declaration()
60✔
93
        name = self.get_unique_name(_decl)
60✔
94
        if self.is_registered(name):
60✔
95
            obj = self.get_registered(name)
60✔
96
        else:
×
97
            log.warning('Was in ENUM but had to parse record declaration ')
×
98
            obj = self.parse_cursor(_decl)
×
99
        return obj
60✔
100

101
    @log_entity
60✔
102
    def ELABORATED(self, _cursor_type):
48✔
103
        """
104
        Handles elaborated types eg. enum return.
105
        """
106
        _decl = _cursor_type.get_declaration()
×
107
        name = self.get_unique_name(_decl)
×
108
        if self.is_registered(name):
×
109
            obj = self.get_registered(name)
×
110
        else:
×
111
            log.warning('Was in ELABORATED but had to parse record declaration ')
×
112
            obj = self.parse_cursor(_decl)
×
113
        return obj
×
114

115
    @log_entity
60✔
116
    def POINTER(self, _cursor_type):
48✔
117
        """
118
        Handles POINTER types.
119
        """
120
        #
121
        # FIXME catch InvalidDefinitionError and return a void *
122
        #
123
        #
124
        # we shortcut to canonical typedefs and to pointee canonical defs
125
        comment = None
60✔
126
        _type = _cursor_type.get_pointee().get_canonical()
60✔
127
        _p_type_name = self.get_unique_name(_type)
60✔
128
        # get pointer size
129
        size = _cursor_type.get_size()  # not size of pointee
60✔
130
        align = _cursor_type.get_align()
60✔
131
        log.debug(
60✔
132
            "POINTER: size:%d align:%d typ:%s",
60✔
133
            size, align, _type.kind)
60✔
134
        if self.is_fundamental_type(_type):
60✔
135
            p_type = self.parse_cursor_type(_type)
60✔
136
        elif self.is_pointer_type(_type) or self.is_array_type(_type):
60✔
137
            p_type = self.parse_cursor_type(_type)
60✔
138
        elif _type.kind == TypeKind.FUNCTIONPROTO:
60✔
139
            p_type = self.parse_cursor_type(_type)
60✔
140
        elif _type.kind == TypeKind.FUNCTIONNOPROTO:
60✔
141
            p_type = self.parse_cursor_type(_type)
×
142
        else:  # elif _type.kind == TypeKind.RECORD:
×
143
            # check registration
144
            decl = _type.get_declaration()
60✔
145
            decl_name = self.get_unique_name(decl)
60✔
146
            # Type is already defined OR will be defined later.
147
            if self.is_registered(decl_name):
60✔
148
                p_type = self.get_registered(decl_name)
60✔
149
            else:  # forward declaration, without looping
×
150
                log.debug(
60✔
151
                    'POINTER: %s type was not previously declared',
60✔
152
                    decl_name)
60✔
153
                try:
60✔
154
                    p_type = self.parse_cursor(decl)
60✔
155
                except InvalidDefinitionError as e:
×
156
                    # no declaration in source file. Fake a void *
157
                    p_type = typedesc.FundamentalType('None', 1, 1)
×
158
                    comment = "InvalidDefinitionError"
×
159
        log.debug("POINTER: pointee type_name:'%s'", _p_type_name)
60✔
160
        # return the pointer
161
        obj = typedesc.PointerType(p_type, size, align)
60✔
162
        obj.location = p_type.location
60✔
163
        if comment is not None:
60✔
164
            obj.comment = comment
×
165
        return obj
60✔
166

167
    @log_entity
60✔
168
    def _array_handler(self, _cursor_type):
48✔
169
        """
170
        Handles all array types.
171
        Resolves it's element type and makes a Array typedesc.
172
        """
173
        # The element type has been previously declared
174
        # we need to get the canonical typedef, in some cases
175
        _type = _cursor_type.get_canonical()
60✔
176
        size = _type.get_array_size()
60✔
177
        if size == -1 and _type.kind == TypeKind.INCOMPLETEARRAY:
60✔
178
            size = 0
60✔
179
            # FIXME: Incomplete Array handling at end of record.
180
            # https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
181
            # FIXME VARIABLEARRAY DEPENDENTSIZEDARRAY
182
        _array_type = _type.get_array_element_type()  # .get_canonical()
60✔
183
        if self.is_fundamental_type(_array_type):
60✔
184
            _subtype = self.parse_cursor_type(_array_type)
60✔
185
        elif self.is_pointer_type(_array_type):
60✔
186
            # code.interact(local=locals())
187
            # pointers to POD have no declaration ??
188
            # FIXME test_struct_with_pointer x_n_t g[1]
189
            _subtype = self.parse_cursor_type(_array_type)
60✔
190
        elif self.is_array_type(_array_type):
60✔
191
            _subtype = self.parse_cursor_type(_array_type)
×
192
        else:
×
193
            _subtype_decl = _array_type.get_declaration()
60✔
194
            _subtype = self.parse_cursor(_subtype_decl)
60✔
195
            # if _subtype_decl.kind == CursorKind.NO_DECL_FOUND:
196
            #    pass
197
            #_subtype_name = self.get_unique_name(_subtype_decl)
198
            #_subtype = self.get_registered(_subtype_name)
199
        obj = typedesc.ArrayType(_subtype, size)
60✔
200
        obj.location = _subtype.location
60✔
201
        return obj
60✔
202

203
    CONSTANTARRAY = _array_handler
60✔
204
    INCOMPLETEARRAY = _array_handler
60✔
205
    VARIABLEARRAY = _array_handler
60✔
206
    DEPENDENTSIZEDARRAY = _array_handler
60✔
207

208
    @log_entity
60✔
209
    def FUNCTIONPROTO(self, _cursor_type):
48✔
210
        """Handles function prototype."""
211
        # id, returns, attributes
212
        returns = _cursor_type.get_result()
213
        # if self.is_fundamental_type(returns):
214
        returns = self.parse_cursor_type(returns)
215
        attributes = []
216
        obj = typedesc.FunctionType(returns, attributes)
217
        for i, _attr_type in enumerate(_cursor_type.argument_types()):
218
            arg = typedesc.Argument(
219
                "a%d" %
220
                (i),
221
                self.parse_cursor_type(_attr_type))
222
            obj.add_argument(arg)
223
        self.set_location(obj, None)
224
        return obj
225

226
    @log_entity
227
    def FUNCTIONNOPROTO(self, _cursor_type):
228
        """Handles function with no prototype."""
229
        # id, returns, attributes
230
        returns = _cursor_type.get_result()
×
231
        # if self.is_fundamental_type(returns):
232
        returns = self.parse_cursor_type(returns)
×
233
        attributes = []
×
234
        obj = typedesc.FunctionType(returns, attributes)
×
235
        # argument_types cant be asked. no arguments.
236
        self.set_location(obj, None)
×
237
        return obj
×
238

239
    # structures, unions, classes
240

241
    @log_entity
60✔
242
    def RECORD(self, _cursor_type):
48✔
243
        """
244
        A record is a NOT a declaration. A record is the occurrence of a
245
        previously defined record type. So no action is needed. Type is already
246
        known.
247
        Type is accessible by cursor.type.get_declaration()
248
        """
249
        _decl = _cursor_type.get_declaration()  # is a record
60✔
250
        # code.interact(local=locals())
251
        #_decl_cursor = list(_decl.get_children())[0] # record -> decl
252
        name = self.get_unique_name(_decl)  # _cursor)
60✔
253
        if self.is_registered(name):
60✔
254
            obj = self.get_registered(name)
60✔
255
        else:
×
256
            log.debug('Was in RECORD but had to parse record declaration for %s',name)
60✔
257
            obj = self.parse_cursor(_decl)
60✔
258
        return obj
60✔
259

260
    @log_entity
60✔
261
    def UNEXPOSED(self, _cursor_type):
48✔
262
        """
263
        Handles unexposed types.
264
        Returns the canonical type instead.
265
        """
266
        _decl = _cursor_type.get_declaration()
×
267
        name = self.get_unique_name(_decl)  # _cursor)
×
268
        if self.is_registered(name):
×
269
            obj = self.get_registered(name)
×
270
        else:
×
271
            obj = self.parse_cursor(_decl)
×
272
        return obj
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc