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,1618 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import pprint
|
|
3
|
+
import time
|
|
4
|
+
import os
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
|
|
7
|
+
import networkx as nx
|
|
8
|
+
from deepdiff import DeepDiff
|
|
9
|
+
from loguru import logger
|
|
10
|
+
|
|
11
|
+
from ...utils.java_nodes import statement_types
|
|
12
|
+
from ...utils.src_parser import traverse_tree
|
|
13
|
+
|
|
14
|
+
assignment = ["assignment_expression"]
|
|
15
|
+
def_statement = ["variable_declarator"]
|
|
16
|
+
increment_statement = ["update_expression"]
|
|
17
|
+
variable_type = ["identifier", "this"]
|
|
18
|
+
method_calls = ["method_invocation"]
|
|
19
|
+
|
|
20
|
+
switch_type = ["switch_expression"]
|
|
21
|
+
inner_types = [
|
|
22
|
+
"declaration",
|
|
23
|
+
"expression_statement",
|
|
24
|
+
"local_variable_declaration",
|
|
25
|
+
]
|
|
26
|
+
method_invocation = method_calls + [
|
|
27
|
+
"object_creation_expression",
|
|
28
|
+
"explicit_constructor_invocation",
|
|
29
|
+
]
|
|
30
|
+
method_declaration = ["method_declaration", "constructor_declaration"]
|
|
31
|
+
handled_types = (
|
|
32
|
+
assignment
|
|
33
|
+
+ def_statement
|
|
34
|
+
+ increment_statement
|
|
35
|
+
+ method_calls
|
|
36
|
+
+ method_declaration
|
|
37
|
+
+ switch_type
|
|
38
|
+
+ [
|
|
39
|
+
"catch_clause",
|
|
40
|
+
"return_statement",
|
|
41
|
+
"throw_statement",
|
|
42
|
+
"enhanced_for_statement",
|
|
43
|
+
"for_statement",
|
|
44
|
+
"object_creation_expression",
|
|
45
|
+
"lambda_expression",
|
|
46
|
+
]
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
pp = pprint.PrettyPrinter(indent=4)
|
|
50
|
+
system_type = ("Console", "System", "String", "Collections")
|
|
51
|
+
# call_variable_map = {}
|
|
52
|
+
# node_list = {}
|
|
53
|
+
debug = False
|
|
54
|
+
# if any(
|
|
55
|
+
# # GITHUB_ACTIONS
|
|
56
|
+
# x in os.environ for x in ("PYCHARM_HOSTED",)
|
|
57
|
+
# ):
|
|
58
|
+
# debug = True
|
|
59
|
+
# properties = {
|
|
60
|
+
# "last_use": False,
|
|
61
|
+
# "last_def": False,
|
|
62
|
+
# "alex_algo": False
|
|
63
|
+
# }
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def scope_check(parent_scope, child_scope):
|
|
67
|
+
for p in parent_scope:
|
|
68
|
+
if p not in child_scope:
|
|
69
|
+
return False
|
|
70
|
+
return True
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class Identifier:
|
|
74
|
+
def __init__(
|
|
75
|
+
self,
|
|
76
|
+
parser,
|
|
77
|
+
node,
|
|
78
|
+
line=None,
|
|
79
|
+
declaration=False,
|
|
80
|
+
full_ref=None,
|
|
81
|
+
method_call=False,
|
|
82
|
+
):
|
|
83
|
+
self.core = st(node)
|
|
84
|
+
# field_declaration = return_first_parent_of_types(node, "field_declaration")
|
|
85
|
+
# param_declaration = return_first_parent_of_types(node, "formal_parameter")
|
|
86
|
+
# self.param_declaration = False
|
|
87
|
+
# if param_declaration is not None:
|
|
88
|
+
# self.param_declaration = True
|
|
89
|
+
# self.immutable_declaration = False
|
|
90
|
+
# if field_declaration is not None:
|
|
91
|
+
# self.immutable_declaration = True
|
|
92
|
+
class_node = return_first_parent_of_types(node, "class_declaration")
|
|
93
|
+
if full_ref is None:
|
|
94
|
+
full_ref = node
|
|
95
|
+
self.parent_class = class_node
|
|
96
|
+
self.unresolved_name = st(full_ref)
|
|
97
|
+
if self.unresolved_name.startswith("this."):
|
|
98
|
+
self.unresolved_name = st(full_ref)[5:]
|
|
99
|
+
if class_node is not None:
|
|
100
|
+
class_name = st(class_node.child_by_field_name("name"))
|
|
101
|
+
self.parent_class = class_name
|
|
102
|
+
if self.unresolved_name.startswith(class_name + "."):
|
|
103
|
+
self.unresolved_name = self.unresolved_name[len(class_name) + 1 :]
|
|
104
|
+
self.line = line
|
|
105
|
+
self.declaration = declaration
|
|
106
|
+
self.method_call = method_call
|
|
107
|
+
self.satisfied = method_call
|
|
108
|
+
if self.method_call and self.declaration:
|
|
109
|
+
method_resolution = self.unresolved_name.split(".")
|
|
110
|
+
# br.attribute2.attr.method1
|
|
111
|
+
# Option 1 - method call affects main object
|
|
112
|
+
# resolved_name = br
|
|
113
|
+
# resolved_name = method_resolution[0]
|
|
114
|
+
# resolved_name = br.attribute2.attr
|
|
115
|
+
# Option 2 - method call only affects subattribute
|
|
116
|
+
resolved_name = ".".join(method_resolution[:-1])
|
|
117
|
+
self.name = resolved_name
|
|
118
|
+
else:
|
|
119
|
+
self.name = self.unresolved_name
|
|
120
|
+
if not self.name:
|
|
121
|
+
self.name = self.unresolved_name
|
|
122
|
+
if node.type == "field_access":
|
|
123
|
+
node = recursively_get_children_of_types(
|
|
124
|
+
node,
|
|
125
|
+
["identifier"],
|
|
126
|
+
index=parser.index,
|
|
127
|
+
check_list=parser.symbol_table["scope_map"],
|
|
128
|
+
)[-1]
|
|
129
|
+
variable_index = get_index(node, parser.index)
|
|
130
|
+
self.variable_scope = parser.symbol_table["scope_map"][variable_index]
|
|
131
|
+
if variable_index in parser.declaration_map:
|
|
132
|
+
self.scope = parser.symbol_table["scope_map"][
|
|
133
|
+
parser.declaration_map[variable_index]
|
|
134
|
+
]
|
|
135
|
+
else:
|
|
136
|
+
# self.scope = variable_scope
|
|
137
|
+
# Declaration does not exist hence it is given
|
|
138
|
+
# the outermost scope
|
|
139
|
+
self.scope = [0]
|
|
140
|
+
if line is not None:
|
|
141
|
+
self.real_line_no = read_index(parser.index, line)[0][0]
|
|
142
|
+
|
|
143
|
+
def __eq__(self, other):
|
|
144
|
+
# if not isinstance(other, Identifier):
|
|
145
|
+
# return NotImplemented
|
|
146
|
+
# if self.name == other.name:
|
|
147
|
+
# if other.line is None and other.line is not None:
|
|
148
|
+
# other.line = self.line
|
|
149
|
+
# elif other.line is not None and self.line is None:
|
|
150
|
+
# self.line = other.line
|
|
151
|
+
|
|
152
|
+
# if self.method_call and self.declaration:
|
|
153
|
+
# method_resolution = self.name.split(".")
|
|
154
|
+
# # Option 1 - method call affects main object
|
|
155
|
+
# # resolved_name = method_resolution[0]
|
|
156
|
+
# # Option 2 - method call only affects subattribute
|
|
157
|
+
# resolved_name = ".".join(method_resolution[:-1])
|
|
158
|
+
# return resolved_name == other.name and self.line == other.line and sorted(self.scope) == sorted(
|
|
159
|
+
# other.scope)
|
|
160
|
+
# else:
|
|
161
|
+
return (
|
|
162
|
+
self.name == other.name
|
|
163
|
+
and self.line == other.line
|
|
164
|
+
and sorted(self.scope) == sorted(other.scope)
|
|
165
|
+
and self.method_call == other.method_call
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
def __hash__(self):
|
|
169
|
+
# if self.method_call and self.declaration:
|
|
170
|
+
# method_resolution = self.name.split(".")
|
|
171
|
+
# # Option 1 - method call affects main object
|
|
172
|
+
# resolved_name = method_resolution[0]
|
|
173
|
+
# # Option 2 - method call only affects subattribute
|
|
174
|
+
# # resolved_name = ".".join(method_resolution[:-1])
|
|
175
|
+
# return hash((resolved_name, self.line, str(self.scope), False))
|
|
176
|
+
# else:
|
|
177
|
+
return hash((self.name, self.line, str(self.scope), self.method_call))
|
|
178
|
+
|
|
179
|
+
def __str__(self):
|
|
180
|
+
result = [self.name]
|
|
181
|
+
if self.line:
|
|
182
|
+
result += [str(self.real_line_no)]
|
|
183
|
+
result += ["|".join(map(str, self.scope))]
|
|
184
|
+
else:
|
|
185
|
+
result += ["?"]
|
|
186
|
+
if self.method_call:
|
|
187
|
+
result += ["()"]
|
|
188
|
+
return f"{{{','.join(result)}}}"
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def st(child):
|
|
192
|
+
if child is None:
|
|
193
|
+
# logger.error
|
|
194
|
+
return ""
|
|
195
|
+
else:
|
|
196
|
+
return child.text.decode()
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def get_index(node, index):
|
|
200
|
+
try:
|
|
201
|
+
return index[(node.start_point, node.end_point, node.type)]
|
|
202
|
+
except:
|
|
203
|
+
return None
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def read_index(index, idx):
|
|
207
|
+
return list(index.keys())[list(index.values()).index(idx)]
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def parent_remapping_callback(node, remap=True):
|
|
211
|
+
if node is None:
|
|
212
|
+
return None
|
|
213
|
+
elif node.type == "do_statement":
|
|
214
|
+
if not remap:
|
|
215
|
+
return None
|
|
216
|
+
while_node = None
|
|
217
|
+
for child in node.children:
|
|
218
|
+
if child.type == "while":
|
|
219
|
+
while_node = child.next_named_sibling
|
|
220
|
+
break
|
|
221
|
+
return while_node
|
|
222
|
+
elif node.type == "try_statement":
|
|
223
|
+
return None
|
|
224
|
+
else:
|
|
225
|
+
return node
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def return_first_parent_of_types(node, parent_types, stop_types=None, remap=True):
|
|
229
|
+
if stop_types is None:
|
|
230
|
+
stop_types = []
|
|
231
|
+
if node.type in parent_types:
|
|
232
|
+
return parent_remapping_callback(node, remap=remap)
|
|
233
|
+
while node.parent is not None:
|
|
234
|
+
if node.type in stop_types:
|
|
235
|
+
return None
|
|
236
|
+
if node.parent.type in parent_types:
|
|
237
|
+
return parent_remapping_callback(node.parent, remap=remap)
|
|
238
|
+
node = node.parent
|
|
239
|
+
return None
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
#
|
|
243
|
+
# def set_add(lst, item):
|
|
244
|
+
# for entry in lst:
|
|
245
|
+
# if item == entry:
|
|
246
|
+
# return
|
|
247
|
+
# lst.append(item)
|
|
248
|
+
#
|
|
249
|
+
#
|
|
250
|
+
# def set_union(first_list, second_list):
|
|
251
|
+
# resulting_list = list(first_list)
|
|
252
|
+
# for x in second_list:
|
|
253
|
+
# set_add(resulting_list, x)
|
|
254
|
+
# return resulting_list
|
|
255
|
+
#
|
|
256
|
+
#
|
|
257
|
+
# def set_difference(first_list, second_list):
|
|
258
|
+
# resulting_list = []
|
|
259
|
+
# for item in first_list:
|
|
260
|
+
# match_found = False
|
|
261
|
+
# for item2 in second_list:
|
|
262
|
+
# if item == item2:
|
|
263
|
+
# match_found = True
|
|
264
|
+
# break
|
|
265
|
+
# if not match_found:
|
|
266
|
+
# resulting_list.append(item)
|
|
267
|
+
# return resulting_list
|
|
268
|
+
#
|
|
269
|
+
#
|
|
270
|
+
# def set_intersection(first_list, second_list):
|
|
271
|
+
# resulting_list = []
|
|
272
|
+
# for item in first_list:
|
|
273
|
+
# match_found = False
|
|
274
|
+
# for item2 in second_list:
|
|
275
|
+
# if item == item2:
|
|
276
|
+
# match_found = True
|
|
277
|
+
# break
|
|
278
|
+
# if match_found:
|
|
279
|
+
# resulting_list.append(item)
|
|
280
|
+
# return resulting_list
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def set_add(lst, item):
|
|
284
|
+
for entry in lst:
|
|
285
|
+
if item == entry:
|
|
286
|
+
return
|
|
287
|
+
lst.append(item)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def set_union(first_list, second_list):
|
|
291
|
+
resulting_list = list(first_list)
|
|
292
|
+
resulting_list.extend(x for x in second_list if x not in resulting_list)
|
|
293
|
+
return resulting_list
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def set_difference(first_list, second_list):
|
|
297
|
+
resulting_list = [item for item in first_list if item not in second_list]
|
|
298
|
+
return resulting_list
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def set_intersection(first_list, second_list):
|
|
302
|
+
resulting_list = [item for item in first_list if item in second_list]
|
|
303
|
+
return resulting_list
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def add_entry(
|
|
307
|
+
parser,
|
|
308
|
+
rda_table,
|
|
309
|
+
statement_id,
|
|
310
|
+
used=None,
|
|
311
|
+
defined=None,
|
|
312
|
+
declaration=False,
|
|
313
|
+
core=None,
|
|
314
|
+
method_call=False,
|
|
315
|
+
):
|
|
316
|
+
# global node_list
|
|
317
|
+
if statement_id not in rda_table:
|
|
318
|
+
rda_table[statement_id] = defaultdict(list)
|
|
319
|
+
if not used and not defined:
|
|
320
|
+
return
|
|
321
|
+
mapped_node = None
|
|
322
|
+
# meth_statement = return_first_parent_of_types(used or defined, ['method_declaration', 'constructor_declaration'])
|
|
323
|
+
# if meth_statement is not None:
|
|
324
|
+
# meth_statement_id = get_index(meth_statement, parser.index)
|
|
325
|
+
# if meth_statement_id in call_variable_map and meth_statement_id != statement_id:
|
|
326
|
+
# checker = st(core).split(".")[0] or st(defined).split(".")[0] or st(used).split(".")[0]
|
|
327
|
+
# if checker in call_variable_map[meth_statement_id]:
|
|
328
|
+
# mapped_node = call_variable_map[meth_statement_id][checker]
|
|
329
|
+
# # if mapped_node.parent.type == "field_access":
|
|
330
|
+
# # mapped_node = recursively_get_children_of_types(mapped_node, ['identifier'], index=parser.index,
|
|
331
|
+
# # check_list=parser.symbol_table["scope_map"])[-1]
|
|
332
|
+
if core is None:
|
|
333
|
+
current_node = used or defined
|
|
334
|
+
if current_node.type == "field_access":
|
|
335
|
+
current_node = recursively_get_children_of_types(
|
|
336
|
+
current_node,
|
|
337
|
+
["identifier"],
|
|
338
|
+
index=parser.index,
|
|
339
|
+
check_list=parser.symbol_table["scope_map"],
|
|
340
|
+
)[-1]
|
|
341
|
+
if defined is not None:
|
|
342
|
+
defined = current_node
|
|
343
|
+
else:
|
|
344
|
+
used = current_node
|
|
345
|
+
if (
|
|
346
|
+
current_node.parent is not None
|
|
347
|
+
and current_node.parent.type == "field_access"
|
|
348
|
+
):
|
|
349
|
+
# LOOK AT THE SYMBOL TABLE COMMENT AS WELL #? TODO
|
|
350
|
+
# object_node = current_node.parent.child_by_field_name("name")
|
|
351
|
+
# object_index = get_index(object_node, parser.index)
|
|
352
|
+
# current_index = get_index(current_node, parser.index)
|
|
353
|
+
# if object_index == current_index:
|
|
354
|
+
# all_calls.append(current_index)
|
|
355
|
+
|
|
356
|
+
while (
|
|
357
|
+
current_node.parent is not None
|
|
358
|
+
and current_node.parent.type == "field_access"
|
|
359
|
+
):
|
|
360
|
+
current_node = current_node.parent
|
|
361
|
+
|
|
362
|
+
if (
|
|
363
|
+
current_node.parent is not None
|
|
364
|
+
and current_node.parent.type == "method_invocation"
|
|
365
|
+
):
|
|
366
|
+
if not st(current_node).startswith(system_type):
|
|
367
|
+
add_entry(
|
|
368
|
+
parser,
|
|
369
|
+
rda_table,
|
|
370
|
+
statement_id,
|
|
371
|
+
defined=used or defined,
|
|
372
|
+
core=current_node.parent,
|
|
373
|
+
# declaration=True,
|
|
374
|
+
method_call=True,
|
|
375
|
+
)
|
|
376
|
+
add_entry(
|
|
377
|
+
parser,
|
|
378
|
+
rda_table,
|
|
379
|
+
statement_id,
|
|
380
|
+
used=used or defined,
|
|
381
|
+
core=current_node.parent,
|
|
382
|
+
# declaration=True,
|
|
383
|
+
method_call=True,
|
|
384
|
+
)
|
|
385
|
+
if mapped_node is not None:
|
|
386
|
+
set_add(
|
|
387
|
+
rda_table[statement_id]["def"],
|
|
388
|
+
Identifier(
|
|
389
|
+
parser,
|
|
390
|
+
mapped_node,
|
|
391
|
+
statement_id,
|
|
392
|
+
full_ref=mapped_node,
|
|
393
|
+
declaration=declaration,
|
|
394
|
+
method_call=method_call,
|
|
395
|
+
),
|
|
396
|
+
)
|
|
397
|
+
return
|
|
398
|
+
if defined is not None:
|
|
399
|
+
add_entry(
|
|
400
|
+
parser,
|
|
401
|
+
rda_table,
|
|
402
|
+
statement_id,
|
|
403
|
+
defined=defined,
|
|
404
|
+
core=current_node,
|
|
405
|
+
declaration=declaration,
|
|
406
|
+
method_call=method_call,
|
|
407
|
+
)
|
|
408
|
+
if mapped_node is not None:
|
|
409
|
+
set_add(
|
|
410
|
+
rda_table[statement_id]["def"],
|
|
411
|
+
Identifier(
|
|
412
|
+
parser,
|
|
413
|
+
mapped_node,
|
|
414
|
+
statement_id,
|
|
415
|
+
full_ref=mapped_node,
|
|
416
|
+
declaration=declaration,
|
|
417
|
+
method_call=method_call,
|
|
418
|
+
),
|
|
419
|
+
)
|
|
420
|
+
else:
|
|
421
|
+
add_entry(
|
|
422
|
+
parser,
|
|
423
|
+
rda_table,
|
|
424
|
+
statement_id,
|
|
425
|
+
used=used,
|
|
426
|
+
core=current_node,
|
|
427
|
+
declaration=declaration,
|
|
428
|
+
method_call=method_call,
|
|
429
|
+
)
|
|
430
|
+
return
|
|
431
|
+
elif (
|
|
432
|
+
current_node.next_sibling
|
|
433
|
+
and current_node.next_sibling.type == "."
|
|
434
|
+
and current_node.parent is not None
|
|
435
|
+
and current_node.parent.type == "method_invocation"
|
|
436
|
+
):
|
|
437
|
+
if not st(current_node).startswith(system_type):
|
|
438
|
+
if (used or defined).type == "identifier":
|
|
439
|
+
set_add(
|
|
440
|
+
rda_table[statement_id]["def"],
|
|
441
|
+
Identifier(
|
|
442
|
+
parser,
|
|
443
|
+
used or defined,
|
|
444
|
+
statement_id,
|
|
445
|
+
full_ref=None,
|
|
446
|
+
# declaration=True,
|
|
447
|
+
method_call=True,
|
|
448
|
+
),
|
|
449
|
+
)
|
|
450
|
+
if st(core).startswith(system_type):
|
|
451
|
+
return
|
|
452
|
+
if defined is not None:
|
|
453
|
+
if get_index(defined, parser.index) not in parser.symbol_table["scope_map"]:
|
|
454
|
+
return
|
|
455
|
+
set_add(
|
|
456
|
+
rda_table[statement_id]["def"],
|
|
457
|
+
Identifier(
|
|
458
|
+
parser,
|
|
459
|
+
defined,
|
|
460
|
+
statement_id,
|
|
461
|
+
full_ref=core,
|
|
462
|
+
declaration=declaration,
|
|
463
|
+
method_call=method_call,
|
|
464
|
+
),
|
|
465
|
+
)
|
|
466
|
+
if mapped_node is not None:
|
|
467
|
+
set_add(
|
|
468
|
+
rda_table[statement_id]["def"],
|
|
469
|
+
Identifier(
|
|
470
|
+
parser,
|
|
471
|
+
mapped_node,
|
|
472
|
+
statement_id,
|
|
473
|
+
full_ref=mapped_node,
|
|
474
|
+
declaration=declaration,
|
|
475
|
+
method_call=method_call,
|
|
476
|
+
),
|
|
477
|
+
)
|
|
478
|
+
else:
|
|
479
|
+
if get_index(used, parser.index) not in parser.symbol_table["scope_map"]:
|
|
480
|
+
return
|
|
481
|
+
if mapped_node is not None and method_call:
|
|
482
|
+
set_add(
|
|
483
|
+
rda_table[statement_id]["def"],
|
|
484
|
+
Identifier(
|
|
485
|
+
parser,
|
|
486
|
+
mapped_node,
|
|
487
|
+
statement_id,
|
|
488
|
+
full_ref=mapped_node,
|
|
489
|
+
declaration=declaration,
|
|
490
|
+
method_call=method_call,
|
|
491
|
+
),
|
|
492
|
+
)
|
|
493
|
+
set_add(
|
|
494
|
+
rda_table[statement_id]["use"],
|
|
495
|
+
Identifier(
|
|
496
|
+
parser,
|
|
497
|
+
used,
|
|
498
|
+
full_ref=core,
|
|
499
|
+
declaration=declaration,
|
|
500
|
+
method_call=method_call,
|
|
501
|
+
),
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
def check_field_name(req_child):
|
|
506
|
+
for i, child in enumerate(req_child.parent.children):
|
|
507
|
+
if req_child == child:
|
|
508
|
+
field_type = child.parent.field_name_for_child(i)
|
|
509
|
+
if field_type is not None and field_type == "type":
|
|
510
|
+
return False
|
|
511
|
+
return True
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def recursively_get_children_of_types(
|
|
515
|
+
node, st_types, check_list=None, index=None, result=None, stop_types=None
|
|
516
|
+
):
|
|
517
|
+
if isinstance(st_types, str):
|
|
518
|
+
st_types = [st_types]
|
|
519
|
+
if stop_types is None:
|
|
520
|
+
stop_types = []
|
|
521
|
+
if result is None:
|
|
522
|
+
result = []
|
|
523
|
+
if node.type in stop_types:
|
|
524
|
+
return result
|
|
525
|
+
if check_list and index:
|
|
526
|
+
result.extend(
|
|
527
|
+
list(
|
|
528
|
+
filter(
|
|
529
|
+
lambda child: child.type in st_types
|
|
530
|
+
and get_index(child, index) in check_list
|
|
531
|
+
and check_field_name(child),
|
|
532
|
+
# and child.parent.type in ['variable_declaration', 'object_creation_expression',
|
|
533
|
+
# 'field_access'],
|
|
534
|
+
node.children,
|
|
535
|
+
)
|
|
536
|
+
)
|
|
537
|
+
)
|
|
538
|
+
else:
|
|
539
|
+
result.extend(list(filter(lambda child: child.type in st_types, node.children)))
|
|
540
|
+
for child in node.named_children:
|
|
541
|
+
if child in stop_types:
|
|
542
|
+
continue
|
|
543
|
+
# if child.type not in st_types:
|
|
544
|
+
result = recursively_get_children_of_types(
|
|
545
|
+
child,
|
|
546
|
+
st_types,
|
|
547
|
+
result=result,
|
|
548
|
+
stop_types=stop_types,
|
|
549
|
+
index=index,
|
|
550
|
+
check_list=check_list,
|
|
551
|
+
)
|
|
552
|
+
return result
|
|
553
|
+
|
|
554
|
+
|
|
555
|
+
def compute_out(old_result, connected_derivers, def_set):
|
|
556
|
+
result = []
|
|
557
|
+
for node in connected_derivers:
|
|
558
|
+
result = set_union(result, old_result[node]["IN"])
|
|
559
|
+
# for node in result:
|
|
560
|
+
# if node in def_set:
|
|
561
|
+
# continue
|
|
562
|
+
return result
|
|
563
|
+
|
|
564
|
+
|
|
565
|
+
def compute_in(use_set, out_set, def_set, all_defs):
|
|
566
|
+
result = set_union(use_set, set_difference(out_set, def_set))
|
|
567
|
+
# for node in result:
|
|
568
|
+
# if node in all_defs:
|
|
569
|
+
# continue
|
|
570
|
+
return result
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
def print_table(index, new_result, iteration=0):
|
|
574
|
+
table = [f"\nRDA: iteration {iteration}\n"]
|
|
575
|
+
for key in new_result:
|
|
576
|
+
try:
|
|
577
|
+
table.append(str(read_index(index, key)[0][0] + 1) + "\n")
|
|
578
|
+
except:
|
|
579
|
+
table.append(str(key) + "\n")
|
|
580
|
+
for key2 in new_result[key]:
|
|
581
|
+
table.append(f"\t{key2}:")
|
|
582
|
+
for entry in new_result[key][key2]:
|
|
583
|
+
table.append(str(entry) + ",")
|
|
584
|
+
table.append("\n")
|
|
585
|
+
logger.debug("".join(table))
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def start_rda(index, rda_table, graph, pre_solve=False):
|
|
589
|
+
if debug and not pre_solve:
|
|
590
|
+
print_table(index, rda_table)
|
|
591
|
+
remove_set = []
|
|
592
|
+
# "method_return", "class_return"
|
|
593
|
+
if pre_solve:
|
|
594
|
+
remove_set = [
|
|
595
|
+
"method_call",
|
|
596
|
+
"method_return",
|
|
597
|
+
"class_return",
|
|
598
|
+
"constructor_call",
|
|
599
|
+
]
|
|
600
|
+
graph = copy.deepcopy(graph)
|
|
601
|
+
remove_edges = []
|
|
602
|
+
if remove_set:
|
|
603
|
+
for edge in graph.edges:
|
|
604
|
+
if (
|
|
605
|
+
"label" in graph.edges[edge]
|
|
606
|
+
and graph.edges[edge]["label"] in remove_set
|
|
607
|
+
):
|
|
608
|
+
remove_edges.append(edge)
|
|
609
|
+
graph.remove_edges_from(remove_edges)
|
|
610
|
+
|
|
611
|
+
cfg = graph
|
|
612
|
+
nodes = graph.nodes
|
|
613
|
+
old_result = {}
|
|
614
|
+
iteration = 0
|
|
615
|
+
for node in nodes:
|
|
616
|
+
old_result[node] = {"IN": set(), "OUT": set()}
|
|
617
|
+
# for node in nodes:
|
|
618
|
+
# connected_derivers = [t for (s, t) in cfg.out_edges(node)]
|
|
619
|
+
# old_result[node]["OUT"] = compute_out(old_result, connected_derivers, rda_table[node]["def"] if node in rda_table else [])
|
|
620
|
+
new_result = copy.deepcopy(old_result)
|
|
621
|
+
while True:
|
|
622
|
+
iteration = iteration + 1
|
|
623
|
+
iteration_returners = {}
|
|
624
|
+
for node in nodes:
|
|
625
|
+
connected_feeders = []
|
|
626
|
+
returning_feeders = []
|
|
627
|
+
for s, t in cfg.in_edges(node):
|
|
628
|
+
if "label" in cfg.edges[s, t, 0] and cfg.edges[s, t, 0]["label"] in [
|
|
629
|
+
"method_return",
|
|
630
|
+
"class_return",
|
|
631
|
+
]:
|
|
632
|
+
returning_feeders.append(s)
|
|
633
|
+
else:
|
|
634
|
+
connected_feeders.append(s)
|
|
635
|
+
feeder_union = set()
|
|
636
|
+
returner_union = set()
|
|
637
|
+
for feeder in connected_feeders:
|
|
638
|
+
feeder_union = feeder_union.union(old_result[feeder]["OUT"])
|
|
639
|
+
for returner in returning_feeders:
|
|
640
|
+
returner_union = returner_union.union(old_result[returner]["OUT"])
|
|
641
|
+
for s, t in cfg.out_edges(node):
|
|
642
|
+
if s != t:
|
|
643
|
+
iteration_returners[t] = (
|
|
644
|
+
iteration_returners[t].union(returner_union)
|
|
645
|
+
if t in iteration_returners
|
|
646
|
+
else returner_union
|
|
647
|
+
)
|
|
648
|
+
new_result[node]["IN"] = feeder_union
|
|
649
|
+
def_info = rda_table[node]["def"] if node in rda_table else set()
|
|
650
|
+
names_defined = [defined.name for defined in def_info]
|
|
651
|
+
# if defined.param_declaration is None
|
|
652
|
+
selective_difference = set()
|
|
653
|
+
for already_defined in feeder_union:
|
|
654
|
+
# if already_defined.immutable_declaration:
|
|
655
|
+
# selective_difference.add(already_defined)
|
|
656
|
+
if already_defined.name in names_defined:
|
|
657
|
+
continue
|
|
658
|
+
else:
|
|
659
|
+
selective_difference.add(already_defined)
|
|
660
|
+
new_result[node]["OUT"] = selective_difference.union(def_info)
|
|
661
|
+
for node in iteration_returners:
|
|
662
|
+
def_info = rda_table[node]["def"] if node in rda_table else set()
|
|
663
|
+
names_defined = [defined.name for defined in def_info]
|
|
664
|
+
selective_difference = set()
|
|
665
|
+
for already_defined in iteration_returners[node]:
|
|
666
|
+
# if already_defined.immutable_declaration:
|
|
667
|
+
# selective_difference.add(already_defined)
|
|
668
|
+
if already_defined.name in names_defined:
|
|
669
|
+
continue
|
|
670
|
+
else:
|
|
671
|
+
selective_difference.add(already_defined)
|
|
672
|
+
new_result[node]["OUT"] = new_result[node]["OUT"].union(
|
|
673
|
+
selective_difference
|
|
674
|
+
)
|
|
675
|
+
ddiff = DeepDiff(
|
|
676
|
+
old_result,
|
|
677
|
+
new_result,
|
|
678
|
+
ignore_order=True,
|
|
679
|
+
)
|
|
680
|
+
if ddiff == {}:
|
|
681
|
+
# for node in nodes:
|
|
682
|
+
# all_defs = []
|
|
683
|
+
# connected_feeders = [t for (s, t) in cfg.in_edges(node)]
|
|
684
|
+
# for feeder in connected_feeders:
|
|
685
|
+
# defs = rda_table[feeder]["def"] if feeder in rda_table else []
|
|
686
|
+
# all_defs += defs
|
|
687
|
+
# for outgoing in new_result[node]["IN"]:
|
|
688
|
+
# if outgoing in all_defs:
|
|
689
|
+
# continue
|
|
690
|
+
# connected_derivers = [t for (s, t) in cfg.out_edges(node)]
|
|
691
|
+
# for deriver in connected_derivers:
|
|
692
|
+
# for incoming in new_result[deriver]["IN"]:
|
|
693
|
+
# if incoming in rda_table[node]["def"]:
|
|
694
|
+
# continue
|
|
695
|
+
if debug and not pre_solve:
|
|
696
|
+
logger.info("RDA: Completed in iteration {}", iteration)
|
|
697
|
+
print_table(index, new_result, iteration)
|
|
698
|
+
break
|
|
699
|
+
old_result = copy.deepcopy(new_result)
|
|
700
|
+
return new_result
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
def add_edge(final_graph, a, b, attrib=None, pre_solve=False):
|
|
704
|
+
if (pre_solve and attrib) or not final_graph.has_edge(a, b):
|
|
705
|
+
final_graph.add_edge(a, b)
|
|
706
|
+
if attrib is not None:
|
|
707
|
+
nx.set_edge_attributes(final_graph, {(a, b, 0): attrib})
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
def get_required_edges_from_def_to_use(
|
|
711
|
+
index,
|
|
712
|
+
cfg,
|
|
713
|
+
rda_solution,
|
|
714
|
+
rda_table,
|
|
715
|
+
graph_nodes,
|
|
716
|
+
all_classes,
|
|
717
|
+
additional_edges=None,
|
|
718
|
+
processed_edges=None,
|
|
719
|
+
pre_solve=False,
|
|
720
|
+
properties=None,
|
|
721
|
+
):
|
|
722
|
+
if additional_edges is None:
|
|
723
|
+
additional_edges = []
|
|
724
|
+
if processed_edges is None:
|
|
725
|
+
processed_edges = []
|
|
726
|
+
final_graph = copy.deepcopy(cfg)
|
|
727
|
+
# twin_edges = [
|
|
728
|
+
# "constructor_call", "method_call"
|
|
729
|
+
# ]
|
|
730
|
+
# twins = []
|
|
731
|
+
# retain_edges = [
|
|
732
|
+
# "constructor_call", "class_return", "method_call", "method_return"
|
|
733
|
+
# ]
|
|
734
|
+
# retains = []
|
|
735
|
+
# additional_edges = []
|
|
736
|
+
# for edge in list(final_graph.edges()):
|
|
737
|
+
# edge_data = final_graph.get_edge_data(*edge)[0]
|
|
738
|
+
# if edge_data["label"] in retain_edges:
|
|
739
|
+
# retains.append(edge)
|
|
740
|
+
# # if edge_data["label"] in twin_edges:
|
|
741
|
+
# # twins.append(edge)
|
|
742
|
+
final_graph.remove_edges_from(list(final_graph.edges()))
|
|
743
|
+
for node in graph_nodes:
|
|
744
|
+
rda_info = rda_table[node] if node in rda_table else None
|
|
745
|
+
if rda_info is not None:
|
|
746
|
+
use_info = rda_info["use"]
|
|
747
|
+
# def_info = rda_info["def"]
|
|
748
|
+
else:
|
|
749
|
+
use_info = set()
|
|
750
|
+
# def_info = set()
|
|
751
|
+
# names_used = [used.name for used in use_info]
|
|
752
|
+
for used in use_info:
|
|
753
|
+
for available_def in rda_solution[node]["IN"]:
|
|
754
|
+
if available_def.name == used.name:
|
|
755
|
+
# if available_def not in rda_solution[node]["OUT"]:
|
|
756
|
+
# for line_def in rda_table[node]["def"]:
|
|
757
|
+
# if line_def.name == available_def.name:
|
|
758
|
+
# if line_def.declaration:
|
|
759
|
+
# available_def = line_def
|
|
760
|
+
# if available_def in rda_table[available_def.line]["def"]:
|
|
761
|
+
if scope_check(available_def.scope, used.scope):
|
|
762
|
+
# if available_def.declaration:
|
|
763
|
+
# if available_def.immutable_declaration:
|
|
764
|
+
# for other_def in rda_solution[node]["IN"]:
|
|
765
|
+
# if other_def.name == available_def.name and other_def.param_declaration:
|
|
766
|
+
# if not used.core.startswith("this"):
|
|
767
|
+
# available_def = other_def
|
|
768
|
+
# break
|
|
769
|
+
add_edge(
|
|
770
|
+
final_graph,
|
|
771
|
+
available_def.line,
|
|
772
|
+
node,
|
|
773
|
+
{"used_def": used.name},
|
|
774
|
+
pre_solve,
|
|
775
|
+
)
|
|
776
|
+
used.satisfied = True
|
|
777
|
+
# else:
|
|
778
|
+
# add_edge(final_graph, available_def.line, node, {'used_def': used.name}, pre_solve)
|
|
779
|
+
# used.satisfied = True
|
|
780
|
+
elif "." in used.name or "." in available_def.name:
|
|
781
|
+
if len(used.name.split(".")) < len(available_def.name.split(".")):
|
|
782
|
+
smaller = used
|
|
783
|
+
bigger = available_def
|
|
784
|
+
else:
|
|
785
|
+
smaller = available_def
|
|
786
|
+
bigger = used
|
|
787
|
+
if bigger.name.strip().startswith(smaller.name.strip()):
|
|
788
|
+
if (
|
|
789
|
+
not bigger.name.strip()
|
|
790
|
+
.replace(smaller.name.strip(), "")
|
|
791
|
+
.strip()
|
|
792
|
+
.startswith(".")
|
|
793
|
+
):
|
|
794
|
+
continue
|
|
795
|
+
|
|
796
|
+
# add_edge(final_graph, bigger.line or node, smaller.line or node)
|
|
797
|
+
add_edge(
|
|
798
|
+
final_graph,
|
|
799
|
+
available_def.line or node,
|
|
800
|
+
used.line or node,
|
|
801
|
+
{"used_def": used.name},
|
|
802
|
+
pre_solve,
|
|
803
|
+
)
|
|
804
|
+
used.satisfied = True
|
|
805
|
+
if not used.satisfied:
|
|
806
|
+
if used.core in all_classes:
|
|
807
|
+
static_derive_class = all_classes[used.core]
|
|
808
|
+
fields = recursively_get_children_of_types(
|
|
809
|
+
static_derive_class, "field_declaration"
|
|
810
|
+
)
|
|
811
|
+
for field in fields:
|
|
812
|
+
field_pieces = st(field).split()
|
|
813
|
+
if "static" in field_pieces:
|
|
814
|
+
if used.name.replace(used.core + ".", "") in field_pieces:
|
|
815
|
+
processed_edges.append((get_index(field, index), node))
|
|
816
|
+
else:
|
|
817
|
+
if not pre_solve and properties.get("last_use", False):
|
|
818
|
+
for i in rda_table:
|
|
819
|
+
for entry in rda_table[i]["use"]:
|
|
820
|
+
if entry.name == used.name and i != node:
|
|
821
|
+
# TODO: THIS IS AN AP - Make sure edges added here are right
|
|
822
|
+
if i in cfg and node in cfg:
|
|
823
|
+
# TODO: check missing i and handle it
|
|
824
|
+
if not nx.has_path(cfg, i, node):
|
|
825
|
+
continue
|
|
826
|
+
add_edge(
|
|
827
|
+
final_graph, i, node, {"color": "green"}
|
|
828
|
+
)
|
|
829
|
+
# used.satisfied = True
|
|
830
|
+
# break
|
|
831
|
+
# if used.satisfied:
|
|
832
|
+
# break
|
|
833
|
+
if properties.get("last_def", False):
|
|
834
|
+
for available_def in rda_solution[node]["IN"] - rda_solution[node]["OUT"]:
|
|
835
|
+
ignore_nodes = [
|
|
836
|
+
"for_statement",
|
|
837
|
+
"while_statement",
|
|
838
|
+
"if_statement",
|
|
839
|
+
"switch_statement",
|
|
840
|
+
]
|
|
841
|
+
if (
|
|
842
|
+
read_index(index, node)[-1] in ignore_nodes
|
|
843
|
+
or read_index(index, available_def.line)[-1] in ignore_nodes
|
|
844
|
+
):
|
|
845
|
+
continue
|
|
846
|
+
add_edge(final_graph, available_def.line, node, {"color": "orange"})
|
|
847
|
+
# for definition in def_info:
|
|
848
|
+
# for available_def in rda_solution[node]["IN"]:
|
|
849
|
+
# if "." in definition.name or "." in available_def.name:
|
|
850
|
+
# if len(definition.name.split(".")) < len(available_def.name.split(".")):
|
|
851
|
+
# smaller = definition
|
|
852
|
+
# bigger = available_def
|
|
853
|
+
# else:
|
|
854
|
+
# smaller = available_def
|
|
855
|
+
# bigger = definition
|
|
856
|
+
# if bigger.name.strip().startswith(smaller.name.strip()):
|
|
857
|
+
# if not bigger.name.strip().replace(smaller.name.strip(), "").strip().startswith("."):
|
|
858
|
+
# continue
|
|
859
|
+
# # add_edge(final_graph, bigger.line or node, smaller.line or node)
|
|
860
|
+
# add_edge(final_graph, smaller.line or node, bigger.line or node)
|
|
861
|
+
if not pre_solve:
|
|
862
|
+
for edge in additional_edges:
|
|
863
|
+
if debug:
|
|
864
|
+
add_edge(final_graph, *edge, {"color": "yellow"})
|
|
865
|
+
else:
|
|
866
|
+
add_edge(final_graph, *edge)
|
|
867
|
+
for edge in processed_edges:
|
|
868
|
+
add_edge(final_graph, *edge)
|
|
869
|
+
# for edge in twins:
|
|
870
|
+
# continue
|
|
871
|
+
# add_edge(final_graph, edge[0], edge[1])
|
|
872
|
+
# add_edge(final_graph, edge[1], edge[0])
|
|
873
|
+
return final_graph
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
def rda_cfg_map(rda_solution, CFG_results):
|
|
877
|
+
graph = CFG_results.graph
|
|
878
|
+
attrs = {}
|
|
879
|
+
for edge in list(graph.edges):
|
|
880
|
+
out_set = rda_solution[edge[0]]["OUT"]
|
|
881
|
+
in_set = rda_solution[edge[1]]["IN"]
|
|
882
|
+
intersection = set_intersection(out_set, in_set)
|
|
883
|
+
data = graph.get_edge_data(*edge)
|
|
884
|
+
if intersection:
|
|
885
|
+
data["label"] = ",".join([str(intr) for intr in intersection])
|
|
886
|
+
else:
|
|
887
|
+
graph.remove_edge(*edge)
|
|
888
|
+
# logger.warning("Unable to remap edge {}", edge)
|
|
889
|
+
attrs[edge] = data
|
|
890
|
+
nx.set_edge_attributes(graph, attrs)
|
|
891
|
+
return graph
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
def node_has_parent(nvalue, parent_class):
|
|
895
|
+
if nvalue == parent_class:
|
|
896
|
+
return True
|
|
897
|
+
while nvalue.parent:
|
|
898
|
+
if nvalue.parent == parent_class:
|
|
899
|
+
return True
|
|
900
|
+
else:
|
|
901
|
+
nvalue = nvalue.parent
|
|
902
|
+
return False
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
def call_variable(call_variable_map, node, edge_for, check_virtual=True):
|
|
906
|
+
for virtual_var, actual_var in call_variable_map[node]:
|
|
907
|
+
if check_virtual:
|
|
908
|
+
if st(virtual_var) == edge_for:
|
|
909
|
+
return actual_var
|
|
910
|
+
else:
|
|
911
|
+
if st(actual_var) == edge_for:
|
|
912
|
+
return virtual_var
|
|
913
|
+
return None
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
def dfg_java(prop, CFG_results):
|
|
917
|
+
# global properties
|
|
918
|
+
properties = prop
|
|
919
|
+
parser = CFG_results.parser
|
|
920
|
+
index = parser.index
|
|
921
|
+
tree = parser.tree
|
|
922
|
+
|
|
923
|
+
call_variable_map = {}
|
|
924
|
+
handled_cases = []
|
|
925
|
+
|
|
926
|
+
# if_statement = ["if_statement", "else"]
|
|
927
|
+
# for_statement = ["for_statement"]
|
|
928
|
+
# enhanced_for_statement = ["for_each_statement"]
|
|
929
|
+
# while_statement = ["while_statement"]
|
|
930
|
+
|
|
931
|
+
additional_edges = []
|
|
932
|
+
processed_edges = []
|
|
933
|
+
cfg_graph = copy.deepcopy(CFG_results.graph)
|
|
934
|
+
|
|
935
|
+
# Temperory edge adding logic when CFG is broken
|
|
936
|
+
# 41 -> 57
|
|
937
|
+
# 57 -> 27
|
|
938
|
+
# add_edge(cfg_graph, 41, 57, {'controlflow_type': 'method_return', 'edge_type': 'CFG_edge', 'label': 'method_return', 'color': 'blue'})
|
|
939
|
+
# add_edge(cfg_graph, 57, 27, {'controlflow_type': 'method_call', 'edge_type': 'CFG_edge', 'label': 'method_call', 'color': 'blue'})
|
|
940
|
+
|
|
941
|
+
# global node_list
|
|
942
|
+
node_list = CFG_results.node_list
|
|
943
|
+
|
|
944
|
+
all_classes = {
|
|
945
|
+
st(node_list[read_index(index, x)].child_by_field_name("name")): node_list[
|
|
946
|
+
read_index(index, x)
|
|
947
|
+
]
|
|
948
|
+
for x, y in cfg_graph.nodes(data=True)
|
|
949
|
+
if "type_label" in y and y["type_label"] == "class_declaration"
|
|
950
|
+
}
|
|
951
|
+
uninitiated_classes = [
|
|
952
|
+
x
|
|
953
|
+
for x, y in cfg_graph.nodes(data=True)
|
|
954
|
+
if "type_label" in y
|
|
955
|
+
and y["type_label"] == "class_declaration"
|
|
956
|
+
and cfg_graph.in_degree(x) == 0
|
|
957
|
+
]
|
|
958
|
+
|
|
959
|
+
start_rda_init_time = time.time()
|
|
960
|
+
for edge in list(cfg_graph.edges()):
|
|
961
|
+
edge_data = cfg_graph.get_edge_data(*edge)[0]
|
|
962
|
+
# If there is object creation
|
|
963
|
+
if edge_data["label"] == "class_return":
|
|
964
|
+
# call_statement = node_list[read_index(index, edge[1])]
|
|
965
|
+
# call_node = recursively_get_children_of_types(call_statement, method_invocation)[0]
|
|
966
|
+
last_statement = node_list[read_index(index, edge[0])]
|
|
967
|
+
class_node = return_first_parent_of_types(
|
|
968
|
+
last_statement, "class_declaration"
|
|
969
|
+
)
|
|
970
|
+
class_name = st(class_node.child_by_field_name("name"))
|
|
971
|
+
class_methods = recursively_get_children_of_types(
|
|
972
|
+
class_node, method_declaration
|
|
973
|
+
)
|
|
974
|
+
class_id = get_index(class_node, index)
|
|
975
|
+
# find all simple paths between class_id and edge[0]
|
|
976
|
+
all_paths = nx.all_simple_paths(cfg_graph, source=class_id, target=edge[0])
|
|
977
|
+
# only_path = nx.shortest_path(cfg_graph, source=class_id, target=edge[0])
|
|
978
|
+
unique_constructor_children = set()
|
|
979
|
+
for path in all_paths:
|
|
980
|
+
for node in path:
|
|
981
|
+
unique_constructor_children.add(node)
|
|
982
|
+
if len(unique_constructor_children) == 0:
|
|
983
|
+
unique_constructor_children.add(edge[0])
|
|
984
|
+
# unique_constructor_children = set(only_path)
|
|
985
|
+
# for nkey, nvalue in node_list.items():
|
|
986
|
+
# if node_has_parent(nvalue, class_node):
|
|
987
|
+
# unique_constructor_children.add(index[nkey])
|
|
988
|
+
for class_method in class_methods:
|
|
989
|
+
class_method_name = st(class_method.child_by_field_name("name"))
|
|
990
|
+
if class_method_name != class_name:
|
|
991
|
+
add_edge(cfg_graph, edge[0], get_index(class_method, index))
|
|
992
|
+
|
|
993
|
+
for n_id in unique_constructor_children:
|
|
994
|
+
additional_edges.append((n_id, edge[1]))
|
|
995
|
+
# Handle method_call edges and all constructor calls if there are parameters
|
|
996
|
+
elif edge_data["label"] in ["constructor_call", "method_call"]:
|
|
997
|
+
call_statement = node_list[read_index(index, edge[0])]
|
|
998
|
+
if call_statement.type in method_invocation:
|
|
999
|
+
call_node = call_statement
|
|
1000
|
+
else:
|
|
1001
|
+
marked_index = int(edge_data["controlflow_type"].rsplit("|", 1)[-1])
|
|
1002
|
+
call_nodes = recursively_get_children_of_types(
|
|
1003
|
+
call_statement, method_invocation
|
|
1004
|
+
)
|
|
1005
|
+
for call_node in call_nodes:
|
|
1006
|
+
if marked_index == get_index(call_node, index):
|
|
1007
|
+
break
|
|
1008
|
+
method = node_list[read_index(index, edge[1])]
|
|
1009
|
+
if method.type == "class_declaration":
|
|
1010
|
+
class_node = method
|
|
1011
|
+
constructors = recursively_get_children_of_types(
|
|
1012
|
+
class_node, "constructor_declaration"
|
|
1013
|
+
)
|
|
1014
|
+
if constructors:
|
|
1015
|
+
if "target_constructor" in edge_data:
|
|
1016
|
+
target_constructor = edge_data["target_constructor"]
|
|
1017
|
+
for constructor in constructors:
|
|
1018
|
+
if get_index(constructor, index) == target_constructor:
|
|
1019
|
+
method = constructor
|
|
1020
|
+
break
|
|
1021
|
+
else:
|
|
1022
|
+
continue
|
|
1023
|
+
# TODO if this else is hit its an AP
|
|
1024
|
+
# method = constructors[0]
|
|
1025
|
+
else:
|
|
1026
|
+
continue
|
|
1027
|
+
actual_variables = call_node.child_by_field_name("arguments").named_children
|
|
1028
|
+
virtual_variables = []
|
|
1029
|
+
for node in method.named_children:
|
|
1030
|
+
if "formal_parameter" in node.type:
|
|
1031
|
+
virtual_variables = recursively_get_children_of_types(
|
|
1032
|
+
node,
|
|
1033
|
+
variable_type,
|
|
1034
|
+
index=parser.index,
|
|
1035
|
+
stop_types=statement_types["statement_holders"],
|
|
1036
|
+
)
|
|
1037
|
+
if actual_variables:
|
|
1038
|
+
# TODO: Handle var_args Type... IterableObject
|
|
1039
|
+
var_args = False
|
|
1040
|
+
if var_args or len(actual_variables) == len(virtual_variables):
|
|
1041
|
+
for actual_var, virtual_var in zip(
|
|
1042
|
+
actual_variables, virtual_variables
|
|
1043
|
+
):
|
|
1044
|
+
method_statement_id = edge[1]
|
|
1045
|
+
if method_statement_id not in call_variable_map:
|
|
1046
|
+
call_variable_map[method_statement_id] = []
|
|
1047
|
+
call_variable_map[method_statement_id].append(
|
|
1048
|
+
(virtual_var, actual_var)
|
|
1049
|
+
)
|
|
1050
|
+
processed_edges.append(edge)
|
|
1051
|
+
else:
|
|
1052
|
+
logger.error("Number of actual and virtual variables do not match")
|
|
1053
|
+
if not var_args:
|
|
1054
|
+
pass
|
|
1055
|
+
# assert len(actual_variables) == len(virtual_variables)
|
|
1056
|
+
elif edge_data["label"] == "method_return":
|
|
1057
|
+
return_statement = node_list[read_index(index, edge[0])]
|
|
1058
|
+
if (
|
|
1059
|
+
return_statement.type == "return_statement"
|
|
1060
|
+
and return_statement.named_children
|
|
1061
|
+
):
|
|
1062
|
+
processed_edges.append(edge)
|
|
1063
|
+
elif edge_data["label"] == "lambda_invocation":
|
|
1064
|
+
processed_edges.append(edge)
|
|
1065
|
+
|
|
1066
|
+
for class_id in uninitiated_classes:
|
|
1067
|
+
class_node = node_list[read_index(index, class_id)]
|
|
1068
|
+
class_name = st(class_node.child_by_field_name("name"))
|
|
1069
|
+
class_methods = recursively_get_children_of_types(
|
|
1070
|
+
class_node, method_declaration
|
|
1071
|
+
)
|
|
1072
|
+
|
|
1073
|
+
descendants = [
|
|
1074
|
+
x
|
|
1075
|
+
for x in nx.descendants(cfg_graph, class_id)
|
|
1076
|
+
if cfg_graph.out_degree(x) == 0 and cfg_graph.in_degree(x) == 1
|
|
1077
|
+
]
|
|
1078
|
+
|
|
1079
|
+
for class_method in class_methods:
|
|
1080
|
+
class_method_name = st(class_method.child_by_field_name("name"))
|
|
1081
|
+
if class_method_name != class_name:
|
|
1082
|
+
for descendant in descendants:
|
|
1083
|
+
add_edge(cfg_graph, descendant, get_index(class_method, index))
|
|
1084
|
+
|
|
1085
|
+
rda_table = {}
|
|
1086
|
+
for root_node in traverse_tree(tree, variable_type):
|
|
1087
|
+
if not root_node.is_named:
|
|
1088
|
+
if root_node.type == "while" and root_node.parent.type == "do_statement":
|
|
1089
|
+
root_node = root_node.next_named_sibling
|
|
1090
|
+
parent_id = get_index(root_node, index)
|
|
1091
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1092
|
+
root_node,
|
|
1093
|
+
variable_type,
|
|
1094
|
+
index=parser.index,
|
|
1095
|
+
stop_types=statement_types["statement_holders"],
|
|
1096
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1097
|
+
)
|
|
1098
|
+
for identifier in identifiers_used:
|
|
1099
|
+
# if identifier.parent.type == "method_invocation":
|
|
1100
|
+
# continue
|
|
1101
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1102
|
+
else:
|
|
1103
|
+
continue
|
|
1104
|
+
if root_node.type == "catch_clause":
|
|
1105
|
+
parent_id = get_index(root_node, index)
|
|
1106
|
+
if len(root_node.named_children) > 1:
|
|
1107
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1108
|
+
root_node.named_children[-2],
|
|
1109
|
+
variable_type,
|
|
1110
|
+
index=parser.index,
|
|
1111
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1112
|
+
)
|
|
1113
|
+
add_entry(parser, rda_table, parent_id, defined=identifiers_used[-1])
|
|
1114
|
+
if root_node.type == "return_statement":
|
|
1115
|
+
parent_id = get_index(root_node, index)
|
|
1116
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1117
|
+
root_node,
|
|
1118
|
+
variable_type,
|
|
1119
|
+
index=parser.index,
|
|
1120
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1121
|
+
)
|
|
1122
|
+
for identifier in identifiers_used:
|
|
1123
|
+
if identifier.parent.type == "method_invocation":
|
|
1124
|
+
continue
|
|
1125
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1126
|
+
if root_node.type in def_statement:
|
|
1127
|
+
parent_statement = return_first_parent_of_types(
|
|
1128
|
+
root_node, statement_types["node_list_type"]
|
|
1129
|
+
)
|
|
1130
|
+
parent_id = get_index(parent_statement, index)
|
|
1131
|
+
if parent_statement is None:
|
|
1132
|
+
continue
|
|
1133
|
+
if parent_id not in CFG_results.graph.nodes:
|
|
1134
|
+
if parent_statement and parent_statement.type in inner_types:
|
|
1135
|
+
parent_statement = return_first_parent_of_types(
|
|
1136
|
+
parent_statement, statement_types["node_list_type"]
|
|
1137
|
+
)
|
|
1138
|
+
parent_id = get_index(parent_statement, index)
|
|
1139
|
+
elif parent_statement.type in handled_cases:
|
|
1140
|
+
continue
|
|
1141
|
+
else:
|
|
1142
|
+
raise NotImplementedError
|
|
1143
|
+
# print(parent_id)
|
|
1144
|
+
# print(st(parent_statement))
|
|
1145
|
+
if len(root_node.named_children) == 2:
|
|
1146
|
+
name = root_node.named_children[0]
|
|
1147
|
+
value = root_node.named_children[1]
|
|
1148
|
+
else:
|
|
1149
|
+
name = root_node.named_children[0]
|
|
1150
|
+
value = None
|
|
1151
|
+
add_entry(parser, rda_table, parent_id, defined=name, declaration=True)
|
|
1152
|
+
if value is not None:
|
|
1153
|
+
if value.type == "identifier":
|
|
1154
|
+
identifiers_used = [value]
|
|
1155
|
+
else:
|
|
1156
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1157
|
+
value,
|
|
1158
|
+
variable_type,
|
|
1159
|
+
index=parser.index,
|
|
1160
|
+
stop_types=statement_types["statement_holders"],
|
|
1161
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1162
|
+
)
|
|
1163
|
+
for identifier in identifiers_used:
|
|
1164
|
+
if identifier.parent.type == "method_invocation":
|
|
1165
|
+
continue
|
|
1166
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1167
|
+
elif root_node.type in assignment:
|
|
1168
|
+
parent_statement = return_first_parent_of_types(
|
|
1169
|
+
root_node, statement_types["node_list_type"]
|
|
1170
|
+
)
|
|
1171
|
+
parent_id = get_index(parent_statement, index)
|
|
1172
|
+
# print(parent_id)
|
|
1173
|
+
# print(st(parent_statement))
|
|
1174
|
+
left_nodes = root_node.child_by_field_name("left")
|
|
1175
|
+
right_node = root_node.child_by_field_name("right")
|
|
1176
|
+
operator_text = (
|
|
1177
|
+
root_node.text.split(left_nodes.text, 1)[-1]
|
|
1178
|
+
.rsplit(right_node.text, 1)[0]
|
|
1179
|
+
.strip()
|
|
1180
|
+
.decode()
|
|
1181
|
+
)
|
|
1182
|
+
right_nodes = [right_node]
|
|
1183
|
+
# JRef
|
|
1184
|
+
if parent_id not in CFG_results.graph.nodes:
|
|
1185
|
+
if parent_statement and parent_statement.type in inner_types:
|
|
1186
|
+
parent_statement = return_first_parent_of_types(
|
|
1187
|
+
parent_statement, statement_types["node_list_type"]
|
|
1188
|
+
)
|
|
1189
|
+
parent_id = get_index(parent_statement, index)
|
|
1190
|
+
elif parent_statement.type in handled_cases:
|
|
1191
|
+
continue
|
|
1192
|
+
else:
|
|
1193
|
+
raise NotImplementedError
|
|
1194
|
+
# operator = root_node.child()
|
|
1195
|
+
# operator_text = operator.text.decode('utf-8')
|
|
1196
|
+
if operator_text != "=":
|
|
1197
|
+
right_nodes.append(left_nodes)
|
|
1198
|
+
# TODO triage
|
|
1199
|
+
add_entry(parser, rda_table, parent_id, defined=left_nodes)
|
|
1200
|
+
for node in right_nodes:
|
|
1201
|
+
if node.type in variable_type:
|
|
1202
|
+
add_entry(parser, rda_table, parent_id, used=node)
|
|
1203
|
+
else:
|
|
1204
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1205
|
+
node,
|
|
1206
|
+
variable_type,
|
|
1207
|
+
index=parser.index,
|
|
1208
|
+
stop_types=statement_types["statement_holders"],
|
|
1209
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1210
|
+
)
|
|
1211
|
+
for identifier in identifiers_used:
|
|
1212
|
+
if identifier.parent.type == "method_invocation":
|
|
1213
|
+
continue
|
|
1214
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1215
|
+
elif root_node.type in increment_statement:
|
|
1216
|
+
parent_statement = return_first_parent_of_types(
|
|
1217
|
+
root_node, statement_types["node_list_type"]
|
|
1218
|
+
)
|
|
1219
|
+
parent_id = get_index(parent_statement, index)
|
|
1220
|
+
if parent_id not in CFG_results.graph.nodes:
|
|
1221
|
+
if parent_statement and parent_statement.type in inner_types:
|
|
1222
|
+
parent_statement = return_first_parent_of_types(
|
|
1223
|
+
parent_statement, statement_types["node_list_type"]
|
|
1224
|
+
)
|
|
1225
|
+
parent_id = get_index(parent_statement, index)
|
|
1226
|
+
elif parent_statement.type in handled_cases:
|
|
1227
|
+
continue
|
|
1228
|
+
else:
|
|
1229
|
+
raise NotImplementedError
|
|
1230
|
+
# print(parent_id)
|
|
1231
|
+
# print(st(parent_statement))
|
|
1232
|
+
if root_node.type in variable_type:
|
|
1233
|
+
add_entry(parser, rda_table, parent_id, used=root_node)
|
|
1234
|
+
else:
|
|
1235
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1236
|
+
root_node,
|
|
1237
|
+
variable_type,
|
|
1238
|
+
index=parser.index,
|
|
1239
|
+
stop_types=statement_types["statement_holders"],
|
|
1240
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1241
|
+
)
|
|
1242
|
+
for identifier in identifiers_used:
|
|
1243
|
+
if identifier.parent.type == "method_invocation":
|
|
1244
|
+
continue
|
|
1245
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1246
|
+
add_entry(parser, rda_table, parent_id, defined=identifier)
|
|
1247
|
+
elif root_node.type in method_calls:
|
|
1248
|
+
parent_statement = return_first_parent_of_types(
|
|
1249
|
+
root_node, statement_types["node_list_type"]
|
|
1250
|
+
)
|
|
1251
|
+
parent_id = get_index(parent_statement, index)
|
|
1252
|
+
if parent_id not in CFG_results.graph.nodes:
|
|
1253
|
+
if parent_statement is None:
|
|
1254
|
+
continue
|
|
1255
|
+
if parent_statement and parent_statement.type in inner_types:
|
|
1256
|
+
parent_statement = return_first_parent_of_types(
|
|
1257
|
+
parent_statement, statement_types["node_list_type"]
|
|
1258
|
+
)
|
|
1259
|
+
parent_id = get_index(parent_statement, index)
|
|
1260
|
+
elif parent_statement.type in handled_cases:
|
|
1261
|
+
continue
|
|
1262
|
+
else:
|
|
1263
|
+
raise NotImplementedError
|
|
1264
|
+
add_entry(
|
|
1265
|
+
parser,
|
|
1266
|
+
rda_table,
|
|
1267
|
+
parent_id,
|
|
1268
|
+
used=root_node.children[0],
|
|
1269
|
+
method_call=True,
|
|
1270
|
+
)
|
|
1271
|
+
for node in root_node.children[1:]:
|
|
1272
|
+
if node.type in variable_type:
|
|
1273
|
+
if return_first_parent_of_types(node, "method_invocation") is None:
|
|
1274
|
+
add_entry(parser, rda_table, parent_id, used=node)
|
|
1275
|
+
else:
|
|
1276
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1277
|
+
node,
|
|
1278
|
+
variable_type,
|
|
1279
|
+
index=parser.index,
|
|
1280
|
+
stop_types=statement_types["statement_holders"],
|
|
1281
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1282
|
+
)
|
|
1283
|
+
for identifier in identifiers_used:
|
|
1284
|
+
if identifier.parent.type == "method_invocation":
|
|
1285
|
+
continue
|
|
1286
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1287
|
+
elif root_node.type in method_declaration:
|
|
1288
|
+
parent_id = get_index(root_node, index)
|
|
1289
|
+
for child in root_node.named_children:
|
|
1290
|
+
# if root_node.type == "constructor_declaration":
|
|
1291
|
+
# if child.type == "identifier":
|
|
1292
|
+
|
|
1293
|
+
if child.type == "formal_parameters":
|
|
1294
|
+
for parameter in child.named_children:
|
|
1295
|
+
if parameter.type == "formal_parameter":
|
|
1296
|
+
identifier = parameter.child_by_field_name("name")
|
|
1297
|
+
add_entry(parser, rda_table, parent_id, defined=identifier)
|
|
1298
|
+
break
|
|
1299
|
+
elif root_node.type in switch_type:
|
|
1300
|
+
parent_statement = root_node
|
|
1301
|
+
parent_id = get_index(root_node, index)
|
|
1302
|
+
if parent_id not in CFG_results.graph.nodes:
|
|
1303
|
+
if parent_statement and parent_statement.type in inner_types:
|
|
1304
|
+
parent_statement = return_first_parent_of_types(
|
|
1305
|
+
parent_statement, statement_types["node_list_type"]
|
|
1306
|
+
)
|
|
1307
|
+
parent_id = get_index(parent_statement, index)
|
|
1308
|
+
elif parent_statement.type in handled_cases:
|
|
1309
|
+
continue
|
|
1310
|
+
else:
|
|
1311
|
+
raise NotImplementedError
|
|
1312
|
+
if parent_statement.type == "switch_expression":
|
|
1313
|
+
add_entry(parser, rda_table, parent_id, used=root_node.children[0])
|
|
1314
|
+
elif parent_statement.type == "switch_statement":
|
|
1315
|
+
case_node = parent_statement.child_by_field_name("value")
|
|
1316
|
+
add_entry(parser, rda_table, parent_id, used=case_node)
|
|
1317
|
+
elif root_node.type == "throw_statement":
|
|
1318
|
+
parent_statement = root_node
|
|
1319
|
+
parent_id = get_index(root_node, index)
|
|
1320
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1321
|
+
parent_statement,
|
|
1322
|
+
variable_type,
|
|
1323
|
+
index=parser.index,
|
|
1324
|
+
stop_types=statement_types["statement_holders"],
|
|
1325
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1326
|
+
)
|
|
1327
|
+
for identifier in identifiers_used:
|
|
1328
|
+
if identifier.parent.type == "method_invocation":
|
|
1329
|
+
continue
|
|
1330
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1331
|
+
elif root_node.type == "enhanced_for_statement":
|
|
1332
|
+
parent_statement = root_node
|
|
1333
|
+
parent_id = get_index(root_node, index)
|
|
1334
|
+
for i, child in enumerate(parent_statement.children):
|
|
1335
|
+
if child.parent.field_name_for_child(i) == "dimensions":
|
|
1336
|
+
defined_node = child
|
|
1337
|
+
add_entry(
|
|
1338
|
+
parser,
|
|
1339
|
+
rda_table,
|
|
1340
|
+
parent_id,
|
|
1341
|
+
defined=defined_node,
|
|
1342
|
+
declaration=True,
|
|
1343
|
+
)
|
|
1344
|
+
elif child.parent.field_name_for_child(i) == "value":
|
|
1345
|
+
used_node = child
|
|
1346
|
+
add_entry(parser, rda_table, parent_id, used=used_node)
|
|
1347
|
+
elif root_node.type == "for_statement":
|
|
1348
|
+
parent_statement = root_node
|
|
1349
|
+
parent_id = get_index(root_node, index)
|
|
1350
|
+
for i, child in enumerate(parent_statement.children):
|
|
1351
|
+
if child.parent.field_name_for_child(i) == "dimensions":
|
|
1352
|
+
defined_node = child
|
|
1353
|
+
add_entry(
|
|
1354
|
+
parser,
|
|
1355
|
+
rda_table,
|
|
1356
|
+
parent_id,
|
|
1357
|
+
defined=defined_node,
|
|
1358
|
+
declaration=True,
|
|
1359
|
+
)
|
|
1360
|
+
elif child.parent.field_name_for_child(i) == "value":
|
|
1361
|
+
used_node = child
|
|
1362
|
+
add_entry(parser, rda_table, parent_id, used=used_node)
|
|
1363
|
+
elif root_node.type == "object_creation_expression":
|
|
1364
|
+
parent_statement = return_first_parent_of_types(
|
|
1365
|
+
root_node, statement_types["node_list_type"]
|
|
1366
|
+
)
|
|
1367
|
+
parent_id = get_index(parent_statement, index)
|
|
1368
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1369
|
+
root_node,
|
|
1370
|
+
variable_type,
|
|
1371
|
+
index=parser.index,
|
|
1372
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1373
|
+
)
|
|
1374
|
+
for identifier in identifiers_used:
|
|
1375
|
+
if identifier.parent.type == "method_invocation":
|
|
1376
|
+
continue
|
|
1377
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1378
|
+
elif root_node.type == "lambda_expression":
|
|
1379
|
+
parent_statement = root_node
|
|
1380
|
+
parent_id = get_index(root_node, index)
|
|
1381
|
+
defined_nodes = parent_statement.child_by_field_name("parameters")
|
|
1382
|
+
if defined_nodes:
|
|
1383
|
+
for defined_node in defined_nodes.named_children:
|
|
1384
|
+
add_entry(
|
|
1385
|
+
parser,
|
|
1386
|
+
rda_table,
|
|
1387
|
+
parent_id,
|
|
1388
|
+
defined=defined_node,
|
|
1389
|
+
declaration=True,
|
|
1390
|
+
)
|
|
1391
|
+
else:
|
|
1392
|
+
# THIS ELSE IS VERY INEFFICIENT
|
|
1393
|
+
# Essentially considers all variable references as use
|
|
1394
|
+
# if return_first_parent_of_types(root_node, handled_types) is None:
|
|
1395
|
+
parent_statement = return_first_parent_of_types(
|
|
1396
|
+
root_node,
|
|
1397
|
+
# statement_types["node_list_type"],
|
|
1398
|
+
# [x for x in statement_types["node_list_type"] if x not in block_types],
|
|
1399
|
+
statement_types["non_control_statement"]
|
|
1400
|
+
+ statement_types["control_statement"],
|
|
1401
|
+
stop_types=statement_types["statement_holders"] + handled_types,
|
|
1402
|
+
remap=False,
|
|
1403
|
+
)
|
|
1404
|
+
parent_id = get_index(parent_statement, index)
|
|
1405
|
+
if parent_id is None:
|
|
1406
|
+
continue
|
|
1407
|
+
if parent_id not in CFG_results.graph.nodes:
|
|
1408
|
+
if parent_statement and parent_statement.type in inner_types:
|
|
1409
|
+
parent_statement = return_first_parent_of_types(
|
|
1410
|
+
parent_statement, statement_types["node_list_type"]
|
|
1411
|
+
)
|
|
1412
|
+
parent_id = get_index(parent_statement, index)
|
|
1413
|
+
elif parent_statement.type in handled_cases:
|
|
1414
|
+
continue
|
|
1415
|
+
else:
|
|
1416
|
+
raise NotImplementedError
|
|
1417
|
+
# print(root_node.type)
|
|
1418
|
+
# print(parent_statement.type)
|
|
1419
|
+
|
|
1420
|
+
# print("...")
|
|
1421
|
+
|
|
1422
|
+
# print(parent_id)
|
|
1423
|
+
# print(st(parent_statement))
|
|
1424
|
+
|
|
1425
|
+
# if parent_statement and parent_statement.type in block_types:
|
|
1426
|
+
# continue
|
|
1427
|
+
|
|
1428
|
+
# if root_node.type in variable_type:
|
|
1429
|
+
# add_entry(parser, rda_table, parent_id, used=root_node)
|
|
1430
|
+
# else:
|
|
1431
|
+
identifiers_used = recursively_get_children_of_types(
|
|
1432
|
+
root_node,
|
|
1433
|
+
variable_type,
|
|
1434
|
+
stop_types=statement_types["statement_holders"] + handled_types,
|
|
1435
|
+
index=parser.index,
|
|
1436
|
+
check_list=parser.symbol_table["scope_map"],
|
|
1437
|
+
)
|
|
1438
|
+
for identifier in identifiers_used:
|
|
1439
|
+
if identifier.parent.type == "method_invocation":
|
|
1440
|
+
continue
|
|
1441
|
+
add_entry(parser, rda_table, parent_id, used=identifier)
|
|
1442
|
+
end_rda_init_time = time.time()
|
|
1443
|
+
end_rda_presolve_time = 0
|
|
1444
|
+
start_rda_presolve_time = 0
|
|
1445
|
+
end_alias_analysis_time = 0
|
|
1446
|
+
start_alias_analysis_time = 0
|
|
1447
|
+
if properties.get("alex_algo", True):
|
|
1448
|
+
start_rda_presolve_time = time.time()
|
|
1449
|
+
rda_solution = start_rda(index, rda_table, cfg_graph, pre_solve=True)
|
|
1450
|
+
# pp.pprint(rda_solution)
|
|
1451
|
+
final_graph = get_required_edges_from_def_to_use(
|
|
1452
|
+
index,
|
|
1453
|
+
cfg_graph,
|
|
1454
|
+
rda_solution,
|
|
1455
|
+
rda_table,
|
|
1456
|
+
cfg_graph.nodes,
|
|
1457
|
+
all_classes,
|
|
1458
|
+
additional_edges,
|
|
1459
|
+
processed_edges,
|
|
1460
|
+
pre_solve=True,
|
|
1461
|
+
properties=properties,
|
|
1462
|
+
)
|
|
1463
|
+
used_classes_or_methods = set()
|
|
1464
|
+
for edge in cfg_graph.edges:
|
|
1465
|
+
if "label" in cfg_graph.edges[edge] and cfg_graph.edges[edge]["label"] in [
|
|
1466
|
+
"method_call",
|
|
1467
|
+
"constructor_call",
|
|
1468
|
+
]:
|
|
1469
|
+
final_graph.nodes[edge[0]][cfg_graph.edges[edge]["label"]] = edge[1]
|
|
1470
|
+
used_classes_or_methods.add(edge[1])
|
|
1471
|
+
end_rda_presolve_time = time.time()
|
|
1472
|
+
start_alias_analysis_time = time.time()
|
|
1473
|
+
al_analysis = set()
|
|
1474
|
+
proc_analysis = set()
|
|
1475
|
+
|
|
1476
|
+
for node in final_graph.nodes:
|
|
1477
|
+
if node not in used_classes_or_methods:
|
|
1478
|
+
continue
|
|
1479
|
+
if final_graph.nodes[node]["type_label"] == "method_declaration":
|
|
1480
|
+
if "main" in final_graph.nodes[node]["label"]:
|
|
1481
|
+
continue
|
|
1482
|
+
handled_node_leaf_pair = set()
|
|
1483
|
+
for leaf in nx.algorithms.dag.descendants(final_graph, node):
|
|
1484
|
+
if len([x for x in final_graph.edges(leaf) if x[0] != x[1]]) == 0:
|
|
1485
|
+
# print("Leaf: ", leaf)
|
|
1486
|
+
# final_graph.add_edge(leaf, "exit")
|
|
1487
|
+
# used_names = [n.name for n in rda_table[leaf]['def']]
|
|
1488
|
+
# if len(used_names) != 1:
|
|
1489
|
+
# logger.error("Multiple used names: %s", used_names)
|
|
1490
|
+
# get shortest path from node to leaf
|
|
1491
|
+
paths = nx.all_simple_paths(final_graph, node, leaf)
|
|
1492
|
+
# print("All_Simple: ", node, leaf)
|
|
1493
|
+
for path in paths:
|
|
1494
|
+
# get first edge in path
|
|
1495
|
+
first_edge = (path[0], path[1], 0)
|
|
1496
|
+
# get last edge in path
|
|
1497
|
+
last_edge = (path[-2], path[-1], 0)
|
|
1498
|
+
# get data for edge
|
|
1499
|
+
edge_for = final_graph.edges[first_edge]["used_def"]
|
|
1500
|
+
# get data for last edge
|
|
1501
|
+
edge_for_last = final_graph.edges[last_edge]["used_def"]
|
|
1502
|
+
defined_cores = [d.core for d in rda_table[leaf]["def"]]
|
|
1503
|
+
call_node = None
|
|
1504
|
+
# print("java:" + edge_for_last)
|
|
1505
|
+
if edge_for_last not in defined_cores:
|
|
1506
|
+
# "method_return", "class_return"
|
|
1507
|
+
if any(
|
|
1508
|
+
[
|
|
1509
|
+
x in final_graph.nodes[leaf]
|
|
1510
|
+
for x in ["method_call", "constructor_call"]
|
|
1511
|
+
]
|
|
1512
|
+
):
|
|
1513
|
+
if "method_call" in final_graph.nodes[leaf]:
|
|
1514
|
+
call_node = final_graph.nodes[leaf][
|
|
1515
|
+
"method_call"
|
|
1516
|
+
]
|
|
1517
|
+
elif "constructor_call" in final_graph.nodes[leaf]:
|
|
1518
|
+
call_node = final_graph.nodes[leaf][
|
|
1519
|
+
"constructor_call"
|
|
1520
|
+
]
|
|
1521
|
+
node_leaf_key = str(leaf) + "_" + str(edge_for)
|
|
1522
|
+
if node_leaf_key in handled_node_leaf_pair:
|
|
1523
|
+
continue
|
|
1524
|
+
handled_node_leaf_pair.add(node_leaf_key)
|
|
1525
|
+
if node in call_variable_map:
|
|
1526
|
+
if call_node:
|
|
1527
|
+
proc_analysis.add((node, leaf, edge_for, call_node))
|
|
1528
|
+
# al_analysis.append((node, leaf, edge_for, call_node))
|
|
1529
|
+
if edge_for_last not in defined_cores:
|
|
1530
|
+
n = -1
|
|
1531
|
+
while edge_for_last not in defined_cores:
|
|
1532
|
+
n = n - 1
|
|
1533
|
+
if abs(n - 1) > len(path):
|
|
1534
|
+
break
|
|
1535
|
+
last_edge = (path[n - 1], path[n], 0)
|
|
1536
|
+
edge_for_last = final_graph.edges[last_edge][
|
|
1537
|
+
"used_def"
|
|
1538
|
+
]
|
|
1539
|
+
defined_cores = [
|
|
1540
|
+
d.core for d in rda_table[path[n]]["def"]
|
|
1541
|
+
]
|
|
1542
|
+
if edge_for_last in defined_cores:
|
|
1543
|
+
al_analysis.add(
|
|
1544
|
+
(node, path[n], edge_for, None)
|
|
1545
|
+
)
|
|
1546
|
+
else:
|
|
1547
|
+
al_analysis.add((node, leaf, edge_for, call_node))
|
|
1548
|
+
|
|
1549
|
+
while proc_analysis:
|
|
1550
|
+
temp_proc_analysis = set()
|
|
1551
|
+
for node, leaf, edge_for, call_node in proc_analysis:
|
|
1552
|
+
completed_analysis = set()
|
|
1553
|
+
for al_entry in al_analysis:
|
|
1554
|
+
if al_entry[0] == call_node:
|
|
1555
|
+
mapped_node = call_variable(
|
|
1556
|
+
call_variable_map, call_node, edge_for, check_virtual=False
|
|
1557
|
+
)
|
|
1558
|
+
if al_entry[2] != st(mapped_node):
|
|
1559
|
+
continue
|
|
1560
|
+
leaf = al_entry[1]
|
|
1561
|
+
completed_analysis.add((node, leaf, edge_for, al_entry[3]))
|
|
1562
|
+
if al_entry[3] is not None:
|
|
1563
|
+
temp_proc_analysis.add((node, leaf, edge_for, al_entry[3]))
|
|
1564
|
+
al_analysis.update(completed_analysis)
|
|
1565
|
+
proc_analysis = temp_proc_analysis
|
|
1566
|
+
|
|
1567
|
+
for node, leaf, edge_for, call_node in al_analysis:
|
|
1568
|
+
mapped_node = call_variable(call_variable_map, node, edge_for)
|
|
1569
|
+
# print(st(mapped_node))
|
|
1570
|
+
if mapped_node:
|
|
1571
|
+
if mapped_node.type == "method_invocation":
|
|
1572
|
+
# if a reference is passed back it is ignored in alias analysis
|
|
1573
|
+
# to handle turn this into a while loop and trace the return chain
|
|
1574
|
+
# track_leaf = leaf
|
|
1575
|
+
# leaf_node = node_list[read_index(index, track_leaf)]
|
|
1576
|
+
# if leaf_node.type == "return_statement":
|
|
1577
|
+
# print("skipped")
|
|
1578
|
+
continue
|
|
1579
|
+
# [(st(a),st(b)) for a,b in call_variable_map[100]]
|
|
1580
|
+
# print(edge_for, final_graph.nodes[leaf]["label"])
|
|
1581
|
+
set_add(
|
|
1582
|
+
rda_table[leaf]["def"],
|
|
1583
|
+
Identifier(
|
|
1584
|
+
parser,
|
|
1585
|
+
mapped_node,
|
|
1586
|
+
leaf,
|
|
1587
|
+
full_ref=mapped_node,
|
|
1588
|
+
declaration=True,
|
|
1589
|
+
method_call=True,
|
|
1590
|
+
),
|
|
1591
|
+
)
|
|
1592
|
+
end_alias_analysis_time = time.time()
|
|
1593
|
+
# print_table(index, rda_table)
|
|
1594
|
+
start_rda_time = time.time()
|
|
1595
|
+
rda_solution = start_rda(index, rda_table, cfg_graph)
|
|
1596
|
+
final_graph = get_required_edges_from_def_to_use(
|
|
1597
|
+
index,
|
|
1598
|
+
cfg_graph,
|
|
1599
|
+
rda_solution,
|
|
1600
|
+
rda_table,
|
|
1601
|
+
cfg_graph.nodes,
|
|
1602
|
+
all_classes,
|
|
1603
|
+
additional_edges,
|
|
1604
|
+
processed_edges,
|
|
1605
|
+
pre_solve=False,
|
|
1606
|
+
properties=properties,
|
|
1607
|
+
)
|
|
1608
|
+
end_rda_time = time.time()
|
|
1609
|
+
if debug:
|
|
1610
|
+
logger.warning(
|
|
1611
|
+
"RDA init, presolve, alias, rda: {}, {}, {}, {}",
|
|
1612
|
+
end_rda_init_time - start_rda_init_time,
|
|
1613
|
+
end_rda_presolve_time - start_rda_presolve_time,
|
|
1614
|
+
end_alias_analysis_time - start_alias_analysis_time,
|
|
1615
|
+
end_rda_time - start_rda_time,
|
|
1616
|
+
)
|
|
1617
|
+
debug_graph = rda_cfg_map(rda_solution, CFG_results)
|
|
1618
|
+
return final_graph, debug_graph, rda_table, rda_solution
|