lambda-graphs 0.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lambda_graphs/__init__.py +18 -0
- lambda_graphs/__main__.py +7 -0
- lambda_graphs/cli.py +183 -0
- lambda_graphs/codeviews/AST/AST.py +120 -0
- lambda_graphs/codeviews/AST/AST_driver.py +37 -0
- lambda_graphs/codeviews/AST/__init__.py +0 -0
- lambda_graphs/codeviews/CFG/CFG.py +42 -0
- lambda_graphs/codeviews/CFG/CFG_c.py +1182 -0
- lambda_graphs/codeviews/CFG/CFG_cpp.py +5604 -0
- lambda_graphs/codeviews/CFG/CFG_driver.py +45 -0
- lambda_graphs/codeviews/CFG/CFG_java.py +1722 -0
- lambda_graphs/codeviews/CFG/__init__.py +0 -0
- lambda_graphs/codeviews/CST/CST_driver.py +70 -0
- lambda_graphs/codeviews/CST/__init__.py +0 -0
- lambda_graphs/codeviews/DFG/DFG_driver.py +42 -0
- lambda_graphs/codeviews/DFG/__init__.py +0 -0
- lambda_graphs/codeviews/SDFG/SDFG.py +135 -0
- lambda_graphs/codeviews/SDFG/SDFG_c.py +2041 -0
- lambda_graphs/codeviews/SDFG/SDFG_cpp.py +4030 -0
- lambda_graphs/codeviews/SDFG/SDFG_java.py +1618 -0
- lambda_graphs/codeviews/SDFG/__init__.py +0 -0
- lambda_graphs/codeviews/__init__.py +0 -0
- lambda_graphs/codeviews/combined_graph/__init__.py +0 -0
- lambda_graphs/codeviews/combined_graph/combined_driver.py +163 -0
- lambda_graphs/tree_parser/__init__.py +0 -0
- lambda_graphs/tree_parser/c_parser.py +565 -0
- lambda_graphs/tree_parser/cpp_parser.py +424 -0
- lambda_graphs/tree_parser/custom_parser.py +66 -0
- lambda_graphs/tree_parser/java_parser.py +254 -0
- lambda_graphs/tree_parser/parser_driver.py +54 -0
- lambda_graphs/utils/DFG_utils.py +44 -0
- lambda_graphs/utils/__init__.py +0 -0
- lambda_graphs/utils/c_nodes.py +431 -0
- lambda_graphs/utils/cpp_nodes.py +1331 -0
- lambda_graphs/utils/java_nodes.py +756 -0
- lambda_graphs/utils/multi_file_merger.py +444 -0
- lambda_graphs/utils/postprocessor.py +83 -0
- lambda_graphs/utils/preprocessor.py +68 -0
- lambda_graphs/utils/src_parser.py +23 -0
- lambda_graphs-0.1.4.dist-info/METADATA +380 -0
- lambda_graphs-0.1.4.dist-info/RECORD +45 -0
- lambda_graphs-0.1.4.dist-info/WHEEL +5 -0
- lambda_graphs-0.1.4.dist-info/entry_points.txt +2 -0
- lambda_graphs-0.1.4.dist-info/licenses/LICENSE +21 -0
- lambda_graphs-0.1.4.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,565 @@
|
|
|
1
|
+
from ..tree_parser.custom_parser import CustomParser
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class CParser(CustomParser):
|
|
5
|
+
def __init__(self, src_language, src_code):
|
|
6
|
+
super().__init__(src_language, src_code)
|
|
7
|
+
self.struct_definitions = {}
|
|
8
|
+
self.typedef_map = {}
|
|
9
|
+
self._parse_struct_definitions()
|
|
10
|
+
self._parse_typedefs()
|
|
11
|
+
|
|
12
|
+
def check_declaration(self, current_node):
|
|
13
|
+
"""
|
|
14
|
+
Check if the current node is a variable declaration in C.
|
|
15
|
+
C declarations can be:
|
|
16
|
+
- init_declarator (e.g., int x = 5;)
|
|
17
|
+
- Direct child of declaration (e.g., int x;)
|
|
18
|
+
- parameter_declaration (function parameters)
|
|
19
|
+
- pointer_declarator (pointer variables)
|
|
20
|
+
"""
|
|
21
|
+
parent_types = [
|
|
22
|
+
"init_declarator",
|
|
23
|
+
"parameter_declaration",
|
|
24
|
+
"pointer_declarator",
|
|
25
|
+
"array_declarator",
|
|
26
|
+
]
|
|
27
|
+
current_types = ["identifier"]
|
|
28
|
+
|
|
29
|
+
if (
|
|
30
|
+
current_node.parent is not None
|
|
31
|
+
and current_node.parent.type in parent_types
|
|
32
|
+
and current_node.type in current_types
|
|
33
|
+
):
|
|
34
|
+
if current_node.parent.type == "init_declarator":
|
|
35
|
+
if (
|
|
36
|
+
current_node.parent.children
|
|
37
|
+
and current_node.parent.children[0] == current_node
|
|
38
|
+
):
|
|
39
|
+
return True
|
|
40
|
+
if current_node.parent.children[0].type == "pointer_declarator":
|
|
41
|
+
pointer_node = current_node.parent.children[0]
|
|
42
|
+
if self.find_identifier_in_declarator(pointer_node) == current_node:
|
|
43
|
+
return True
|
|
44
|
+
elif current_node.parent.type == "pointer_declarator":
|
|
45
|
+
if current_node.type == "identifier":
|
|
46
|
+
return True
|
|
47
|
+
elif current_node.parent.type == "array_declarator":
|
|
48
|
+
if (
|
|
49
|
+
current_node.parent.children
|
|
50
|
+
and current_node.parent.children[0] == current_node
|
|
51
|
+
):
|
|
52
|
+
return True
|
|
53
|
+
elif current_node.parent.type == "parameter_declaration":
|
|
54
|
+
return True
|
|
55
|
+
|
|
56
|
+
if (
|
|
57
|
+
current_node.parent is not None
|
|
58
|
+
and current_node.parent.type == "declaration"
|
|
59
|
+
and current_node.type == "identifier"
|
|
60
|
+
):
|
|
61
|
+
for i, child in enumerate(current_node.parent.children):
|
|
62
|
+
if child == current_node and i > 0:
|
|
63
|
+
prev_sibling = current_node.parent.children[i - 1]
|
|
64
|
+
if prev_sibling.type in [
|
|
65
|
+
"primitive_type",
|
|
66
|
+
"type_identifier",
|
|
67
|
+
"sized_type_specifier",
|
|
68
|
+
"struct_specifier",
|
|
69
|
+
"union_specifier",
|
|
70
|
+
"enum_specifier",
|
|
71
|
+
"storage_class_specifier",
|
|
72
|
+
"type_qualifier",
|
|
73
|
+
]:
|
|
74
|
+
return True
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
if current_node.parent is not None and current_node.parent.type == "declarator":
|
|
78
|
+
if (
|
|
79
|
+
current_node.parent.parent is not None
|
|
80
|
+
and current_node.parent.parent.type
|
|
81
|
+
in ["declaration", "parameter_declaration"]
|
|
82
|
+
):
|
|
83
|
+
return True
|
|
84
|
+
|
|
85
|
+
if (
|
|
86
|
+
current_node.parent is not None
|
|
87
|
+
and current_node.parent.type == "function_declarator"
|
|
88
|
+
):
|
|
89
|
+
if (
|
|
90
|
+
current_node.parent.children
|
|
91
|
+
and current_node.parent.children[0] == current_node
|
|
92
|
+
):
|
|
93
|
+
return True
|
|
94
|
+
|
|
95
|
+
return False
|
|
96
|
+
|
|
97
|
+
def find_identifier_in_declarator(self, node):
|
|
98
|
+
"""Recursively find the identifier within a declarator node."""
|
|
99
|
+
if node.type == "identifier":
|
|
100
|
+
return node
|
|
101
|
+
for child in node.children:
|
|
102
|
+
result = self.find_identifier_in_declarator(child)
|
|
103
|
+
if result is not None:
|
|
104
|
+
return result
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
def get_type(self, node):
|
|
108
|
+
"""
|
|
109
|
+
Given a declarator node, return the variable type of the identifier INCLUDING pointer indicators.
|
|
110
|
+
C type specifiers include: primitive_type, type_identifier, sized_type_specifier, etc.
|
|
111
|
+
|
|
112
|
+
This function traverses up the tree to find the declaration or parameter_declaration node,
|
|
113
|
+
then searches for the type specifier among its children. This handles complex nested
|
|
114
|
+
declarators like int **pp, int ***ppp, int (*ptr_arr)[10], etc.
|
|
115
|
+
|
|
116
|
+
Returns the full type including pointers, e.g., "char*", "int**", "uint32_t*"
|
|
117
|
+
"""
|
|
118
|
+
datatypes = [
|
|
119
|
+
"primitive_type",
|
|
120
|
+
"type_identifier",
|
|
121
|
+
"sized_type_specifier",
|
|
122
|
+
"struct_specifier",
|
|
123
|
+
"union_specifier",
|
|
124
|
+
"enum_specifier",
|
|
125
|
+
]
|
|
126
|
+
|
|
127
|
+
current = node
|
|
128
|
+
pointer_count = 0
|
|
129
|
+
is_array = False
|
|
130
|
+
|
|
131
|
+
while current is not None:
|
|
132
|
+
if current.type == "pointer_declarator":
|
|
133
|
+
for child in current.children:
|
|
134
|
+
if child.type == "*":
|
|
135
|
+
pointer_count += 1
|
|
136
|
+
|
|
137
|
+
if current.type == "array_declarator":
|
|
138
|
+
is_array = True
|
|
139
|
+
|
|
140
|
+
if current.type in ["declaration", "parameter_declaration"]:
|
|
141
|
+
base_type = None
|
|
142
|
+
for child in current.children:
|
|
143
|
+
if child.type in datatypes:
|
|
144
|
+
base_type = child.text.decode("utf-8")
|
|
145
|
+
break
|
|
146
|
+
|
|
147
|
+
if base_type:
|
|
148
|
+
if pointer_count > 0:
|
|
149
|
+
base_type += "*" * pointer_count
|
|
150
|
+
elif is_array:
|
|
151
|
+
base_type += "*"
|
|
152
|
+
|
|
153
|
+
return self.expand_typedef(base_type)
|
|
154
|
+
|
|
155
|
+
return None
|
|
156
|
+
|
|
157
|
+
current = current.parent
|
|
158
|
+
|
|
159
|
+
return None
|
|
160
|
+
|
|
161
|
+
def scope_check(self, parent_scope, child_scope):
|
|
162
|
+
"""Check if parent_scope is a subset of child_scope."""
|
|
163
|
+
for p in parent_scope:
|
|
164
|
+
if p not in child_scope:
|
|
165
|
+
return False
|
|
166
|
+
return True
|
|
167
|
+
|
|
168
|
+
def longest_scope_match(self, name_matches, symbol_table):
|
|
169
|
+
"""Given a list of name matches, return the longest scope match."""
|
|
170
|
+
scope_array = list(map(lambda x: symbol_table["scope_map"][x[0]], name_matches))
|
|
171
|
+
max_val = max(scope_array, key=lambda x: len(x))
|
|
172
|
+
for i in range(len(scope_array)):
|
|
173
|
+
if scope_array[i] == max_val:
|
|
174
|
+
return name_matches[i][0]
|
|
175
|
+
|
|
176
|
+
def create_all_tokens(
|
|
177
|
+
self,
|
|
178
|
+
src_code,
|
|
179
|
+
root_node,
|
|
180
|
+
all_tokens,
|
|
181
|
+
label,
|
|
182
|
+
method_map,
|
|
183
|
+
method_calls,
|
|
184
|
+
start_line,
|
|
185
|
+
declaration,
|
|
186
|
+
declaration_map,
|
|
187
|
+
symbol_table,
|
|
188
|
+
):
|
|
189
|
+
"""
|
|
190
|
+
Create tokens for C language.
|
|
191
|
+
Handles C-specific constructs like pointers, arrays, function calls, etc.
|
|
192
|
+
"""
|
|
193
|
+
remove_list = ["function_definition", "call_expression"]
|
|
194
|
+
|
|
195
|
+
block_types = [
|
|
196
|
+
"compound_statement",
|
|
197
|
+
"if_statement",
|
|
198
|
+
"while_statement",
|
|
199
|
+
"for_statement",
|
|
200
|
+
"do_statement",
|
|
201
|
+
"switch_statement",
|
|
202
|
+
"case_statement",
|
|
203
|
+
"function_definition",
|
|
204
|
+
]
|
|
205
|
+
|
|
206
|
+
if root_node.is_named and root_node.type in block_types:
|
|
207
|
+
symbol_table["scope_id"] = symbol_table["scope_id"] + 1
|
|
208
|
+
symbol_table["scope_stack"].append(symbol_table["scope_id"])
|
|
209
|
+
|
|
210
|
+
if (
|
|
211
|
+
root_node.is_named
|
|
212
|
+
and (
|
|
213
|
+
len(root_node.children) == 0
|
|
214
|
+
or root_node.type in ["string_literal", "variadic_parameter"]
|
|
215
|
+
)
|
|
216
|
+
and root_node.type != "comment"
|
|
217
|
+
):
|
|
218
|
+
index = self.index[
|
|
219
|
+
(root_node.start_point, root_node.end_point, root_node.type)
|
|
220
|
+
]
|
|
221
|
+
|
|
222
|
+
label[index] = root_node.text.decode("UTF-8")
|
|
223
|
+
|
|
224
|
+
start_line[index] = root_node.start_point[0]
|
|
225
|
+
|
|
226
|
+
all_tokens.append(index)
|
|
227
|
+
|
|
228
|
+
symbol_table["scope_map"][index] = symbol_table["scope_stack"].copy()
|
|
229
|
+
|
|
230
|
+
current_node = root_node
|
|
231
|
+
|
|
232
|
+
if (
|
|
233
|
+
current_node.parent is not None
|
|
234
|
+
and current_node.parent.type in remove_list
|
|
235
|
+
):
|
|
236
|
+
method_map.append(index)
|
|
237
|
+
if (
|
|
238
|
+
current_node.next_named_sibling is not None
|
|
239
|
+
and current_node.next_named_sibling.type == "argument_list"
|
|
240
|
+
):
|
|
241
|
+
method_calls.append(index)
|
|
242
|
+
|
|
243
|
+
if (
|
|
244
|
+
current_node.parent is not None
|
|
245
|
+
and current_node.parent.type == "call_expression"
|
|
246
|
+
):
|
|
247
|
+
if (
|
|
248
|
+
current_node.parent.children
|
|
249
|
+
and current_node.parent.children[0] == current_node
|
|
250
|
+
):
|
|
251
|
+
method_map.append(index)
|
|
252
|
+
method_calls.append(index)
|
|
253
|
+
|
|
254
|
+
if (
|
|
255
|
+
current_node.parent is not None
|
|
256
|
+
and current_node.parent.type == "field_expression"
|
|
257
|
+
):
|
|
258
|
+
field_node = current_node.parent.child_by_field_name("field")
|
|
259
|
+
if field_node is not None:
|
|
260
|
+
field_index = self.index[
|
|
261
|
+
(field_node.start_point, field_node.end_point, field_node.type)
|
|
262
|
+
]
|
|
263
|
+
current_index = self.index[
|
|
264
|
+
(
|
|
265
|
+
current_node.start_point,
|
|
266
|
+
current_node.end_point,
|
|
267
|
+
current_node.type,
|
|
268
|
+
)
|
|
269
|
+
]
|
|
270
|
+
if field_index == current_index:
|
|
271
|
+
method_map.append(current_index)
|
|
272
|
+
|
|
273
|
+
while (
|
|
274
|
+
current_node.parent is not None
|
|
275
|
+
and current_node.parent.type == "field_expression"
|
|
276
|
+
):
|
|
277
|
+
current_node = current_node.parent
|
|
278
|
+
|
|
279
|
+
if (
|
|
280
|
+
current_node.parent is not None
|
|
281
|
+
and current_node.parent.type == "call_expression"
|
|
282
|
+
):
|
|
283
|
+
method_map.append(index)
|
|
284
|
+
method_calls.append(index)
|
|
285
|
+
label[index] = current_node.text.decode("UTF-8")
|
|
286
|
+
|
|
287
|
+
if self.check_declaration(current_node):
|
|
288
|
+
variable_name = label[index]
|
|
289
|
+
declaration[index] = variable_name
|
|
290
|
+
|
|
291
|
+
variable_type = self.get_type(current_node.parent)
|
|
292
|
+
if variable_type is not None:
|
|
293
|
+
symbol_table["data_type"][index] = variable_type
|
|
294
|
+
else:
|
|
295
|
+
current_scope = symbol_table["scope_map"][index]
|
|
296
|
+
|
|
297
|
+
if (
|
|
298
|
+
current_node.parent is not None
|
|
299
|
+
and current_node.parent.type == "field_expression"
|
|
300
|
+
):
|
|
301
|
+
field_variable = current_node.parent.children[-1]
|
|
302
|
+
field_variable_name = field_variable.text.decode("utf-8")
|
|
303
|
+
|
|
304
|
+
for ind, var in declaration.items():
|
|
305
|
+
if var == field_variable_name:
|
|
306
|
+
parent_scope = symbol_table["scope_map"][ind]
|
|
307
|
+
if self.scope_check(parent_scope, current_scope):
|
|
308
|
+
declaration_map[index] = ind
|
|
309
|
+
break
|
|
310
|
+
else:
|
|
311
|
+
name_matches = []
|
|
312
|
+
for ind, var in declaration.items():
|
|
313
|
+
if var == label[index]:
|
|
314
|
+
parent_scope = symbol_table["scope_map"][ind]
|
|
315
|
+
if self.scope_check(parent_scope, current_scope):
|
|
316
|
+
name_matches.append((ind, var))
|
|
317
|
+
|
|
318
|
+
if name_matches:
|
|
319
|
+
closest_index = self.longest_scope_match(
|
|
320
|
+
name_matches, symbol_table
|
|
321
|
+
)
|
|
322
|
+
declaration_map[index] = closest_index
|
|
323
|
+
|
|
324
|
+
else:
|
|
325
|
+
for child in root_node.children:
|
|
326
|
+
self.create_all_tokens(
|
|
327
|
+
src_code,
|
|
328
|
+
child,
|
|
329
|
+
all_tokens,
|
|
330
|
+
label,
|
|
331
|
+
method_map,
|
|
332
|
+
method_calls,
|
|
333
|
+
start_line,
|
|
334
|
+
declaration,
|
|
335
|
+
declaration_map,
|
|
336
|
+
symbol_table,
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
if root_node.is_named and root_node.type in block_types:
|
|
340
|
+
symbol_table["scope_stack"].pop(-1)
|
|
341
|
+
|
|
342
|
+
return (
|
|
343
|
+
all_tokens,
|
|
344
|
+
label,
|
|
345
|
+
method_map,
|
|
346
|
+
method_calls,
|
|
347
|
+
start_line,
|
|
348
|
+
declaration,
|
|
349
|
+
declaration_map,
|
|
350
|
+
symbol_table,
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
def _parse_struct_definitions(self):
|
|
354
|
+
"""
|
|
355
|
+
Parse all struct definitions in the code and build a mapping of
|
|
356
|
+
struct_name -> {field_name: field_type}
|
|
357
|
+
|
|
358
|
+
This allows us to resolve struct field types when we encounter
|
|
359
|
+
field_expression nodes like p.x or ptr->field.
|
|
360
|
+
"""
|
|
361
|
+
|
|
362
|
+
def traverse_for_structs(node):
|
|
363
|
+
if node.type == "struct_specifier":
|
|
364
|
+
struct_name = None
|
|
365
|
+
field_list = None
|
|
366
|
+
|
|
367
|
+
for child in node.children:
|
|
368
|
+
if child.type == "type_identifier":
|
|
369
|
+
struct_name = child.text.decode("utf-8")
|
|
370
|
+
elif child.type == "field_declaration_list":
|
|
371
|
+
field_list = child
|
|
372
|
+
|
|
373
|
+
if struct_name and field_list:
|
|
374
|
+
fields = {}
|
|
375
|
+
for field_decl in field_list.children:
|
|
376
|
+
if field_decl.type == "field_declaration":
|
|
377
|
+
field_type = None
|
|
378
|
+
field_names = []
|
|
379
|
+
|
|
380
|
+
for fc in field_decl.children:
|
|
381
|
+
if fc.type in [
|
|
382
|
+
"primitive_type",
|
|
383
|
+
"type_identifier",
|
|
384
|
+
"sized_type_specifier",
|
|
385
|
+
"struct_specifier",
|
|
386
|
+
]:
|
|
387
|
+
if fc.type == "struct_specifier":
|
|
388
|
+
for sc in fc.children:
|
|
389
|
+
if sc.type == "type_identifier":
|
|
390
|
+
field_type = "struct " + sc.text.decode(
|
|
391
|
+
"utf-8"
|
|
392
|
+
)
|
|
393
|
+
break
|
|
394
|
+
else:
|
|
395
|
+
field_type = fc.text.decode("utf-8")
|
|
396
|
+
|
|
397
|
+
elif fc.type == "field_identifier":
|
|
398
|
+
field_names.append(fc.text.decode("utf-8"))
|
|
399
|
+
elif fc.type == "pointer_declarator":
|
|
400
|
+
pointer_count = fc.text.decode("utf-8").count("*")
|
|
401
|
+
for pchild in fc.named_children:
|
|
402
|
+
if pchild.type == "field_identifier":
|
|
403
|
+
field_names.append(
|
|
404
|
+
pchild.text.decode("utf-8")
|
|
405
|
+
)
|
|
406
|
+
break
|
|
407
|
+
if field_type:
|
|
408
|
+
field_type += "*" * pointer_count
|
|
409
|
+
elif fc.type == "array_declarator":
|
|
410
|
+
for achild in fc.children:
|
|
411
|
+
if achild.type == "field_identifier":
|
|
412
|
+
field_names.append(
|
|
413
|
+
achild.text.decode("utf-8")
|
|
414
|
+
)
|
|
415
|
+
break
|
|
416
|
+
if field_type:
|
|
417
|
+
field_type += "*"
|
|
418
|
+
|
|
419
|
+
for fname in field_names:
|
|
420
|
+
fields[fname] = field_type if field_type else "unknown"
|
|
421
|
+
|
|
422
|
+
self.struct_definitions[struct_name] = fields
|
|
423
|
+
|
|
424
|
+
for child in node.children:
|
|
425
|
+
traverse_for_structs(child)
|
|
426
|
+
|
|
427
|
+
traverse_for_structs(self.root_node)
|
|
428
|
+
|
|
429
|
+
def get_struct_field_type(self, struct_name, field_name):
|
|
430
|
+
"""
|
|
431
|
+
Get the type of a field in a struct.
|
|
432
|
+
|
|
433
|
+
Args:
|
|
434
|
+
struct_name: Name of the struct (without 'struct' keyword)
|
|
435
|
+
field_name: Name of the field
|
|
436
|
+
|
|
437
|
+
Returns:
|
|
438
|
+
Type string or "unknown" if not found
|
|
439
|
+
"""
|
|
440
|
+
if struct_name.startswith("struct "):
|
|
441
|
+
struct_name = struct_name[7:]
|
|
442
|
+
|
|
443
|
+
if struct_name in self.struct_definitions:
|
|
444
|
+
return self.struct_definitions[struct_name].get(field_name, "unknown")
|
|
445
|
+
return "unknown"
|
|
446
|
+
|
|
447
|
+
def _parse_typedefs(self):
|
|
448
|
+
"""
|
|
449
|
+
Parse all typedef declarations and build a mapping of
|
|
450
|
+
typedef_name -> actual_type
|
|
451
|
+
|
|
452
|
+
This allows us to expand typedef aliases when resolving types.
|
|
453
|
+
"""
|
|
454
|
+
|
|
455
|
+
def traverse_for_typedefs(node):
|
|
456
|
+
if node.type == "type_definition":
|
|
457
|
+
children = [
|
|
458
|
+
c for c in node.children if c.type != ";" and c.type != "typedef"
|
|
459
|
+
]
|
|
460
|
+
|
|
461
|
+
if len(children) < 2:
|
|
462
|
+
return
|
|
463
|
+
|
|
464
|
+
typedef_name = None
|
|
465
|
+
actual_type = None
|
|
466
|
+
pointer_count = 0
|
|
467
|
+
|
|
468
|
+
if any(c.type == "pointer_declarator" for c in children):
|
|
469
|
+
if children[0].type in [
|
|
470
|
+
"primitive_type",
|
|
471
|
+
"sized_type_specifier",
|
|
472
|
+
"type_identifier",
|
|
473
|
+
]:
|
|
474
|
+
actual_type = children[0].text.decode("utf-8")
|
|
475
|
+
|
|
476
|
+
for child in children:
|
|
477
|
+
if child.type == "pointer_declarator":
|
|
478
|
+
pointer_count = child.text.decode("utf-8").count("*")
|
|
479
|
+
|
|
480
|
+
def find_typedef_name(node):
|
|
481
|
+
if node.type in ["type_identifier", "identifier"]:
|
|
482
|
+
return node.text.decode("utf-8")
|
|
483
|
+
for c in node.named_children:
|
|
484
|
+
result = find_typedef_name(c)
|
|
485
|
+
if result:
|
|
486
|
+
return result
|
|
487
|
+
return None
|
|
488
|
+
|
|
489
|
+
typedef_name = find_typedef_name(child)
|
|
490
|
+
|
|
491
|
+
elif any(c.type == "function_declarator" for c in children):
|
|
492
|
+
if children[0].type in ["primitive_type", "type_identifier"]:
|
|
493
|
+
actual_type = "function_pointer"
|
|
494
|
+
|
|
495
|
+
for child in children:
|
|
496
|
+
if child.type == "function_declarator":
|
|
497
|
+
for fc in child.children:
|
|
498
|
+
if fc.type == "pointer_declarator":
|
|
499
|
+
for pdc in fc.named_children:
|
|
500
|
+
if pdc.type in [
|
|
501
|
+
"identifier",
|
|
502
|
+
"type_identifier",
|
|
503
|
+
]:
|
|
504
|
+
typedef_name = pdc.text.decode("utf-8")
|
|
505
|
+
break
|
|
506
|
+
|
|
507
|
+
elif any(c.type == "struct_specifier" for c in children):
|
|
508
|
+
for i, child in enumerate(children):
|
|
509
|
+
if child.type == "struct_specifier":
|
|
510
|
+
for sc in child.children:
|
|
511
|
+
if sc.type == "type_identifier":
|
|
512
|
+
actual_type = "struct " + sc.text.decode("utf-8")
|
|
513
|
+
break
|
|
514
|
+
if not actual_type:
|
|
515
|
+
actual_type = child.text.decode("utf-8")
|
|
516
|
+
|
|
517
|
+
elif (
|
|
518
|
+
child.type in ["type_identifier", "primitive_type"]
|
|
519
|
+
and i > 0
|
|
520
|
+
):
|
|
521
|
+
typedef_name = child.text.decode("utf-8")
|
|
522
|
+
|
|
523
|
+
else:
|
|
524
|
+
if len(children) >= 2:
|
|
525
|
+
if children[0].type in [
|
|
526
|
+
"primitive_type",
|
|
527
|
+
"sized_type_specifier",
|
|
528
|
+
"type_identifier",
|
|
529
|
+
]:
|
|
530
|
+
actual_type = children[0].text.decode("utf-8")
|
|
531
|
+
|
|
532
|
+
if children[-1].type in ["type_identifier", "primitive_type"]:
|
|
533
|
+
typedef_name = children[-1].text.decode("utf-8")
|
|
534
|
+
|
|
535
|
+
if actual_type and pointer_count > 0:
|
|
536
|
+
actual_type += "*" * pointer_count
|
|
537
|
+
|
|
538
|
+
if typedef_name and actual_type:
|
|
539
|
+
self.typedef_map[typedef_name] = actual_type
|
|
540
|
+
|
|
541
|
+
for child in node.children:
|
|
542
|
+
traverse_for_typedefs(child)
|
|
543
|
+
|
|
544
|
+
traverse_for_typedefs(self.root_node)
|
|
545
|
+
|
|
546
|
+
def expand_typedef(self, type_name):
|
|
547
|
+
"""
|
|
548
|
+
Recursively expand a typedef to its actual type.
|
|
549
|
+
|
|
550
|
+
Args:
|
|
551
|
+
type_name: Type name (possibly a typedef)
|
|
552
|
+
|
|
553
|
+
Returns:
|
|
554
|
+
Expanded type string, or original if not a typedef
|
|
555
|
+
"""
|
|
556
|
+
if type_name.endswith("*"):
|
|
557
|
+
base = type_name.rstrip("*")
|
|
558
|
+
stars = "*" * type_name.count("*")
|
|
559
|
+
expanded = self.expand_typedef(base.strip())
|
|
560
|
+
return expanded + stars
|
|
561
|
+
|
|
562
|
+
if type_name in self.typedef_map:
|
|
563
|
+
return self.expand_typedef(self.typedef_map[type_name])
|
|
564
|
+
|
|
565
|
+
return type_name
|