diff --git a/jedi/inference/value/instance.py b/jedi/inference/value/instance.py index 1e368d34..a6b6931a 100644 --- a/jedi/inference/value/instance.py +++ b/jedi/inference/value/instance.py @@ -19,7 +19,7 @@ from jedi.inference.value.function import \ BaseFunctionExecutionContext, FunctionExecutionContext from jedi.inference.value.klass import ClassFilter from jedi.inference.value.dynamic_arrays import get_dynamic_array_instance -from jedi.parser_utils import function_is_static_method +from jedi.parser_utils import function_is_staticmethod, function_is_classmethod class InstanceExecutedParamName(ParamName): @@ -41,9 +41,19 @@ class AnonymousMethodExecutionFilter(AnonymousFunctionExecutionFilter): self._instance = instance def _convert_param(self, param, name): - if param.position_index == 0 \ - and not function_is_static_method(self._function_value.tree_node): - return InstanceExecutedParamName(self._instance, self._function_value, name) + if param.position_index == 0: + if function_is_classmethod(self._function_value.tree_node): + return InstanceExecutedParamName( + self._instance.py__class__(), + self._function_value, + name + ) + elif not function_is_staticmethod(self._function_value.tree_node): + return InstanceExecutedParamName( + self._instance, + self._function_value, + name + ) return super(AnonymousMethodExecutionFilter, self)._convert_param(param, name) diff --git a/jedi/parser_utils.py b/jedi/parser_utils.py index 9912c9f9..f8537858 100644 --- a/jedi/parser_utils.py +++ b/jedi/parser_utils.py @@ -297,9 +297,21 @@ def get_string_quote(leaf): return re.match(r'\w*("""|\'{3}|"|\')', leaf.value).group(1) -def function_is_static_method(function_node): - for decorator in function_node.get_decorators(): - dotted_name = decorator.children[1] - if dotted_name.get_code() == 'staticmethod': - return True - return False +def _function_is_x_method(method_name): + def wrapper(function_node): + """ + This is a heuristic. It will not hold ALL the times, but it will be + correct pretty much for anyone that doesn't try to beat it. + staticmethod/classmethod are builtins and unless overwritten, this will + be correct. + """ + for decorator in function_node.get_decorators(): + dotted_name = decorator.children[1] + if dotted_name.get_code() == method_name: + return True + return False + return wrapper + + +function_is_staticmethod = _function_is_x_method('staticmethod') +function_is_classmethod = _function_is_x_method('classmethod') diff --git a/test/completion/stdlib.py b/test/completion/stdlib.py index 10573377..636b66fb 100644 --- a/test/completion/stdlib.py +++ b/test/completion/stdlib.py @@ -318,13 +318,28 @@ class F(): #? return param + @classmethod + def my_method_without_call(cls, param): + #? + cls.my_variable + #? ['my_method', 'my_method_without_call'] + cls.my_meth + #? + return param + @classmethod def my_method(cls, param): - #? [] - param.my_method - + #? + cls.my_variable + #? ['my_method', 'my_method_without_call'] + cls.my_meth + #? + return param +#? str() F.my_func('') +#? str() +F.my_method('') # ----------------- # Unknown metaclass