Fix goto tests.

This commit is contained in:
Dave Halter
2016-11-17 23:28:47 +01:00
parent d15016c5c1
commit 05581714d9
10 changed files with 114 additions and 35 deletions

View File

@@ -237,7 +237,8 @@ class Script(object):
name = self._get_module_node().name_for_position(self._pos) name = self._get_module_node().name_for_position(self._pos)
if name is None: if name is None:
return [] return []
return list(self._evaluator.goto(name)) context = self._evaluator.create_context(self._get_module(), name)
return list(self._evaluator.goto(context, name))
def usages(self, additional_module_paths=()): def usages(self, additional_module_paths=()):
""" """

View File

@@ -145,10 +145,7 @@ class BaseDefinition(object):
'function' 'function'
""" """
try: return self._name.api_type
return self._name.parent_context.api_type
except AttributeError:
return ''
def _path(self): def _path(self):
"""The path to a module/class/function definition.""" """The path to a module/class/function definition."""
@@ -418,7 +415,7 @@ class Completion(BaseDefinition):
""" """
Return the rest of the word, e.g. completing ``isinstance``:: Return the rest of the word, e.g. completing ``isinstance``::
isinstan# <-- Cursor is here # <-- Cursor is here
would return the string 'ce'. It also adds additional stuff, depending would return the string 'ce'. It also adds additional stuff, depending
on your `settings.py`. on your `settings.py`.
@@ -561,6 +558,36 @@ class Definition(use_metaclass(CachedMetaClass, BaseDefinition)):
'class C' 'class C'
""" """
typ = self.type
if typ in ('statement', 'param'):
definition = self._name.tree_name.get_definition()
try:
first_leaf = definition.first_leaf()
except AttributeError:
# `d` is already a Leaf (Name).
first_leaf = definition
# Remove the prefix, because that's not what we want for get_code
# here.
old, first_leaf.prefix = first_leaf.prefix, ''
try:
txt = definition.get_code()
finally:
first_leaf.prefix = old
# Delete comments:
txt = re.sub('#[^\n]+\n', ' ', txt)
# Delete multi spaces/newlines
txt = re.sub('\s+', ' ', txt).strip()
if typ == 'param':
txt = typ + ' ' + txt
return txt
if typ == 'function':
# For the description we want a short and a pythonic way.
typ = 'def'
return typ + ' ' + self._name.string_name
# TODO DELETE
d = self._definition d = self._definition
if isinstance(d, compiled.CompiledObject): if isinstance(d, compiled.CompiledObject):

View File

@@ -76,7 +76,7 @@ class KeywordName(AbstractNameDefinition):
class Keyword(object): class Keyword(object):
type = 'completion_keyword' api_type = 'keyword'
def __init__(self, evaluator, name, pos): def __init__(self, evaluator, name, pos):
self.name = KeywordName(evaluator, name) self.name = KeywordName(evaluator, name)

View File

@@ -66,6 +66,7 @@ from itertools import chain
from jedi.parser import tree from jedi.parser import tree
from jedi import debug from jedi import debug
from jedi.common import unite
from jedi.evaluate import representation as er from jedi.evaluate import representation as er
from jedi.evaluate import imports from jedi.evaluate import imports
from jedi.evaluate import recursion from jedi.evaluate import recursion
@@ -77,7 +78,7 @@ from jedi.evaluate import compiled
from jedi.evaluate import precedence from jedi.evaluate import precedence
from jedi.evaluate import param from jedi.evaluate import param
from jedi.evaluate import helpers from jedi.evaluate import helpers
from jedi.evaluate.context import Context from jedi.evaluate.filters import TreeNameDefinition
from jedi.evaluate.instance import AnonymousInstance, AnonymousInstanceFunctionExecution from jedi.evaluate.instance import AnonymousInstance, AnonymousInstanceFunctionExecution
@@ -461,36 +462,43 @@ class Evaluator(object):
param_names = [] param_names = []
for typ in types: for typ in types:
try: try:
params = typ.params get_param_names = typ.get_param_names
except AttributeError: except AttributeError:
pass pass
else: else:
param_names += [param.name for param in params for param_name in get_param_names():
if param.name.value == name.value] if param_name.string_name == name.value:
param_names.append(param_name)
return param_names return param_names
elif isinstance(par, tree.ExprStmt) and name in par.get_defined_names(): elif isinstance(par, tree.ExprStmt) and name in par.get_defined_names():
# Only take the parent, because if it's more complicated than just # Only take the parent, because if it's more complicated than just
# a name it's something you can "goto" again. # a name it's something you can "goto" again.
return [name] return [TreeNameDefinition(context, name)]
elif isinstance(par, (tree.Param, tree.Function, tree.Class)) and par.name is name: elif isinstance(par, (tree.Param, tree.Function, tree.Class)) and par.name is name:
return [name] return [TreeNameDefinition(context, name)]
elif isinstance(stmt, tree.Import): elif isinstance(stmt, tree.Import):
modules = imports.ImportWrapper(context, name).follow(is_goto=True) module_names = imports.ImportWrapper(context, name).follow(is_goto=True)
return list(resolve_implicit_imports(modules)) return module_names
return list(resolve_implicit_imports(module_names))
elif par.type == 'dotted_name': # Is a decorator. elif par.type == 'dotted_name': # Is a decorator.
index = par.children.index(name) index = par.children.index(name)
if index > 0: if index > 0:
new_dotted = helpers.deep_ast_copy(par) new_dotted = helpers.deep_ast_copy(par)
new_dotted.children[index - 1:] = [] new_dotted.children[index - 1:] = []
types = self.eval_element(context, new_dotted) values = self.eval_element(context, new_dotted)
return unite(
self.find_types(value, name, is_goto=True) for value in values
)
return resolve_implicit_imports(iterable.unite( return resolve_implicit_imports(iterable.unite(
self.find_types(typ, name, is_goto=True) for typ in types self.find_types(typ, name, is_goto=True) for typ in types
)) ))
scope = name.get_parent_scope()
if tree.is_node(par, 'trailer') and par.children[0] == '.': if tree.is_node(par, 'trailer') and par.children[0] == '.':
call = helpers.call_of_leaf(name, cut_own_trailer=True) call = helpers.call_of_leaf(name, cut_own_trailer=True)
types = self.eval_element(context, call) values = self.eval_element(context, call)
return unite(
self.find_types(value, name, is_goto=True) for value in values
)
return resolve_implicit_imports(iterable.unite( return resolve_implicit_imports(iterable.unite(
self.find_types(typ, name, is_goto=True) for typ in types self.find_types(typ, name, is_goto=True) for typ in types
)) ))
@@ -499,7 +507,7 @@ class Evaluator(object):
# We only need to adjust the start_pos for statements, because # We only need to adjust the start_pos for statements, because
# there the name cannot be used. # there the name cannot be used.
stmt = name stmt = name
return self.find_types(scope, name, stmt.start_pos, return self.find_types(context, name, stmt.start_pos,
search_global=True, is_goto=True) search_global=True, is_goto=True)
def wrap(self, element, parent_context): def wrap(self, element, parent_context):

View File

@@ -85,7 +85,8 @@ class CompiledObject(Context):
return inspect.getdoc(self.obj) or '' return inspect.getdoc(self.obj) or ''
@property @property
def params(self): def get_params(self):
return [] # TODO Fix me.
params_str, ret = self._parse_function_doc() params_str, ret = self._parse_function_doc()
tokens = params_str.split(',') tokens = params_str.split(',')
if inspect.ismethoddescriptor(self.obj): if inspect.ismethoddescriptor(self.obj):
@@ -280,6 +281,9 @@ class CompiledName(AbstractNameDefinition):
name = None name = None
return '<%s: (%s).%s>' % (self.__class__.__name__, name, self.string_name) return '<%s: (%s).%s>' % (self.__class__.__name__, name, self.string_name)
def api_type(self):
return self.infer()[0].api_type
@underscore_memoization @underscore_memoization
def infer(self): def infer(self):
module = self.parent_context.get_root_context() module = self.parent_context.get_root_context()
@@ -291,6 +295,10 @@ class CompiledContextName(AbstractNameDefinition):
self.string_name = name self.string_name = name
self.parent_context = parent_context self.parent_context = parent_context
@property
def api_type(self):
return self.parent_context.api_type
def infer(self): def infer(self):
return [self.parent_context] return [self.parent_context]

View File

@@ -51,6 +51,10 @@ class ContextName(AbstractNameDefinition):
def infer(self): def infer(self):
return [self.parent_context] return [self.parent_context]
@property
def api_type(self):
return self.parent_context.api_type
class TreeNameDefinition(ContextName): class TreeNameDefinition(ContextName):
def get_parent_flow_context(self): def get_parent_flow_context(self):
@@ -61,8 +65,20 @@ class TreeNameDefinition(ContextName):
from jedi.evaluate.finder import _name_to_types from jedi.evaluate.finder import _name_to_types
return _name_to_types(self.parent_context.evaluator, self.parent_context, self.tree_name) return _name_to_types(self.parent_context.evaluator, self.parent_context, self.tree_name)
@property
def api_type(self):
definition = self.tree_name.get_definition()
return dict(
import_name='import',
funcdef='function',
param='param',
classdef='class',
).get(definition.type, 'statement')
class ParamName(ContextName): class ParamName(ContextName):
api_type = 'param'
def __init__(self, parent_context, tree_name): def __init__(self, parent_context, tree_name):
self.parent_context = parent_context self.parent_context = parent_context
self.tree_name = tree_name self.tree_name = tree_name

View File

@@ -144,7 +144,6 @@ class FakeName(tree.Name):
In case is_definition is defined (not None), that bool value will be In case is_definition is defined (not None), that bool value will be
returned. returned.
""" """
raise NotImplementedError
super(FakeName, self).__init__(name_str, start_pos) super(FakeName, self).__init__(name_str, start_pos)
self.parent = parent self.parent = parent
self._is_definition = is_definition self._is_definition = is_definition

View File

@@ -68,6 +68,8 @@ class SpecialMethodFilter(DictFilter):
classes like Generator (for __next__, etc). classes like Generator (for __next__, etc).
""" """
class SpecialMethodName(AbstractNameDefinition): class SpecialMethodName(AbstractNameDefinition):
api_type = 'function'
def __init__(self, parent_context, string_name, callable_, builtin_context): def __init__(self, parent_context, string_name, callable_, builtin_context):
self.parent_context = parent_context self.parent_context = parent_context
self.string_name = string_name self.string_name = string_name

View File

@@ -54,7 +54,8 @@ from jedi.evaluate import param
from jedi.evaluate import flow_analysis from jedi.evaluate import flow_analysis
from jedi.evaluate import imports from jedi.evaluate import imports
from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \ from jedi.evaluate.filters import ParserTreeFilter, FunctionExecutionFilter, \
GlobalNameFilter, DictFilter, ContextName, AbstractNameDefinition GlobalNameFilter, DictFilter, ContextName, AbstractNameDefinition, \
ParamName, AnonymousInstanceParamName
from jedi.evaluate.dynamic import search_params from jedi.evaluate.dynamic import search_params
from jedi.evaluate import context from jedi.evaluate import context
@@ -470,12 +471,10 @@ class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper))
def py__class__(self): def py__class__(self):
return compiled.create(self.evaluator, type) return compiled.create(self.evaluator, type)
@property def get_params(self):
def params(self): from jedi.evaluate.instance import AnonymousInstance
try: anon = AnonymousInstance(self.evaluator, self.parent_context, self)
return self.get_subscope_by_name('__init__').params return [AnonymousInstanceParamName(anon, param.name) for param in self.funcdef.params]
except KeyError:
return [] # object.__init__
def names_dicts(self, search_global, is_instance=False): def names_dicts(self, search_global, is_instance=False):
if search_global: if search_global:
@@ -509,6 +508,13 @@ class ClassContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper))
return sub return sub
raise KeyError("Couldn't find subscope.") raise KeyError("Couldn't find subscope.")
def get_function_slot_names(self, name):
for filter in self.get_filters(search_global=False):
names = filter.get(name)
if names:
return names
return []
def __repr__(self): def __repr__(self):
return "<%s of %s>" % (self.__class__.__name__, self.classdef) return "<%s of %s>" % (self.__class__.__name__, self.classdef)
@@ -582,6 +588,14 @@ class FunctionContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrappe
def name(self): def name(self):
return ContextName(self, self.funcdef.name) return ContextName(self, self.funcdef.name)
def get_param_names(self):
anon = AnonymousFunctionExecution(
self.evaluator,
self.parent_context,
self.funcdef
)
return [ParamName(anon, param.name) for param in self.funcdef.params]
class LambdaWrapper(FunctionContext): class LambdaWrapper(FunctionContext):
def get_decorated_func(self): def get_decorated_func(self):
@@ -747,6 +761,8 @@ class ModuleAttributeName(AbstractNameDefinition):
""" """
For module attributes like __file__, __str__ and so on. For module attributes like __file__, __str__ and so on.
""" """
api_type = 'instance'
def __init__(self, parent_module, string_name): def __init__(self, parent_module, string_name):
self.parent_context = parent_module self.parent_context = parent_module
self.string_name = string_name self.string_name = string_name
@@ -758,8 +774,9 @@ class ModuleAttributeName(AbstractNameDefinition):
class SubModuleName(AbstractNameDefinition): class SubModuleName(AbstractNameDefinition):
""" api_type = 'module'
""" start_pos = (1, 0)
def __init__(self, parent_module, string_name): def __init__(self, parent_module, string_name):
self.parent_context = parent_module self.parent_context = parent_module
self.string_name = string_name self.string_name = string_name
@@ -774,6 +791,7 @@ class SubModuleName(AbstractNameDefinition):
class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper)): class ModuleContext(use_metaclass(CachedMetaClass, context.TreeContext, Wrapper)):
api_type = 'module'
parent_context = None parent_context = None
def __init__(self, evaluator, module_node): def __init__(self, evaluator, module_node):

View File

@@ -44,7 +44,7 @@ class C(object):
self.b self.b
#! 14 ['def b'] #! 14 ['def b']
self.b() self.b()
#! 11 ['self'] #! 11 ['param self']
self.b self.b
return 1 return 1
@@ -99,7 +99,7 @@ ClassVar().x = ''
# Recurring use of the same var name, github #315 # Recurring use of the same var name, github #315
def f(t=None): def f(t=None):
#! 9 ['t=None'] #! 9 ['param t=None']
t = t or 1 t = t or 1
@@ -180,9 +180,9 @@ class ClassDef():
# ----------------- # -----------------
param = ClassDef param = ClassDef
#! 8 ['param'] #! 8 ['param param']
def ab1(param): pass def ab1(param): pass
#! 9 ['param'] #! 9 ['param param']
def ab2(param): pass def ab2(param): pass
#! 11 ['param = ClassDef'] #! 11 ['param = ClassDef']
def ab3(a=param): pass def ab3(a=param): pass
@@ -211,7 +211,7 @@ for i in []:
def dec(dec_param=3): def dec(dec_param=3):
pass pass
#! 8 ['dec_param=3'] #! 8 ['param dec_param=3']
@dec(dec_param=5) @dec(dec_param=5)
def y(): def y():
pass pass