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