| 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))
|
|
|