Fix an issue with creating contexts.

This commit is contained in:
Dave Halter
2017-01-05 18:05:24 +01:00
parent 12a9ef48f7
commit 9fb2644f03
5 changed files with 33 additions and 19 deletions

View File

@@ -518,7 +518,7 @@ class Evaluator(object):
search_global=True, is_goto=True search_global=True, is_goto=True
) )
def create_context(self, base_context, node, node_is_context=False): def create_context(self, base_context, node, node_is_context=False, node_is_object=False):
def parent_scope(node): def parent_scope(node):
while True: while True:
node = node.parent node = node.parent
@@ -534,7 +534,7 @@ class Evaluator(object):
if n.type == 'comp_for': if n.type == 'comp_for':
return n return n
def from_scope_node(scope_node, child_is_funcdef=None, is_nested=True): def from_scope_node(scope_node, child_is_funcdef=None, is_nested=True, node_is_object=False):
if scope_node == base_node: if scope_node == base_node:
return base_context return base_context
@@ -554,7 +554,7 @@ class Evaluator(object):
parent_context, parent_context,
scope_node scope_node
) )
if is_nested: if is_nested and not node_is_object:
return func.get_function_execution() return func.get_function_execution()
return func return func
elif scope_node.type == 'classdef': elif scope_node.type == 'classdef':
@@ -580,4 +580,4 @@ class Evaluator(object):
# object itself and not its contents. # object itself and not its contents.
node = node.parent node = node.parent
scope_node = parent_scope(node) scope_node = parent_scope(node)
return from_scope_node(scope_node, is_nested=not node_is_context) return from_scope_node(scope_node, is_nested=True, node_is_object=node_is_object)

View File

@@ -46,7 +46,8 @@ class MixedObject(object):
self._context = module_context.create_context( self._context = module_context.create_context(
tree_name.parent, tree_name.parent,
node_is_context=True node_is_context=True,
node_is_object=True
) )
# We have to overwrite everything that has to do with trailers, name # We have to overwrite everything that has to do with trailers, name

View File

@@ -55,8 +55,8 @@ class Context(object):
return self.evaluator.find_types( return self.evaluator.find_types(
self, name_or_str, name_context, position, search_global, is_goto) self, name_or_str, name_context, position, search_global, is_goto)
def create_context(self, node, node_is_context=False): def create_context(self, node, node_is_context=False, node_is_object=False):
return self.evaluator.create_context(self, node, node_is_context) return self.evaluator.create_context(self, node, node_is_context, node_is_object)
def is_class(self): def is_class(self):
return False return False

View File

@@ -162,35 +162,35 @@ class NameFinder(object):
return types return types
def _name_to_types(evaluator, context, name): def _name_to_types(evaluator, context, tree_name):
types = [] types = []
node = name.get_definition() node = tree_name.get_definition()
if node.isinstance(tree.ForStmt): if node.isinstance(tree.ForStmt):
types = pep0484.find_type_from_comment_hint_for(context, node, name) types = pep0484.find_type_from_comment_hint_for(context, node, tree_name)
if types: if types:
return types return types
if node.isinstance(tree.WithStmt): if node.isinstance(tree.WithStmt):
types = pep0484.find_type_from_comment_hint_with(context, node, name) types = pep0484.find_type_from_comment_hint_with(context, node, tree_name)
if types: if types:
return types return types
if node.type in ('for_stmt', 'comp_for'): if node.type in ('for_stmt', 'comp_for'):
try: try:
types = context.predefined_names[node][name.value] types = context.predefined_names[node][tree_name.value]
except KeyError: except KeyError:
container_types = context.eval_node(node.children[3]) container_types = context.eval_node(node.children[3])
for_types = iterable.py__iter__types(evaluator, container_types, node.children[3]) for_types = iterable.py__iter__types(evaluator, container_types, node.children[3])
types = check_tuple_assignments(evaluator, for_types, name) types = check_tuple_assignments(evaluator, for_types, tree_name)
elif node.isinstance(tree.ExprStmt): elif node.isinstance(tree.ExprStmt):
types = _remove_statements(evaluator, context, node, name) types = _remove_statements(evaluator, context, node, tree_name)
elif node.isinstance(tree.WithStmt): elif node.isinstance(tree.WithStmt):
types = context.eval_node(node.node_from_name(name)) types = context.eval_node(node.node_from_name(tree_name))
elif isinstance(node, tree.Import): elif isinstance(node, tree.Import):
types = imports.infer_import(context, name) types = imports.infer_import(context, tree_name)
elif node.type in ('funcdef', 'classdef'): elif node.type in ('funcdef', 'classdef'):
types = _apply_decorators(evaluator, context, node) types = _apply_decorators(evaluator, context, node)
elif node.type == 'global_stmt': elif node.type == 'global_stmt':
context = evaluator.create_context(context, name) context = evaluator.create_context(context, tree_name)
finder = NameFinder(evaluator, context, context, str(name)) finder = NameFinder(evaluator, context, context, str(tree_name))
filters = finder.get_filters(search_global=True) filters = finder.get_filters(search_global=True)
# For global_stmt lookups, we only need the first possible scope, # For global_stmt lookups, we only need the first possible scope,
# which means the function itself. # which means the function itself.
@@ -200,7 +200,7 @@ def _name_to_types(evaluator, context, name):
# TODO an exception can also be a tuple. Check for those. # TODO an exception can also be a tuple. Check for those.
# TODO check for types that are not classes and add it to # TODO check for types that are not classes and add it to
# the static analysis report. # the static analysis report.
exceptions = context.eval_node(name.get_previous_sibling().get_previous_sibling()) exceptions = context.eval_node(tree_name.get_previous_sibling().get_previous_sibling())
types = unite( types = unite(
evaluator.execute(t, param.ValuesArguments([])) evaluator.execute(t, param.ValuesArguments([]))
for t in exceptions for t in exceptions

View File

@@ -15,3 +15,16 @@ def test_empty_init():
class X(object): pass class X(object): pass
X(''') X(''')
assert Script(code).completions() assert Script(code).completions()
def test_in_empty_space():
code = dedent('''\
class X(object):
def __init__(self):
hello
''')
comps = Script(code, 3, 7).completions()
self, = [c for c in comps if c.name == 'self']
assert self.name == 'self'
def_, = self._goto_definitions()
assert def_.name == 'X'