soa.py 5.5 KB

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