Index: tools/telemetry/third_party/rope/rope/base/oi/soa.py |
diff --git a/tools/telemetry/third_party/rope/rope/base/oi/soa.py b/tools/telemetry/third_party/rope/rope/base/oi/soa.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..a34b970ea2f599189ad959f7a97ad6e4a6ec8275 |
--- /dev/null |
+++ b/tools/telemetry/third_party/rope/rope/base/oi/soa.py |
@@ -0,0 +1,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)) |