Commits

Anonymous committed 6e9f718

Better inference of the first parameters of methods

Comments (0)

Files changed (5)

docs/dev/workingon.txt

 Small Stories
 =============
 
-- Not waiting on stoppable task runner dialog
-- Adding `PyFunction.get_kind()`
-- Moving static method detection to a common place; extract,
-  funcionutils, staticoi
-- Problems with cache in inline for returns
-
-* Remove `extract._get_method_kind()`
-* object inference and ``self`` argument; it gets the value of
+- object inference and ``self`` argument; it gets the value of
   subclasses
+- What to do about methods with no parameters?
 
 * What to do with files that cannot be compiled when refactoring?
 * Extracting subexpressions; look at `extracttest` for more info

rope/base/oi/objectinfer.py

         result = self.object_info.get_parameter_objects(pyobject)
         if result is None:
             result = self.soi.infer_parameter_objects(pyobject)
+        self._handle_first_parameter(pyobject, result)
         return result
 
+    def _handle_first_parameter(self, pyobject, parameters):
+        kind = pyobject.get_kind()
+        if parameters is None or kind not in ['method', 'classmethod']:
+            pass
+        if not parameters:
+            if not pyobject.get_param_names(special_args=False):
+                return
+            parameters.append(pyobjects.get_unknown())
+        if kind == 'method':
+            parameters[0] = pyobjects.PyObject(pyobject.parent)
+        if kind == 'classmethod':
+            parameters[0] = pyobject.parent
+
     def infer_assigned_object(self, pyname):
         if not pyname.assignments:
             return

rope/base/oi/staticoi.py

                 pass
 
     def infer_parameter_objects(self, pyobject):
-        objects = []
-        kind = pyobject.get_kind()
-        if kind == 'method':
-            objects.append(pyobjects.PyObject(pyobject.parent))
-        elif kind == 'staticmethod':
-            objects.append(pyobjects.get_unknown())
-        elif kind == 'classmethod':
-            objects.append(pyobject.parent)
         params = pyobject.get_param_names(special_args=False)
-        for parameter in params[len(objects):]:
-            objects.append(pyobjects.get_unknown())
-        return objects
+        return [pyobjects.get_unknown()] * len(params)
 
     def analyze_module(self, pymodule, should_analyze, search_subscopes):
         """Analyze `pymodule` for static object inference

rope/refactor/extract.py

             if self.info.method and not self.info.variable:
                 class_scope = self.info.scope.parent
                 regions = []
-                method_kind = _get_method_kind(self.info.scope)
+                method_kind = _get_function_kind(self.info.scope)
                 for scope in class_scope.get_scopes():
                     if method_kind == 'method' and \
-                       _get_method_kind(scope) != 'method':
+                       _get_function_kind(scope) != 'method':
                         continue
                     start = self.info.lines.get_line_start(scope.get_start())
                     end = self.info.lines.get_line_end(scope.get_end())
         args = self._find_function_arguments()
         returns = self._find_function_returns()
         result = []
-        if self.info.method and _get_method_kind(self.info.scope) != 'method':
+        if self.info.method and _get_function_kind(self.info.scope) != 'method':
             result.append('@staticmethod\n')
         result.append('def %s:\n' % self._get_function_signature(args))
         unindented_body = self._get_unindented_function_body(returns)
     def _get_function_signature(self, args):
         args = list(args)
         prefix = ''
-        if self.info.method and _get_method_kind(self.info.scope) == 'method':
+        if self.info.method and _get_function_kind(self.info.scope) == 'method':
             self_name = self._get_self_name()
             if self_name in args:
                 args.remove(self_name)
     def _get_function_call(self, args):
         prefix = ''
         if self.info.method:
-            if _get_method_kind(self.info.scope) == 'method':
+            if _get_function_kind(self.info.scope) == 'method':
                 self_name = self._get_self_name()
                 if  self_name in args:
                     args.remove(self_name)
         ast.walk(node, visitor)
         return visitor.error
 
-def _get_method_kind(scope):
-    """Get the type of a method
-
-    It returns 'normal', 'static', or 'class'
-
-    """
+def _get_function_kind(scope):
     return scope.pyobject.get_kind()
 
 

ropetest/advanced_oi_test.py

             self.assertNotEquals(c_class, var_pyname.get_object().get_type(),
                                  'Class `C` no more exists')
 
+    def test_always_returning_containing_class_for_selfs(self):
+        code = 'class A(object):\n    def f(p):\n        return p\n' \
+               'class B(object):\n    pass\nb = B()\nb.f()\n'
+        self.mod.write(code)
+        self.pycore.analyze_module(self.mod)
+        pymod = self.pycore.resource_to_pyobject(self.mod)
+        a_class = pymod.get_attribute('A').get_object()
+        f_scope = a_class.get_scope().get_scopes()[0]
+        p_type = f_scope.get_name('p').get_object().get_type()
+        self.assertEquals(a_class, p_type)
+
 
 def suite():
     result = unittest.TestSuite()