Anonymous avatar Anonymous committed 69124d3

pycore: added followed_calls argument to PyCore.analyze_module()

Comments (0)

Files changed (3)

rope/base/oi/staticoi.py

 from rope.base import pyobjects, evaluate, astutils, arguments
 
 
-def analyze_module(pycore, pymodule, should_analyze, search_subscopes):
+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)
+    _analyze_node(pycore, pymodule, should_analyze,
+                  search_subscopes, followed_calls)
 
 
-def _analyze_node(pycore, pydefined, should_analyze, search_subscopes):
+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)
+            _analyze_node(pycore, scope.pyobject, should_analyze,
+                          search_subscopes, followed_calls)
     if should_analyze(pydefined):
-        visitor = SOIVisitor(pycore, pydefined)
+        new_followed_calls = max(0, followed_calls - 1)
+        def _called(pyfunction):
+            if followed_calls:
+                _analyze_node(pycore, pyfunction, should_analyze,
+                              search_subscopes, new_followed_calls)
+        visitor = SOIVisitor(pycore, pydefined, _called)
         for child in rope.base.ast.get_child_nodes(pydefined.get_ast()):
             rope.base.ast.walk(child, visitor)
 
 
 class SOIVisitor(object):
 
-    def __init__(self, pycore, pydefined):
+    def __init__(self, pycore, pydefined, called_callback=None):
         self.pycore = pycore
         self.pymodule = pydefined.get_module()
         self.scope = pydefined.get_scope()
+        self.called = called_callback
 
     def _FunctionDef(self, node):
         pass
             self.pycore.object_info.function_called(
                 pyfunction, args.get_arguments(pyfunction.get_param_names()))
             pyfunction._set_parameter_pyobjects(None)
+            if self.called is not None:
+                self.called(pyfunction)
         # XXX: Maybe we should not call every builtin function
         if isinstance(pyfunction, rope.base.builtins.BuiltinFunction):
             pyfunction.get_returned_object(args)

rope/base/pycore.py

         return result
 
     def resource_to_pyobject(self, resource, force_errors=False):
-        return self.module_cache.get_pymodule(resource, force_errors) 
+        return self.module_cache.get_pymodule(resource, force_errors)
 
     def get_python_files(self):
         """Returns all python files available in the project"""
         return runner
 
     def analyze_module(self, resource, should_analyze=lambda py: True,
-                       search_subscopes=lambda py: True):
+                       search_subscopes=lambda py: True, followed_calls=0):
         """Analyze `resource` module for static object inference
 
         This function forces rope to analyze this module to collect
         """
         pymodule = self.resource_to_pyobject(resource)
         self.module_cache.forget_all_data()
-        rope.base.oi.staticoi.analyze_module(self, pymodule,
-                                             should_analyze, search_subscopes)
+        rope.base.oi.staticoi.analyze_module(
+            self, pymodule, should_analyze, search_subscopes, followed_calls)
 
     def get_subclasses(self, pyclass, task_handle=taskhandle.NullTaskHandle()):
         classes = self.classes_cache.get_classes(task_handle)

ropetest/advanced_oi_test.py

         p_type = f_scope['p'].get_object().get_type()
         self.assertEquals(a_class, p_type)
 
+    def test_following_function_calls_when_asked_to(self):
+        code = 'class A(object):\n    pass\n' \
+               'class C(object):\n' \
+               '    def __init__(self, arg):\n' \
+               '        self.attr = arg\n' \
+               'def f(p):\n    return C(p)\n' \
+               'c = f(A())\nx = c.attr\n'
+        self.mod.write(code)
+        self.pycore.analyze_module(self.mod, followed_calls=1)
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        a_class = pymod['A'].get_object()
+        x_var = pymod['x'].get_object().get_type()
+        self.assertEquals(a_class, x_var)
+
 
 def suite():
     result = unittest.TestSuite()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.