forked from DonJayamanne/pythonVSCode
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsoa.py
More file actions
139 lines (117 loc) · 5.5 KB
/
soa.py
File metadata and controls
139 lines (117 loc) · 5.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import rope.base.ast
import rope.base.oi.soi
import rope.base.pynames
from rope.base import pyobjects, evaluate, astutils, arguments
def analyze_module(pycore, pymodule, should_analyze,
search_subscopes, followed_calls):
"""Analyze `pymodule` for static object inference
Analyzes scopes for collecting object information. The analysis
starts from inner scopes.
"""
_analyze_node(pycore, pymodule, should_analyze,
search_subscopes, followed_calls)
def _analyze_node(pycore, pydefined, should_analyze,
search_subscopes, followed_calls):
if search_subscopes(pydefined):
for scope in pydefined.get_scope().get_scopes():
_analyze_node(pycore, scope.pyobject, should_analyze,
search_subscopes, followed_calls)
if should_analyze(pydefined):
new_followed_calls = max(0, followed_calls - 1)
return_true = lambda pydefined: True
return_false = lambda pydefined: False
def _follow(pyfunction):
_analyze_node(pycore, pyfunction, return_true,
return_false, new_followed_calls)
if not followed_calls:
_follow = None
visitor = SOAVisitor(pycore, pydefined, _follow)
for child in rope.base.ast.get_child_nodes(pydefined.get_ast()):
rope.base.ast.walk(child, visitor)
class SOAVisitor(object):
def __init__(self, pycore, pydefined, follow_callback=None):
self.pycore = pycore
self.pymodule = pydefined.get_module()
self.scope = pydefined.get_scope()
self.follow = follow_callback
def _FunctionDef(self, node):
pass
def _ClassDef(self, node):
pass
def _Call(self, node):
for child in rope.base.ast.get_child_nodes(node):
rope.base.ast.walk(child, self)
primary, pyname = evaluate.eval_node2(self.scope, node.func)
if pyname is None:
return
pyfunction = pyname.get_object()
if isinstance(pyfunction, pyobjects.AbstractFunction):
args = arguments.create_arguments(primary, pyfunction,
node, self.scope)
elif isinstance(pyfunction, pyobjects.PyClass):
pyclass = pyfunction
if '__init__' in pyfunction:
pyfunction = pyfunction['__init__'].get_object()
pyname = rope.base.pynames.UnboundName(pyobjects.PyObject(pyclass))
args = self._args_with_self(primary, pyname, pyfunction, node)
elif '__call__' in pyfunction:
pyfunction = pyfunction['__call__'].get_object()
args = self._args_with_self(primary, pyname, pyfunction, node)
else:
return
self._call(pyfunction, args)
def _args_with_self(self, primary, self_pyname, pyfunction, node):
base_args = arguments.create_arguments(primary, pyfunction,
node, self.scope)
return arguments.MixedArguments(self_pyname, base_args, self.scope)
def _call(self, pyfunction, args):
if isinstance(pyfunction, pyobjects.PyFunction):
if self.follow is not None:
before = self._parameter_objects(pyfunction)
self.pycore.object_info.function_called(
pyfunction, args.get_arguments(pyfunction.get_param_names()))
pyfunction._set_parameter_pyobjects(None)
if self.follow is not None:
after = self._parameter_objects(pyfunction)
if after != before:
self.follow(pyfunction)
# XXX: Maybe we should not call every builtin function
if isinstance(pyfunction, rope.base.builtins.BuiltinFunction):
pyfunction.get_returned_object(args)
def _parameter_objects(self, pyfunction):
result = []
for i in range(len(pyfunction.get_param_names(False))):
result.append(pyfunction.get_parameter(i))
return result
def _Assign(self, node):
for child in rope.base.ast.get_child_nodes(node):
rope.base.ast.walk(child, self)
visitor = _SOAAssignVisitor()
nodes = []
for child in node.targets:
rope.base.ast.walk(child, visitor)
nodes.extend(visitor.nodes)
for subscript, levels in nodes:
instance = evaluate.eval_node(self.scope, subscript.value)
args_pynames = []
args_pynames.append(evaluate.eval_node(self.scope,
subscript.slice.value))
value = rope.base.oi.soi._infer_assignment(
rope.base.pynames.AssignmentValue(node.value, levels),
self.pymodule)
args_pynames.append(rope.base.pynames.UnboundName(value))
if instance is not None and value is not None:
pyobject = instance.get_object()
if '__setitem__' in pyobject:
pyfunction = pyobject['__setitem__'].get_object()
args = arguments.ObjectArguments([instance] + args_pynames)
self._call(pyfunction, args)
# IDEA: handle `__setslice__`, too
class _SOAAssignVisitor(astutils._NodeNameCollector):
def __init__(self):
super(_SOAAssignVisitor, self).__init__()
self.nodes = []
def _added(self, node, levels):
if isinstance(node, rope.base.ast.Subscript) and \
isinstance(node.slice, rope.base.ast.Index):
self.nodes.append((node, levels))